Hacker News new | past | comments | ask | show | jobs | submit login

This is an important point: abstractions like generic functions are only as good as how much people respect them, and enforcement of that is largely cultural. You can add technological levels of enforcement, but those are limited at best because people are brilliantly devious and can find ways to break any technological enforcement if they set their minds to it; the key to preventing that is convincing them to set their minds to respecting abstractions instead.

For a negative example of this, C++ introduced function overloading — which is a static and therefore broken version of multiple dispatch (that calls the wrong “methods” based only on static type information). They then immediately decided to abuse the bitshift operators for I/O — in the standard library, no less. (There are other abuses of overloading but this is the most famous one.) So that didn’t exactly create a culture where people respect the semantic meaning of overloaded functions. As a result, C++ has given function overloading a really horrible reputation. Partly because it is likely to be not actually so what you want because it’s static rather than based on the actual types of arguments, but even more so because there’s no culture of semantic consistency in C++, starting from the standard library itself — you cannot trust anyone to respect the meaning of anything, not even the language authors.

In Julia, on the other hand, we’ve always been very strict about this: don’t add a method to a function unless it means the same thing. We would never dream of using bitshift operators to do I/O. Since meaning is the level where human thinking operates, this makes it reasonable to write generic code that works the way you meant it to: you can call `+` on two things and just trust that whoever has implemented `+` for those objects didn’t decide to make it append a value to an array or something wonky like that. Not that people haven’t proposed that kind of thing, but because of the culture, it gets shot down in the standard library and elsewhere in the ecosystem.

But yeah, it’s hard to see how this would happen because there is nothing technical preventing the same kinds of abuses that are rampant in C++, it’s just the invisible but extremely force of culture.




> We would never dream of using bitshift operators to do I/O

Or the sum operator for string concatenation, which is the epitome of non-commutative operation.

I like your point of view, but still I'm skeptical of function and especially operator overloading. Shouldn't these semantic constraints that you mention be enforced by the language? For example, the language does not let you overload + for a non-commutative operation, and so on.


I was curious what Julia decided to use for string concatenation (+ method would be the least surprising option for me since it's common for the most of source code in use, even while the string concatenation is non commutative).

I was surprised to find Julia uses the multiplication method for string concatenation. For me it feels as wrong as using bitshift operators for I/O but maybe I'm missing something.


+ is terribly wrong for string concatenation and people who used it first were illiterate freaks. If I had to chose among my many reasons to avoid python this by far is the strongest one. I'm forced to use formatting operators and string interpolation just to avoid the stupid +

Multiplication for concatenation makes perfect sense: it is commutative, associative, and consistent with mathematical notation. A space would be even better. And the empty string would be great, but maybe difficult to implement if you want to allow multiple-letter variable names, as julia seems to do.


We considered juxtaposition with string literals for concatenation for a while, as in `file ".txt"`. That would make `a "" b` a natural string concatenation syntax, which rather like it, but Jeff felt it was a bit too clever/weird, so we didn't do it.


Oh interesting. That would work too, but `*` is really quite nice in the context that string concatenation is properly the associative binary operation of a free monoid.


Interesting, is multiplication method used for arrays concatenation as well?

Even if using multiplication to join strings may be consistent with some properties of mathematical notation, it's less consistent with the usual meaning of the words (I checked the cosine similarity using GloVe 6B words embeddings, the similarity between "add" and "join" is 0.4 while between "multiply" and "join" is only 0.03), so it's probably the balance between being the general purpose and math oriented language.


Technical enforcement would be nice, but it's a hard design problem and my point is that even with that, you still need the cultural aspect. Time and time again, we see that culture trumps technology for these kinds of things. In this case, the proof is in the pudding: in Julia there is no technical enforcement of consistency, but semantic meaning of generic functions is broadly respected and generic code works. It would be nice to add some kind of protocols that support enforcement, but it's (apparently) not necessary and it's a hard design problem.

> For example, the language does not let you overload + for a non-commutative operation

It does allow it? I'm not even sure how one would disallow non-commutative operations. How would you know if a definition is commutative?


(Now I realize that you are one of the designers of Julia, I feel deeply honored by your answers. I really love your job with the language!)

> how one would disallow non-commutative operations. How would you know if a definition is commutative?

I don't think that this is possible without solving the halting problem. But in practice, you can do that by documenting this enforcement and making it unfeasible to overload a commutative operator with non-commutative code. For example, the callers of the overloaded commutative operator can and do assume commutativity to optimize compilation; as in, you fill a matrix with "f(i+j)" and it may only evaluate the upper-half of the matrix (this is even more interesting for the associative case). I think that Mathematica does a similar thing, I recall several symbols for operators to be overloaded assuming certain symmetries. As another example, in C++ you must overload "<" with something that is an order relation, otherwise the sort function fails. Being more fancy, a test option of the interpreter may run each call of the operator in a random order, etc.

Also, related to Mathematica, using juxtaposition for product is very natural to mathematicians. It is indeed hard point of friction when moving from Mathematica to Maple or Matlab.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: