Julia: Calling syntax for literals converts to *

Created on 23 Mar 2016  Â·  4Comments  Â·  Source: JuliaLang/julia

@c42f and I were playing with the new calling syntax and we were momentarily confused.

(i::Int)(x::Int) = i + x
a = 3
a(4) # = 7
3(4) # = 12

For some reason the parser feels its more important to multiply here than to call the function. Even (3)(4) == 12.

julia> :(3(4))
:(3 * 4)

Is this intentional, or desired?

won't change

Most helpful comment

I think Julia tries to find a balance between a syntax that is easy on the
eyes and for the novice user, while also allowing quite generic mechanisms
for advanced users. Sometimes there's a clash, and that requires trade-offs
leading to exceptions in rules that are not always straightforward to
remember.

One such ease-of-use is Julia's sensitivity to white space, i.e. 4a is
different from 4 a, and 1 +1 can mean different things depending on
context (and different from 1+1 or 1 + 1). Earlier today was an email
about 0x being parsed differently from 0a.

There seems to be a general consensus to move away from white-space
sensitivity, and towards disallowing strange corner cases rather than
trying to make sense of them; e.g. f (1,2) is now deprecated, so that
people don't get surprised by the different meanings of @f(1,2) and @f (1,2).

The parsing of numeric literals prefixing another expression falls in the
same category. It's a special rule, designed to apply only for numeric
literals. So yes, it's working as intended, it was designed before some of
the other generic mechanisms that are now in Julia, and if someone
suggested today a new "cute" syntax it would probably be met with
scepticism. At the same time, backward compatibility is important, and
other languages (e.g. Mathematica) make juxtaposition-is-multiplication
work as well, although without white space sensitivity, and without using
white space as separator in many cases.

In your case, I would have expected numeric literals to be treated
specially. I assume that this special case is handled already by the
parser, which inserts the missing * operator -- see dump(parse("3x")).
(Also, the output of parse("3*x") is interesting.) Handling types and
overloading comes later. Thus if you mentally distinguish between syntax
and interpretation -- which is a very Julian way of thinking -- then it
might be easier to make sense of things.

In my mind, Julia's syntax is defined ad-hoc, you need to read the Lisp
source code to understand it. (There's e.g. no grammar or other formal
description.) Julia's type system, on the other hand, is well described in
the documentation and associated publications. Thus, after navigating
around the syntactic surprises, there's a very clean language to be found.

I hope this didn't offend anybody.

-erik

On Wed, Mar 23, 2016 at 12:22 AM, Andy Ferris [email protected]
wrote:

Right. I do know about the juxtaposition-multiplication rules, but I
wonder if they were designed quite a while ago before overloading call
was allowed (maybe I'm wrong here too). In the cases above, it's quite
ambiguous what should happen, and it's quite surprising to see an instance
as a literal behave different to an instance with a reference. Does that
happen elsewhere in the language? Since in Julia we all seem to be quite
worried about being consistent, clear and unambiguous, do you feel there is
a better way forward?

To be clear, I don't really care that much. I can use Int(3)(4) to force
the parser into the correct behaviour, and it's a little insane to overload
calling on Int anyway!

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
https://github.com/JuliaLang/julia/issues/15593#issuecomment-200167554

Erik Schnetter [email protected]
http://www.perimeterinstitute.ca/personal/eschnetter/

All 4 comments

The behavior is intentional and most of them are documented. I don't see it mention in particular about (3)(4) though.

Right. I do know about the juxtaposition-multiplication rules, but I wonder if they were designed quite a while ago before overloading call was allowed (maybe I'm wrong here too). In the cases above, it's quite ambiguous what should happen, and it's quite surprising to see an instance as a literal behave different to an instance with a reference. Does that happen elsewhere in the language? Since in Julia we all seem to be quite worried about being consistent, clear and unambiguous, do you feel there is a better way forward?

To be clear, I don't really care that much. I can use Int(3)(4) to force the parser into the correct behaviour, and it's a little insane to overload calling on Int anyway!

I think Julia tries to find a balance between a syntax that is easy on the
eyes and for the novice user, while also allowing quite generic mechanisms
for advanced users. Sometimes there's a clash, and that requires trade-offs
leading to exceptions in rules that are not always straightforward to
remember.

One such ease-of-use is Julia's sensitivity to white space, i.e. 4a is
different from 4 a, and 1 +1 can mean different things depending on
context (and different from 1+1 or 1 + 1). Earlier today was an email
about 0x being parsed differently from 0a.

There seems to be a general consensus to move away from white-space
sensitivity, and towards disallowing strange corner cases rather than
trying to make sense of them; e.g. f (1,2) is now deprecated, so that
people don't get surprised by the different meanings of @f(1,2) and @f (1,2).

The parsing of numeric literals prefixing another expression falls in the
same category. It's a special rule, designed to apply only for numeric
literals. So yes, it's working as intended, it was designed before some of
the other generic mechanisms that are now in Julia, and if someone
suggested today a new "cute" syntax it would probably be met with
scepticism. At the same time, backward compatibility is important, and
other languages (e.g. Mathematica) make juxtaposition-is-multiplication
work as well, although without white space sensitivity, and without using
white space as separator in many cases.

In your case, I would have expected numeric literals to be treated
specially. I assume that this special case is handled already by the
parser, which inserts the missing * operator -- see dump(parse("3x")).
(Also, the output of parse("3*x") is interesting.) Handling types and
overloading comes later. Thus if you mentally distinguish between syntax
and interpretation -- which is a very Julian way of thinking -- then it
might be easier to make sense of things.

In my mind, Julia's syntax is defined ad-hoc, you need to read the Lisp
source code to understand it. (There's e.g. no grammar or other formal
description.) Julia's type system, on the other hand, is well described in
the documentation and associated publications. Thus, after navigating
around the syntactic surprises, there's a very clean language to be found.

I hope this didn't offend anybody.

-erik

On Wed, Mar 23, 2016 at 12:22 AM, Andy Ferris [email protected]
wrote:

Right. I do know about the juxtaposition-multiplication rules, but I
wonder if they were designed quite a while ago before overloading call
was allowed (maybe I'm wrong here too). In the cases above, it's quite
ambiguous what should happen, and it's quite surprising to see an instance
as a literal behave different to an instance with a reference. Does that
happen elsewhere in the language? Since in Julia we all seem to be quite
worried about being consistent, clear and unambiguous, do you feel there is
a better way forward?

To be clear, I don't really care that much. I can use Int(3)(4) to force
the parser into the correct behaviour, and it's a little insane to overload
calling on Int anyway!

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
https://github.com/JuliaLang/julia/issues/15593#issuecomment-200167554

Erik Schnetter [email protected]
http://www.perimeterinstitute.ca/personal/eschnetter/

@eschnett thanks a lot for the detailed overview.

Was this page helpful?
0 / 5 - 0 ratings