Problem is, some fields for some cases should be public, because this is the most natural option...
On Wednesday, July 8, 2015 at 1:56:37 PM UTC+2, Milan Bouchet-Valat wrote: > > Le mercredi 08 juillet 2015 à 12:37 +0200, Stefan Karpinski a écrit : > > On Sun, Jul 5, 2015 at 7:30 PM, Julian Manzano < > > [email protected] <javascript:>> wrote: > > > Hi All, > > > > > > I have been using C++ and Python for several years > > > > > I'll comment on this later... > > > > > and I am very curious about Julia, I've got the REPL working on my > > > workstation and I am really impressed so far with what I've seen. > > > > > Thanks :-) > > > > > However there are some design decisions in the language that I fail > > > to understand and I would really appreciate if someone could > > > explain the rationale: > > > > > > The main point that I fail to understand is the decision not to > > > allow member functions. > > > The typical explanation that I find everywhere is that Julia > > > designers have chosen all the methods to be external because this > > > is cleaner (specially for mathematical methods where there is no > > > clear owner) and allows for multiple dispatch. > > > This explanation does not convince me for the following reasons: > > > > > > 1) We can have multiple dispatch a la Julia and still allow types > > > to have methods. These two things seeem independent to me. > > > > > These things are distinct but not orthogonal. Multiple dispatch is a > > generalization of single dispatch. As such, it is strictly more > > expressive, and having two separate dispatch mechanisms – a weak one > > for "internal" methods and a more powerful one for external methods – > > would be non-orthogonal while not increasing the overall expressive > > power of the language at all. That's lose-lose from a language design > > perspective. > > > > > 2) Dynamic multiple dispatch can also be done as a byproduct of > > > single dispatch using the visitor pattern (C++, Java, etc.), so in > > > that sense, multiple dispatch is not a new feature. > > > > > This isn't really true – or at least double dispatch requires an > > unacceptable amount of coupling between classes that should be > > unrelated to emulate proper multiple dispatch. This article has a > > pretty lucid explanation of the issues. In particular note the bit > > about the price of double dispatch: > > > Adding new shapes will be cumbersome: we will have to change all > > > existing visitors to add the new case. > > > Dangerous for bugs too: when adding new subtypes of Shape, one > > > might easily forget to override the accept method which will lead > > > to unwanted behaviour: All visitors would treat instances of the > > > newly created type like its super type. > > > > > So, single dispatch allows you to emulate multiple dispatch, but only > > awkwardly and in a way that makes any instance of the expression > > problem (and they are not uncommon at all) a maintenance nightmare. > > > > Consider how to make `1 + obj` work just as well as `obj + 1` – i.e. > > how to make dispatch symmetric for a new type with a pre-existing > > type. In Python you can use __radd__ methods, but this is clearly a > > hack that just addresses this one particular instance of the > > expression problem in a non-general way. What you really need here is > > precisely multiple dispatch – with it, this is completely trivial to > > do. In fact, with Julia's promotion and conversion system (which is > > really just a clever application of multiple dispatch), you don't > > have to explicitly handle this case, you just provide the appropriate > > promotion rules and you can solve this entire class of promotion > > problems all at once in a completely general and extensible way. This > > is, in fact, how mixed-type arithmetic between built-in types are > > defined: > > > > julia> @less 1 + 2.3 > > +(x::Number, y::Number) = +(promote(x,y)...) > > > > If you define your own type, you hook into the same system and it > > just works. And it's efficient. Despite the fact that really basic > > mathematical operations like + are generic functions and mixed type > > addition conceptually goes through many layers of dispatch, it still > > boils down to the minimal two instructions: > > > > julia> @code_llvm 1 + 2.5 > > > > define double @"julia_+_21457"(i64, double) { > > top: > > %2 = sitofp i64 %0 to double > > %3 = fadd double %2, %1 > > ret double %3 > > } > > > > Compare this with the cost of dynamic dispatch through a vtable even > > in a fast language like C++ – if you had to do addition with two > > jumps through vtables, it would be a performance disaster. Perhaps > > you could backport some of the technology from Julia to a single > > dispatch design. In fact, modern C++ compilers rely heavily on > > devirtualization, which is essentially a mild form of how Julia's > > compiler manages this, but I'm really not sure if it would work in > > the large – there's a strangely nice synergy between dynamic type > > inference and multiple dispatch. Expressing complex polymorphic > > behaviors using dispatch is not only convenient, it also gives the > > compiler a huge amount of type information in a form that it can > > reason quite effectively about. > > > > > 3) Lack of member functions forces all field to be public and > > > therefore I cannot understand how Julia will avoid the object orgy > > > anti-pattern (https://en.wikipedia.org/wiki/Object_orgy) > > > > > External dispatch does make it non-obvious how to enforce > > encapsulation. However, lots of languages don't enforce member > > encapsulation and get by just fine. Python, for example, doesn't have > > private members, and this doesn't seem to lead to any kind of orgy > > that I've ever noticed. They have a convention that members starting > > with _ are private and that works pretty well – if you access one of > > those and your code breaks in the future, you have only yourself to > > blame. In Julia, we take this attitude a bit further and consider all > > fields private unless otherwise indicated in the documentation of a > > type. So far this hasn't caused trouble. > Then maybe this fact should be stressed more in the documentation. For > example, in the manual, nothing implies that fields should be > considered private at all: > http://docs.julialang.org/en/latest/manual/types/#composite-types > > In the recent discussions, I had the feeling that many contributors > weren't clear on whether fields are considered private or not. > > Also, to me the project of being able to overload the a.b field access > syntax [1] goes against the idea that fields are private. In that > issue, that feature was even considered as a way of implementing an > abstraction on top of a given structure. That's probably fine as long > as it's only used by packages interacting with other languages where > the convention is different, but beyond that it would really blur the > message about private fields. > > So basically, I think we should be absolutely clear about whether > accessing fields from external code is subject to breaking at any point > or not. (Other than that, I agree with all of your points.) > > > Regards > > > 1: https://github.com/JuliaLang/julia/issues/1974 > > > You may find it strange for a language not to have class-based single > > -dispatch object-orientation because both of the languages you've > > used happen to have this model. While it's been fairly successful, > > this model hasn't been the panacea that it was touted to be in the > > 1990s and early 2000s. There are many programming languages that > > don't work this way at all and don't miss it. C is still the most > > popular language and doesn't do this. Almost all the functional > > languages don't do things this way. Give the multiple dispatch > > paradigm a try for a while. I think you'll find that it grows on you. > > Fair warning: after getting used to it, it's hard to go back. >
