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.