I don’t completely get this. What happens if the objects in question haven’t implemented the collidable
interface?
to add on this narrative, often, OO language would have a class collidable_obj
, and then say, car and bus inherit from it. The problem is that if you want to build things on top, you either have to convince author to add something to handle your class, or you copy source code and do it yourself.
But in multi-dispatch paradigm, you can just extend the collide
function to collode(a::collidable_obj, b::your_obj)
, which boosts the re-usability in science domain dramatically.
The assumption here is that you care for data flow (i.e. outcome of function rather than change of internal states), so clearly if we’re talking about collision in game engine or something, OO would make more sense to a lot of people.
But couldn’t multiple dispatch handle changes in internal state just as well as OO?
not as ‘intuitive’, in terms of mental picture and code base separation, some people would argue.
I’m not quite convinced. More familiar, probably.
That is an interesting idea and would certainly alleviate this problem a bit. But it won’t be quite as good:
- This discoverability feature is itself not very discoverable. If you just write normal code, then you would never notice that this feature is there. Since it only kicks in, if you don’t write the method and just start with a parenthesis, and know that you can use tab to get suggestions. In the OO case, you just write the object as if you did not want to use any feature and the suggestion list just pops up when you write the dot.
This might sound trivial, but using LaTeX for example, I don’t really use macros where you need to type some shorthand for something and hit a certain button so that it creates the \begin{…} \end{…} wrapping for it. Because I always forget them, and they aren’t really suggested to me. But I do take the suggestion of adding the corresponding \end{} to the \begin I typed.
So whether or not the feature presents itself to you, or whether you need to find it somewhere is a big difference. In a sense it is the difference between vim and other editors. And there aren’t that many vim users. - You need to decide when to trigger the suggestions. In the OO case, the suggestions start appearing when using the dot. If the list is too long, you can try guessing the first letter and see if the list is now short enough. You can also delete that letter and go back to the larger list and try a different letter. If you have to press tab, you can’t quite play with it as interactively.
I guess you could move the cursor into a searchbar of the list when you press tab to help with that though.
So I would say, that while it would certainly help, it won’t be quite as natural as the OO version. And the second issue I have with this is: It does not exist yet.
I am not sure if I understand what you are saying, so I am going to rephrase it so that you can correct me: You are saying that for things that work in other language (i.e. normal methods) there does not have to be a difference, i.e. you could use normal methods in these cases which could be namespaced and only use the multiple-dispatch like methods when needed?
Because I don’t get what you want to say with this. There aren’t really two different types of methods in julia, are there?
And this sounds a bit like the difference between functions and methods and not necessarily multiple-dispatch methods and methods. I.e. you have functions which don’t belong to anything and methods which belong to an object. But I also don’t really get what the difference between functions and multiple dispatch is…
Well except for the fact that you would write the distinction of cases for different types in the function body, while it is spread over different objects in the multiple dispatch case. So I guess in a sense it is a global function @override decorator.
Julia IDEs just don’t have the massive history and funding that have gone into Java editors. This is largely orthogonal to multiple dispatch vs OOP. Just because nobody has made a nice and convenient UI for discovery of methods doesn’t mean it can’t be done, it just means that nobody has done it.
You could imagine writing obj
plus some magic key combination would prompt an UI allowing you to select the method and would rewrite it as method(obj)
. Maybe there’ll be a PR proposing obj1:obj2(method)
as an alias for method(obj1,obj2)
or some crazy syntax like that, and then you’d just get standard REPL completion. There’s already |>
which allows you to do eg randn(2,2) |> qr
. Tab completion doesn’t restrict to the correct methods right now, but that’s probably a 10-lines PR away. There is a large design space that is still unexplored just because multiple dispatch languages are less “standard” than OOP.
Also there’s a huge difference in communities: I know many people that don’t particularly like Java-style IDEs and would definitely object to
And there aren’t that many vim users.
I don’t think it’s too big a hurdle to have to learn a shortcut to trigger method discovery. You also have to learn that you have to write .
in order to access properties and methods in OO.
Unless everyone is perpetually a first time user of Julia, this is not a big deal.
Also, I don’t see how this is an issue with multiple dispatch specifically. Isn’t this just how it is with every paradigm except class-based OO?
Singular dispatch is simply a big giant annoyance every time I want behaviour to depend on more than one single input argument type. If could get back of half the time I’ve spent coding input parsing, I would probably have accomplished great things in my life Multiple dispatch solves this elegantly.
Furthermore, external methods allow me to add behaviour to types without having to change other peoples code. These features are huge steps forward, in my opinion.
I actually have a (somewhat buggy) version of this since a few years :
I don’t use it much though, probably because it doesn’t work well enough.
This is all documented in detail:
https://docs.julialang.org/en/v1/manual/methods/
but in case of TL;DR:
-
a function is a collection of methods, usually organized by a name (but there are anonymous functions),
-
multiple dispatch is the mechanism that looks up the method to use from this collection
-
methods don’t “belong to” any object, but they “belong to” a function in the sense above
-
namespaces are completely orthogonal to this.
Just an update to this: I am, right now, struggling with how handle various combinations of inputs to a Matlab plotting function for a class I’m writing. Is the axis handle specified? Are plot ranges given? What about a preprocessor? It is infuriating. Singular dispatch !! I’d give an arm and a leg to be allowed to transition to a multiple dispatch language (i.e. Julia).
No. I’m saying multiple dispatched function could be namespaced as well.
That is correct. I’m just saying that what you are complaining about isn’t about multiple dispatch at all.
On functions and methods: try playing with the REPL.
This defines the function somefunction
with no methods:
julia> function somefunction end
somefunction (generic function with 0 methods)
This defines a method of somefunction
, that dispatches on Int
and String
args. So multiple dispatch.
julia> somefunction(x::Int, y::String) = string(x, y)
somefunction (generic function with 1 method)
Now say you defined these in a module - Module1.
In some other package you want to define a new type and add a method for it to somefunc
module Module2
using Module1
struct NewType end
Module1.somefunction(x::Int, y::NewType) = string(x, "some string")
end
Namespacing, multiple dispatch, methods and functions.
Other packages just call Module1.somefunction(2, NewType())
, and will work with your new custom type from Module2. This makes clean package interop ridiculously easy, and greatly reduces the total number of methods we need, as you can keep reusing the same ones from Base.
Yes its harder to auto complete method names than oop. But there are far less to remember anyway and namespacing is much less of a problem.
I’ve been learning Julia for roughly six months, coming from (mostly) python and C. Multiple dispatch is definitely growing on me. I don’t feel as much oscillation between using classes and using more imperative style.
A simple example from yesterday: I was using hcubature
(Thanks @stevengj!!) and it likes a function with a signature like f(x)
where x is a vector, but I was also using Plots, which, if I want to write plot(x,y,f, st=:surface)
, expects f(x,y)
, where x
and y
are the two scalar args which would have been packed into the vector x
. I started to use an anonymous function, but instead did this:
f((x,y)) = some expression # takes a single argument and unpacks it into the two scalars
f(x,y) = f((x,y)) # directly takes the two scalars
and boom, I can either use f with separate scalar arguments or with a vector of args without doing something like f_for_hcube
and f_for_plot
, or making a class with two different methods like f.for_plot
or f.for_hcube
.
It’s a tiny example, but it kept the function definition simple and clean as well as the code that calls it.
Others have said this in various ways, but I just want to emphasize this point from yuyichao. Multiple dispatch is a language feature, not UI feature. The construction of the language does make some UI features harder or impossible to do, and that’s certainly a trade-off one has to consider, but it’s really a different thing. And, speaking as someone that used python exclusively before this, I can honestly say that I haven’t missed it much in ~3 years using mostly julia.
Others have already talked about the usefulness of MD for extensibility, and I’ll add my endorsement to Stefan’s video linked above, but given your a math person, I should think multiple dispatch should make a lot of sense to you. Thinking about addition, is there any reason why sum(x, y)
should belong to x
rather than y
?
Even plots, which you mentioned are the same way. Why should the plot
function belong to the xaxis argument vs the yaxis argument? If I’m writing a new vector-like type, do I really want to have to re-write all of the different plot functions (scatter, barplot, boxplot etc) for my type, or do I just want to tell the language to treat it like an array and have dispatch take care of it for me?
I have to say, coming from C++ (and a little Python) and also going through losing the autocomplete feature of .
or ->
, I am shocked by how big a deal people make out of this (granted, it’s not that many people that I’ve seen complaining about it, but many of those who do make it sound like they were asked to shoot their pet). I pretty much just forgot about it after a couple of weeks and never looked back, I can’t even say I was particularly heartbroken to have lost it in the first place. Part of it is that I just don’t think this way anymore: I’m now much more likely to want to know methods(f)
(which I can simply type into the REPL) than which struct
s are accepted as the first argument to f
. It also seems to me that, as has already been pointed out, if you are sufficiently determined you could just build tooling to give you exactly the same tooling for this sort of discovery in Julia, though granted said tooling would be more complicated than it would be for most OO languages.
Interfaces and dispatch can be orthogonal concepts. Sometimes you want dispatch to select for you between different objects with completely different interfaces. This is not uncommon. For me the most prominent example is that, when I work on IO-related code, I very often need to write functions that accept either IO
objects or buffers (Vector{UInt8}
) as arguments. These two things have completely different interfaces for good reason. With multiple dispatch it is trivially easy for me to write generic code that works for either of these very different objects, even if all of the inner code that deals with them directly must be different.
I’ve said this before, but multiple dispatch as a central paradigm really is the ultimate killer feature of Julia to me. Julia does quite a lot of things right, but to me, this more than anything else is the thing that keeps me wanting to use Julia pretty much exclusively. Class-based OOP has seemed horribly broken to me since about a month after starting to use Julia, and, interestingly I don’t think I would have walked away with that perception of it had I not spent so many years on strictly class-based OOP languages.
Given that the position of arguments is rarely relevant per se for method discovery, methodswith
should be perfect for this purpose.
No not necessarily. Universal function call syntax would basically kill the possibility of having any namespace.
Please don’t review old topics for new suggestions. You may want to start a new one, but first kindly read