376 karma · joined December 8, 2009
But yeah if it weren't for that there wouldn't have been much incentive to stick around.
bqView = bQuery.view()
bqView.set(...)
bqView.on(...)
MyBackboneView = bqView.make() AlbumsView =
bQuery.view()
.set("el", "#albums-view")
.init((opts={})->
@readOnly = opts.readOnly or no
@app = opts.app
)
.use(Mixins.bq.init('albums'))
.use(Mixins.bq.collection
tag: "#album-list"
createView: (m) ->
AlbumView = Views.AlbumView(readOnly: @readOnly)
new AlbumView { model: m, app: @app }
)
.use(Mixins.bq.filterable
pred: (album, ftext) -> album.get('title').indexOf(ftext) is 0
filterTag: "#filter"
collectionTag: "#album-list"
)
.on("click #addNew", ->
@collection.create
title: "New Album"
type: "Album"
)
.make()
For example, the Mixins.bq.collection plugin abstracts away the common task of adding and removing subviews when new things are added the collection. The filterable plugin abstracts away the common task of filtering collections. Our custom init plugin sets up all the events common to all of our views. In the end make() just returns a BackboneView with all the events set up properly. It has saved us so much time we figure people may actually want to use this as well, we just have to write the documentation and some plugins now :)I'm looking forward to writing a game in Clay to measure its true performance in a realtime system.
Here's a full example in some production code. I ended up doing it this way to simplify some crazy legacy code. There were a bunch of different classes that provide order items and extended prices in different ways. With this setup as long as those types implement the necessary interfaces, they get those extension methods for free.
public static IEnumerable<CalculatedTax> CalculateTaxes<T>(this T t)
where T : IOrderItems, IAddress {}
This adds an extension method to any type that implements those interfaces. Using this technique I have been able to make my interfaces much smaller and have generic functions which apply to many different types.Here's what it would might look like in Haskell:
calculateTaxes :: (OrderItems a, Address a) => a -> [CalculatedTax]For example, a common pattern that I find myself repeating in many languages is downloading a bunch of webpages asynchronously and collecting the results in a consistent order. To do this in Go I might wire up a channel and collect the results that way. In C# I might use the BeginAsync functions and possibly locks to collect all my results. And what if one of them times out? Throws an exception?
In almost every language I have had to specifically think about all these situations, making sure I have handled all of the exceptions and timeouts properly and by the end of the day I usually end up with a mudball procedure that is really good at asynchronously downloading webpages, but it is far from reusable.
In Haskell, once I'm done writing my function "downloadWebPage", I just lift it into the context of the problem I'm trying to solve. If I'm trying to download a page asynchronously, I'll use "asyncDl = forkAsync downloadWebPage" to make it a function that downloads a page asynchronously. If I need to handle timeouts, I'll use "timeout 200000 . asyncDl" to make a function that returns Nothing after a certain amount of time. What if I wanted to do this for a list of web pages? Well I just use mapM run the asynchronous, timed out webpage download function over a list of websites.
What if I want to use any function instead of one that download websites? Well you make a library: https://github.com/jb55/async-util
What I find in Haskell/Lisp that I have not seen in many other languages is the idea of a combinatoric API. One where combining functions is your main tool for building abstractions rather than more rigid computation paths. The amount of code that you do not have to write when programming this way is something that you just don't see in other languages.
I guess I'm still stuck with rsync and cronjobs until they work out the issues.
That's not to say they still don't have their niche for high performance applications. It's just that in most cases other, more expressive languages are usually a better choice.
It's possible I just live in the wrong area and I'm going to the wrong schools, but that has been my experience so far.