Just to get it out of the way, I'll point out first that since all of the aforementioned languages are turing-complete, they can all solve all of the same programming problems. Therefore, there is never a question of whether one language can be used to emulate the features of another language. Instead, the question is whether one programming language makes the right paradigms sufficiently more useful or obvious than another language, for achieving the objectives of a particular programming problem.1) OO-style dispatch is essentially single-dispatch on the first (implicit/hidden) argument. Multiple dispatch is a strict superset of that. So you could provide both, but there's no benefit. It complicates the user's mental model of the language to provide these as two independent features, rather than one unified system.2) In C++ and Java, the type signature of the dispatch delegate is fully resolved at compile time. By contrast, in Julia, the dispatch occurs at runtime, when the actual type is known. The visitor design is exactly the sort of anti-pattern that Julia seeks to eliminate by removing the forced distinction between multiple dispatch functions (interfaces) and methods associated with types (ref. question #1).3) As noted by the wikipedia article, this is a design problem, not a language problem. Some languages, like Python and Julia, therefore choose not to hide anything from the user, but simply provide recommendations against certain patterns. In Julia, it is generally discouraged to directly access the fields of an object outside some set of methods that are understood to be implementing the informal API for that type. Similarly, in Python, the convention is to prefix private data with `_`, since in general the dot-oriented access is the approved access API, but the general principle is the same.
@ Scott, correct me if I am wrong: you say that fields of types should be accessible only to methods in the module where the type is defined, right?
For example in Julia 0.3.10 I can write:
module X
export myType,foo
type myType
dontTouchMe
end
foo(x::myType) = x.dontTouchMe
end
i feel like these conversations are often driven by people who want "new language" to be like whatever language they are most familiar with. and those people, since they are naturally in an uncomfortable place (away from their "old" language) tend to be the most vocal.
so i just wanted to add a voice saying, no. i don't want this. i think the initial design of the language was correct. the added complexity here seems unnecessary to me. things work just fine in more functional languages that do not have this kind of constraint. they also work fine in python - if you want to use underscores in names as a sign to others, go ahead.
more than that, there are more important problems still to be addressed. inheritance of fields, for example.
The problem is, how are you going to police all of the _ accesses, to give somebody crap about it?Are you going to have to grep all of the registered packages constantly?
Ok I have to say that I am not that sure about the immutable thingy as for the regular type. For me an immutable is just like say an Int32 that also does not try to hide that it has 32 bits. Thus I do not see why an ARGB immutable that is bitwise represented by 4 packed bytes should hide its structure. But again, I am not 100% certain about this.
Hi All,
I have been using C++ and Python for several years
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.
1) We can have multiple dispatch a la Julia and still allow types to have methods. These two things seeem independent to me.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:
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.
- 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.
julia> @less 1 + 2.3+(x::Number, y::Number) = +(promote(x,y)...)
julia> @code_llvm 1 + 2.5define double @"julia_+_21457"(i64, double) {top:%2 = sitofp i64 %0 to double%3 = fadd double %2, %1ret double %3}
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)
3) Encapsulation:
> External dispatch does make it non-obvious how to enforce encapsulation
True, but for example, there are some proposals (Scott's one) where you can explicitly indicate that some fields are private to the module where the type is defined. This is just a proposal that, as Scott pointed out, is opt in, will not break anybody's code and I honestly do not think adds any significant complexity to the language. But, hey, this is just 'a' proposal.
Although Python gets by fine without any enforced privacy, Python is also notorious for being poorly suited for writing large scale reliable systems - lack of privacy of internals is only one factor among many, but it contributes.
However this will be very difficult to convince enough of the core development group that it needs to be implemented (hint: step one is to create a proof-of-concept implementation) as a first-class language feature, when it could potentially be implemented via macros in user code. Especially on top of getfield overloading, #1974.
P.S: Scott, for everyone's benefit, please refrain from using the "private parts" metaphor.
The real question with any notion of privacy is "private from whom?" Methods don't belong to any particular argument, so which of their arguments' private fields are they allowed to fiddle with? And what about more granular permissions like r/w? There are many ways to answer these issues, but whatever one chooses, it's more complicated than just marking some fields as private. It also doesn't enable anyone to do anything that they couldn't do before, which is what we tend to prioritize at this point.
Many factors, and many of the complaints apply equally to Javascript or any other dynamically typed language. Julia talks more about types than most other dynamic languages, but many things are still not statically checked and can lead to runtime-only errors. The problem boils down to whether or not a compiler is verifying invariants, interfaces, types, and safety in your code ahead of time. It's a common justification for using languages like Ada, Rust, Haskell, Scala, etc. Julia may be more amenable to offline static analysis than many other dynamic languages, but this really isn't the design space that's being targeted here, and tooling for this remains immature.
You've quoted that phrase multiple times since May, sorry I deliberately chose not to read that disaster of a many-pages-long mailing list thread so was unaware it was first written by someone else. I'd chastise him too and recommend a different choice of words. The "consenting adults" phrasing should probably be retired as well, given the growth and standards that we'd like to maintain as a community.
On Wed, Jul 8, 2015, at 01:28 PM, Stefan Karpinski wrote:The real question with any notion of privacy is "private from whom?" Methods don't belong to any particular argument, so which of their arguments' private fields are they allowed to fiddle with? And what about more granular permissions like r/w? There are many ways to answer these issues, but whatever one chooses, it's more complicated than just marking some fields as private. It also doesn't enable anyone to do anything that they couldn't do before, which is what we tend to prioritize at this point.This is an excellent point. I'm curious what the exact semantics are of the public/private keywords Scott is proposing.
I agree that defining interfaces is currently a problem but there's work on multiple fronts happening to make that better. I think though that the question should not be "How can I restrict what users can do with my package" and more "How do I communicate what I expect users to do".It also seems that between getfield overloading and Traits/Interfaces we'll have mechanisms for package developers to get as granular as they want, and I wouldn't be surprised if someone ends up developing an `@private` macro that automatically overloads field access to raise an error or something.Also FWIW I've always read "Consulting Adults" in a strictly platonic way until the addition of the private parts metaphor. Probably I've actually been reading it more as "Responsible" or "Trustworthy" in the sense that we don't need to go out of our way to protect again bad/stupid behavior in other code.
-s