5 ms·
This is known as the expression problem: https://en.wikipedia.org/wiki/Expression_problem https://en.wikipedia.org/wiki/Expression_problem
by millstone 6y ago
This is known as the expression problem: https://en.wikipedia.org/wiki/Expression_problem https://en.wikipedia.org/wiki/Expression_problem
- GistNoesis 6y agoI like Julia's solution to it : Multiple dispatch. It's great for code reuse and generic algorithms, but it kind of need the magic of the Julia compiler to make it shine. JuliaCon 2019 | The Unreasonable Effectiveness of Multiple Dispatch | Stefan Karpinski https://www.youtube.com/watch?v=kc9HwsxE1OY https://www.youtube.com/watch?v=kc9HwsxE1OY
- smabie 6y agoJulia's function polymorphism shines in a lot of cases, but in general it is less powerful than the OOP solution and also I find it much more difficult to read. For example, I recently ran into this problem when prototyping a new Julia library. Without going too into the specifics, I can only match on a type of a object. With Scala say, I can override the method of an object at creation without actually defining a class. In order to do a similar thing with Julia, I have to package the function as a field of the struct, I can't do multiple dispatch on it. In general I think multiple dispatch is great for the incremental adding of new functionality without modifying the original source but bad at dynamically augmenting functionality at runtime. A common example in Scala is creating an iterator. I can override the next and hasNext methods at object creation instead of creating a whole new class with a name. With Julia I would have to define a new kind of iterator at the top-level and then implement the necessary functions. Let's say I want to have an iterator type of numbers in which I want to multiply or add constants to. In Scala I can easily return a new iterator that wraps the old one with overridden methods that adds or multiples by the constant. I could write val newIter = 2 + iter Or whatever and with the right definition of +, everything would work correctly. In Julia I belive the only way to make this work would be to package the next and hasNext functions (or their Julia equivalents) inside the struct itself, which is unidiomatic I believe. Also the amount of type-piracy can get a little annoying. A lot of libraries end up defining alternative dispatches that are inappropriate. For Julia's problem domain, I do think this approach makes more sense than OOP and leads to saner scientific code. A lot of Python scientific computing libraries have these crazy baroque mutation heavy brain dead OOP interfaces that serve no purpose. It's just that in some cases, the packaging of data and functions together is really the only way to sanely solve a given problem.
- ChrisRackauckas 6y ago>Julia's function polymorphism shines in a lot of cases, but in general it is less powerful than the OOP solution and also I find it much more difficult to read. Given that OOP is single dispatch and multiple dispatch is a strict generalization, that's not just wrong or an opinion but it's a statement that can't be true. a.b(x) is equivalent to b(a,x) where b is a (possibly callbale struct) function you allow dispatching on a but not x. Multiple dispatch is the case where you can, well, dispatch on both. >Without going too into the specifics, I can only match on a type of a object. With Scala say, I can override the method of an object at creation without actually defining a class. You could also just drop to Val to dispatch on values or even define calls from the parameters like GeneralizedGenerated. That's pretty much the behavior you're trying to recreate so that would just do it directly. It's not the most common thing to do since you will hit dynamic dispatch, but of course if you're trying to dynamically add or change functions that's bound to happen. >Also the amount of type-piracy can get a little annoying. A lot of libraries end up defining alternative dispatches that are inappropriate. Interesting. Can you please make a list?
- snicker7 6y agoYour example is specific to not all OOP languages, only those that have prototypical inheritance.
- ahefner 6y agoAs a Common Lisp head, I love generic functions / multiple dispatch and would take them even over classes and inheritance as a language feature, but it's definitely cheating when the expression problem is framed in terms of static type systems where your code is guaranteed not to fall over at runtime with a 'no applicable method' error'. (...although I could have gotten a lot of useful work done with my dirty dynamic types and shameful runtime errors in all the years people searched for a solution to the expression problem...)
- wodenokoto 6y agoDoesn't R also use multiple dispatch[1]? What magic does Julia bring to the game that R doesn't? [1] http://adv-r.had.co.nz/S4.html http://adv-r.had.co.nz/S4.html
- GistNoesis 6y agoJulia makes it a zero-cost abstraction by emitting and optimizing the code dynamically.
- amkkma 6y agoThe type system. Also making it a zero cost abstraction as mentioned by the other child comment. Type system and language semantics are critical for that as well, not just the compiler.