2 ms·
I don't use Clojure, but I've applied some of its lessons to my work in Julia. The biggest one is the benefit of using simple, literal datatypes over classes/s
by SatvikBeri 6y ago
I don't use Clojure, but I've applied some of its lessons to my work in Julia.
The biggest one is the benefit of using simple, literal datatypes over classes/structs. If a function takes literals, you can just pick it up and run it, and if most of your code uses simple data types, it's more composable by default.
The mini-project I'm working on now has just one custom type, if I had written it 2 years ago it would probably have ten. This has made a big difference in the testability and reusability of my functions.
- darioush 6y agoFunny how a lot of "work" on large scale code bases boils down to de-coupling code from the datatypes they never needed to be dependent on (eg, function takes obj but only needs obj.foo)
- SatvikBeri 6y agoIt's a problem without an easy solution. There are some cases where you genuinely want to couple fields together basically all the time (e.g. a database driver, address, etc. into a "DB" object) but there are many more cases where you want to couple fields together 80% of the time. Those are the hard ones to deal with - separate your fields, and you need to do a lot of redundant work, but if you combine them that can be a pain to unravel and slow down your loops. Julia's multiple dispatch is really helpful here, because you can e.g. write one connect_to_db that takes a DB object, and another that takes a string. I've found this flexibility to be surprisingly helpful, it completely takes away the tradeoff in many (not all) cases.
- A-Train 6y agoPretty interesting topic. I am all for composability. However, I don't necessarily agree with particular benefits of pure data literals. I feel more secure when I wrap even simple types like Strings so that ItemId, UserId is a String but I cannot interchange them. Similar level of composability with objects and structs can be achieved with generics and traits. I have a code that operates on arrays and matrices however particular implementations depend on the context - it is a DSL embedded into the application. For example I have `lazy matrices` that don't own the matrix or I can have matrices with owned data.
- SatvikBeri 6y agoFor sure. You can think of static types as deliberately preventing composability in cases where you definitely don't want it (e.g. passing in a user_id when dollars are expected), and that's often worth it. The point about matrix types is interesting, because Julia does have a huge host of matrix types, which are primarily used for efficiency via multiple dispatch. Some examples are upper triangular, symmetric, diagonal etc. One cool case is UniformScaling, which is an almost-matrix representing the identity times a constant. It's stored as just that constant, and can be used in 90% of the places a matrix can be used. Implementing these sorts of partial interfaces is one of the tricky parts of static typing, especially when you have multiple partial interfaces for one main interface. You can get around this with typeclasses a la Haskell, but that's a lot of overhead, especially if you have just one example of each partial interface.