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
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.
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).
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 structs 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.