Codata in action, or how to connect FP and OOP
javiercasas.com
Codata in action, or how to connect FP and OOP
1–10 of 58 posts
Re: Codata in action, or how to connect FP and OOP
#2[ Codata in Action ] https://link.springer.com/chapter/10.1007/978-3-030-17184-1_...
Re: Codata in action, or how to connect FP and OOP
#3Re: Codata in action, or how to connect FP and OOP
#4- In a FP language you can add a new function to an existing datatype just by adding a function. But, if you want to add a new case, you have to add the constructor and modify all the functions that use the datatype, which means modifying a lot of files and recompiling most of the program.
(...)"
...and by using multiple dispatch (as in Julia) you can do both. And it just works. True code reuse. Why did it take us so long to recognise this?
Re: Codata in action, or how to connect FP and OOP
#5" (...) - In an OO language, you can add a new case by creating another subclass and implementing the methods. But, if you want to add a new function to a datatype, you have to add it to the superclass and implement it on all the existing subclasses, which means modifying a lot of files and recompiling most of the program. - In a FP language you can add a new function to an existing datatype just by adding a function…
Re: Codata in action, or how to connect FP and OOP
#6" (...) - In an OO language, you can add a new case by creating another subclass and implementing the methods. But, if you want to add a new function to a datatype, you have to add it to the superclass and implement it on all the existing subclasses, which means modifying a lot of files and recompiling most of the program. - In a FP language you can add a new function to an existing datatype just by adding a function…
The idea here is that you can have an opaque interface. Then, adding new implementations of that interface is very easy. But, if you want to extend the interface, you need to modify all of the existing implementations. Multiple dispatch suffers of this problem just as much as single dispatch.
In the other case, you have a transparent interface - anyone can build code based on your data type. But, if you add more cases to your data type, anyone who had functionality built on it needs to take into account the new cases.
I think that this is in inherently an unavoidable problem. You can of course expose both kinds of constructs in your language, but you can't make interface implementation easily modifiable, and you can't make sum types easily extensible. The programmer ultimately has to choose the one that they believe will best capture the domain and its probable evolution.
What multiple dispatch can do is take some cases where sum types are obviously preferable to single dispatch (operations on related objects) and apply the interface abstraction to those cases as well (without reaching for horrible solutions like the visitor pattern).
Edit: thinking a bit more about the article, what they are showing is that you can essentially use the visitor pattern (and multiple dispatch) to implement GADTs instead of using them for regular multiple dispatch with inheritance. Basically, you can use them bring completely disparate types under the same umbrella, just like a GADT. I'm not sure that this still allows subtyping of that GADT as if it were a regular class.
Re: Codata in action, or how to connect FP and OOP
#7" (...) - In an OO language, you can add a new case by creating another subclass and implementing the methods. But, if you want to add a new function to a datatype, you have to add it to the superclass and implement it on all the existing subclasses, which means modifying a lot of files and recompiling most of the program. - In a FP language you can add a new function to an existing datatype just by adding a function…
It didn't take us long. Schemers did multiple dispatch at least 40 years ago. SICP explains how to do it.
(Arguably, both R and Julia are Lisp dialects under the hood, just disguised behind a more arcane syntax. Which goes to show that 'practioners' take Lisp seriously exactly as long as they don't know it's Lisp.)
Re: Codata in action, or how to connect FP and OOP
#8" (...) - In an OO language, you can add a new case by creating another subclass and implementing the methods. But, if you want to add a new function to a datatype, you have to add it to the superclass and implement it on all the existing subclasses, which means modifying a lot of files and recompiling most of the program. - In a FP language you can add a new function to an existing datatype just by adding a function…
Re: Codata in action, or how to connect FP and OOP
#9" (...) - In an OO language, you can add a new case by creating another subclass and implementing the methods. But, if you want to add a new function to a datatype, you have to add it to the superclass and implement it on all the existing subclasses, which means modifying a lot of files and recompiling most of the program. - In a FP language you can add a new function to an existing datatype just by adding a function…
The article's concern is real but overstated in my opinion. When adding a new function in a hierarchy you'll either have a good default or you'll be implementing via type matching branches or 10 implementations in each type behind multiple dispatch.
The difference, to me, is minimal.
Re: Codata in action, or how to connect FP and OOP
#10" (...) - In an OO language, you can add a new case by creating another subclass and implementing the methods. But, if you want to add a new function to a datatype, you have to add it to the superclass and implement it on all the existing subclasses, which means modifying a lot of files and recompiling most of the program. - In a FP language you can add a new function to an existing datatype just by adding a function…
Any OOP with inheritance does multiple dispatch. Java, C++ vitual functions, python via ducktyping. The article's concern is real but overstated in my opinion. When adding a new function in a hierarchy you'll either have a good default or you'll be implementing via type matching branches or 10 implementations in each type behind multiple dispatch. The difference, to me, is minimal.
Java, Python and C++ require Visitor machinery that you ahev to write, for each case, to implement multiple dispatch (and Visitor only works for double dispatch, if you want more than 2 arguments you need even more boilerplate). Julia and CLOS essentially have that machinery built in.
In case this is not clear, multiple dispatch refers to choosing which method implementation to call based on the specific runtime subtypes of all function arguments, not just the runtime type of `this` (which is all that Java, C++, and even Python can dispatch based on). It's basically like applying C++ function overloading rules at runtime.
> The article's concern is real but overstated in my opinion. When adding a new function in a hierarchy you'll either have a good default or you'll be implementing via type matching branches or 10 implementations in each type behind multiple dispatch.
That's assuming you can modify all existing implementations. If you can't (e.g. if you wanted to modify Iterable to add a new method) then the solution is just.. don't do that. Note that the article also doesn't offer a solution - they're just showing that multiple dispatch can be used to implement a different construct with different limitations (GADTs).