Code Quarterly's Interview with Rich Hickey
codequarterly.com
codequarterly.com
> When we drop down to the algorithm level, I think OO can seriously thwart reuse. In particular, the use of objects to represent simple informational data is almost criminal in its generation of per-piece-of-information micro-languages, i.e. the class methods, versus far more powerful, declarative, and generic methods like relational algebra. Inventing a class with its own interface to hold a piece of information is like inventing a new language to write every short story. This is anti-reuse, and, I think, results in an explosion of code in typical OO applications.
Also, it's easy to say, "object-oriented programming is bad for reuse," but that's not all OO is for (i.e. encapsulation, etc.).
With that said, reuse with OO today is not in a horrible state, no pun intended. Things can certainly be easier, but I think design is the bigger issue. And the problems I see suffer in functional designs as well as OO designs.
Maybe it was an '80s thing, but I recall "reusable software components" being touted as the industry savior. OO was all about reuse then.
[1] - http://steve-yegge.blogspot.com/2010/07/wikileaks-to-leak-50...
Are there any good existing resources for learning these things?
[1] http://www.amazon.com/Presidential-Cotton-Rope-Hammock-Size/...
But switching to dictionaries wholesale for this reason seems to throw out the baby with the bathwater. The loss of abstraction is real, and could be worked around trivially by making every object respond to a dictionary protocol. This would give you the best of both worlds.
I think Javascript, C#, Ruby, Python give you this. C++ and Java don't.
And as you say, you do lose a fair bit giving this away.
(get "foo" 0) ; \f
(get {:foo 'bar} :foo) ; bar
(get #{0 1 2} 1) ; 1
(get [:a :b :c] 1) ; :b
(def path [0 :foo 1])
(get-in [{:foo "bar"} 1 2] path) ;\a
Being able to deal with data generically in a first class manner is very, very useful. You can only get this in all the languages you've mentioned (including JS) w/ more or less custom code writing.You do realize that's the approach Clojure takes right?
Java reflection does much of this. Though you can't add properties.
He's against types, and only values them for performance. Yet, the relational algebra that he admires uses types (the definitions of tables - "schema"). Although they're flexible types, in that you can change schema definitions (schema are themselves tables). And you can invent new schema willy nilly (e.g. result of a join). They are types in that each row (or instance) in a table has a value for each column in the table.
The relational algebra is one of the most successful and enduring innovations in computer science - and it also has a solid mathematical basis. It's dynamic types may be a good guide to the value of types other than for performance.
order.getLineItem(2).getQuantity();
(get-in order [:lineitems 2 :quantity] 1)
The first is simple enough, but it's essentially a DSL. No code that doesn't know about that API can work with those objects. If I want to guard against null objects I have to re-do that sort of work over and over again.Contrast with the latter, where the get-in function just treats the subject as a nested associative structure. It can handle the null checking, and it doesn't care what my keys look like.
http://blog.bestinclass.dk/index.clj/2010/11/clojureql--1.0....
The only real advantage I see from the second line version is that I can write that code and run a partially completed program, that for example doesn't have a notion of orders at all -- and the program can still run. But I guess this just boils down to preferences.
(I read relentlessly, too; English is not my native language though so sorry for the grammar)