# Syntax Surprises

**URL:** <https://discourse.julialang.org/t/syntax-surprises/92369>\
**Category:** General Usage\
**Tags:** syntax, discussion, fun, gotchas\
**Created:** [December 31, 2022, 8:00pm UTC](https://discourse.julialang.org/t/syntax-surprises/92369 "2022-12-31T20:00:02Z")\
**Posts on this page:** 20\
**Page:** 4

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [January 9, 2023, 4:23pm UTC](https://discourse.julialang.org/t/syntax-surprises/92369/62 "2023-01-09T16:23:29Z")

</div>

Yeah, as much as syntax conflicts like this are conceptually annoying and make for great syntax “wat” examples, this just doesn’t seem like it’s actually a big issue in practice and so isn’t worth the churn or breakage to eliminate wats. Sometimes I wear more of a “what if we did this?” hat; but other times I have to put a more classic, boring hat, which defaults to leavings alone that are good enough.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [January 9, 2023, 4:30pm UTC](https://discourse.julialang.org/t/syntax-surprises/92369/63 "2023-01-09T16:30:17Z")

</div>

That being said, I agree with comments above that obfuscated syntax is absolutely something that would be **good to check in a linter** , e.g. give a warning if the user has a variable named `f0` in the same scope that uses single-precision literals like `2f0`.

~~(One of the reasons that this doesn’t show up very often, I suspect, is that production Julia code doesn’t use single-precision literals all that often — if you want your code to handle single precision, then typically you want it to handle _all_ precisions, and you write precision-independent literals based on the types of the function arguments.)~~ Not really relevant since the hypothetical confusion is in the opposite direction (but requires variables named `e` or `f` and for you to write something like `2e-1` without noticing it looks like a literal).

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 10, 2023, 1:33am UTC](https://discourse.julialang.org/t/syntax-surprises/92369/64 "2023-01-10T01:33:59Z")

</div>

> [@StefanKarpinski](#):
>
> Sometimes I wear more of a “what if we did this?” hat

I would like to express that I appreciate this. We can’t be confident we’ve found an optimal solution if we don’t occasionally entertain the possibility that we haven’t.

I very much like numeric literal juxtaposition; the improved readability reduces error rate; it’s simple, intuitive, and hard to misinterpret. Most of the WATs are only encountered if you go looking for trouble.

My concern is, I wouldn’t want to pick the language that solved the interpreted vs. compiled two-language problem, only to run into another two-language problem a few years later (small-scale scripts vs. production code). Numeric juxtaposition is hard to get wrong, except for ambiguity over `e`, `E`, and `f` which raises the possibility of runtime black swans; sooner or later some knucklehead on the team is bound to mess it up (probably me) and ruin the party. I’d want assurance that, on a risk-adjusted basis, I’m not paying a penalty for the feature.

A linter solves this. I don’t need it _right now_, but having it on the roadmap puts my unease to rest: that when the time comes for a project to scale and a bunch of under-supervised 18-year-olds start getting thrown at it, or when Elon decides to use Julia for FSD, automated checks can help steer them away from trouble.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 10, 2023, 2:04am UTC](https://discourse.julialang.org/t/syntax-surprises/92369/65 "2023-01-10T02:04:08Z")

</div>

@stevengj I’d also like to express gratitude for steadfastly holding your ground and forcing us to figure out how to make it work the way it is.

---

<div class="post-metadata">

**Author:** ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)\
**Post date:** [January 14, 2023, 6:46pm UTC](https://discourse.julialang.org/t/syntax-surprises/92369/66 "2023-01-14T18:46:06Z")

</div>

Surprise - can we rely on that?

```julia
julia> foo((a,b...)...) = [a, b]
foo (generic function with 1 method)

julia> foo((1,2,3), (4,5,6), (7,8))
2-element Vector{Tuple{Any, Any, Vararg{Int64}}}:
 (1, 2, 3)
 ((4, 5, 6), (7, 8))

```

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [January 14, 2023, 8:01pm UTC](https://discourse.julialang.org/t/syntax-surprises/92369/67 "2023-01-14T20:01:28Z")

</div>

> [@klacru](#):
>
> can we rely on that?

[Yes](https://docs.julialang.org/en/v1/manual/functions/#Argument-destructuring).

---

<div class="post-metadata">

**Author:** ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)\
**Post date:** [January 14, 2023, 10:01pm UTC](https://discourse.julialang.org/t/syntax-surprises/92369/68 "2023-01-14T22:01:11Z")

</div>

I can’t see the example matches the manual. Over there we don’t have the double ellipsis.

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [January 14, 2023, 10:10pm UTC](https://discourse.julialang.org/t/syntax-surprises/92369/69 "2023-01-14T22:10:38Z")

</div>

Did you miss the sections about [varargs functions](https://docs.julialang.org/en/v1/manual/functions/#Varargs-Functions) and [destructuring assignment and multiple return values](https://docs.julialang.org/en/v1/manual/functions/#destructuring-assignment)?

---

<div class="post-metadata">

**Author:** ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)\
**Post date:** [January 15, 2023, 2:40am UTC](https://discourse.julialang.org/t/syntax-surprises/92369/70 "2023-01-15T02:40:58Z")

</div>

No. I don’t get it. My example behaves like `foo(a, b...) = [a, b]`. There is no example or rule explaining the syntax I used.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 15, 2023, 2:44am UTC](https://discourse.julialang.org/t/syntax-surprises/92369/71 "2023-01-15T02:44:36Z")

</div>

Hah, that’s a fun one. It’s conceptually similar to having a bunch of extraneous parentheses, with this weird exception:

_**Function Abduction (Part Deux)**_

```julia
julia> f(((((x,)...,)...,)...,)...) = x+27
f (generic function with 1 method)

julia> f(15)
42

julia> f(42, "where", :do, `these`, r"go?!?")
69

```

It’s also handy for masking the method signature, to prevent people from knowing the argument names:

```julia
julia> methods(f)
# 1 method for generic function "f" from Main:
 [1] f(...)
     @ REPL[1]:1

```

Here’s another fun one. Apparently underscore `_` is allowed as a fieldname for now 😈

_ **Under Scores Under Stress** _

```julia
julia> Main._ = "hi!"
"hi!"

julia> hellos = (a = "hello!", b = "hola!", _ = "hallo!")
(a = "hello!", b = "hola!", _ = "hallo!")

julia> (; b, _, a) = hellos # destructure syntax
(a = "hello!", b = "hola!", _ = "hallo!")

julia> @show Main._
       @show a
       @show b
       @show _
Main._ = "hi!"
a = "hello!"
b = "hola!"
ERROR: syntax: all-underscore identifier used as rvalue around show.jl:1128

```

And another. The surprise in this one is the unprivileged treatment of a local function’s name despite using _named function syntax_, and [it should not be possible for performance reasons](https://github.com/JuliaLang/julia/issues/47760#issuecomment-1334741784), but it’s a fun brain teaser for now:

_ **Method Impossible** _

```julia
julia> const f = let start=4, c=start+1, f(x)=x
           f() = if f(c-=1)==start; "Your mission, should you choose to accept it. 📦"
                 elseif c>0; "This message will self-destruct in $c times. "*"🕐🕑🕒"[4c-3]
                 else f=nothing; "Self-destructing! 🔥" end
       end;

julia> println(f())
       println(f())
       println(f())
       println(f())
       println(f())
       println(f())
Your mission, should you choose to accept it. 📦
This message will self-destruct in 3 times. 🕒
This message will self-destruct in 2 times. 🕑
This message will self-destruct in 1 times. 🕐
Self-destructing! 🔥
ERROR: MethodError: objects of type Nothing are not callable

```

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [January 16, 2023, 3:45pm UTC](https://discourse.julialang.org/t/syntax-surprises/92369/72 "2023-01-16T15:45:56Z")

</div>

> [@klacru](#):
>
> My example behaves like `foo(a, b...) = [a, b]`. There is no example or rule explaining the syntax I used.

With the declaration `foo(x...)`, you get all the arguments in a tuple called `x` (the vararg feature described in the doc). When you write `foo((a,b...)...)` you effectively replace `x` with `(a,b...)`. This is a destructuring assignment, of the kind described at the end of [this section](https://docs.julialang.org/en/v1/manual/functions/#destructuring-assignment). You get the first value of `x` in `a` and the rest in `b`. (And as @uniment showed, you can also write `(a,)` to get the first value and discard the rest.)

---

<div class="post-metadata">

**Author:** ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)\
**Post date:** [January 17, 2023, 11:32am UTC](https://discourse.julialang.org/t/syntax-surprises/92369/73 "2023-01-17T11:32:02Z")

</div>

> [@sijo](#):
>
> With the declaration `foo(x...)`, you get all the arguments in a tuple called `x` (the vararg feature described in the doc).

Ok, that is what I read from the doc.

> [@sijo](#):
>
> When you write `foo((a,b...)...)` you effectively replace `x` with `(a,b...)`.

There is not mention of effective replacement in the docs, only ellipsis after a variable appears there.  
Also `foo((a,b)...)` is not effectivly replaced by `foo(a, b)`.

---

<div class="post-metadata">

**Author:** ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)\
**Post date:** [January 17, 2023, 11:41am UTC](https://discourse.julialang.org/t/syntax-surprises/92369/74 "2023-01-17T11:41:32Z")

</div>

> [@sijo](#):
>
> And as @uniment showed, you can also write `(a,)`

Yes. You can do quite a lot of things, which are not documented; and then guess what is the semantics behind that. That is not like it should be!

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [January 17, 2023, 12:27pm UTC](https://discourse.julialang.org/t/syntax-surprises/92369/75 "2023-01-17T12:27:05Z")

</div>

> [@klacru](#):
>
> > [@sijo](#):
> >
> > When you write `foo((a,b...)...)` you effectively replace `x` with `(a,b...)`.
> 
> There is not mention of effective replacement in the docs, only ellipsis after a variable appears there.

Here’s how I understand it (the following quotes are from the documentation):

> The destructuring feature can also be used within a function argument. If a function argument name is written as a tuple (e.g. `(x, y)` ) instead of just a symbol, then an assignment `(x, y) = argument` will be inserted for you […]

On the surface this says that `foo(x)` can be written `foo((a, b))`, but it also references “the destructuring feature” which is described earlier in the page, and which includes this:

> If the last symbol in the assignment list is suffixed by `...` (known as _slurping_ ), then it will be assigned a collection or lazy iterator of the remaining elements of the right-hand side iterator

followed by the example of `a, b... = "hello"`. Since that’s part of the feature that “can also be used within a function argument”, it’s logical that you can do `foo((a, b...))`.

Finally, the page also says

> You can define a varargs function by following the last positional argument with an ellipsis

In the declaration `foo((a, b...))` the function has one positional argument: `(a, b...)`. So making it a vararg gives `foo((a, b...)...)`.

The documentation can surely be improved. It’s true it doesn’t say explicitly that all the features can be combined in this way, maybe that would be a worthy addition… On the other hand if you decide to nest fancy syntaxes as in the `foo((a, b...)...)` example, I think the hard-to-interpret problem is on you, and it’s not surprising that such a convoluted combination is not explicitly documented…

> [@klacru](#):
>
> > [@sijo](#):
> >
> > you can also write `(a,)`
> 
> Yes. You can do quite a lot of things, which are not documented; and then guess what is the semantics behind that. That is not like it should be!

Again from the documentation:

> A comma-separated list of variables (optionally wrapped in parentheses) can appear on the left side of an assignment: the value on the right side is _destructured_ by iterating over and assigning to each variable in turn:
> 
> ```julia
> julia> (a,b,c) = 1:3
> 1:3
> 
> julia> b
> 2
> 
> ```
> 
> The value on the right should be an iterator (see [Iteration interface](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-iteration)) at least as long as the number of variables on the left (any excess elements of the iterator are ignored).

The last sentence says that you can indeed write `(a, )` (a comma-separated list of one element) to keep only the first element.

---

<div class="post-metadata">

**Author:** ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)\
**Post date:** [January 17, 2023, 1:20pm UTC](https://discourse.julialang.org/t/syntax-surprises/92369/76 "2023-01-17T13:20:44Z")

</div>

The syntax on the left hand side of an assignment is not identical to the syntax of the formal arguments of a function. For example `(a, b...)... = 1 ,2, 3` is a syntax error. Therefore some of your conclusions seem wrong to me.

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [January 17, 2023, 1:34pm UTC](https://discourse.julialang.org/t/syntax-surprises/92369/77 "2023-01-17T13:34:04Z")

</div>

The documentation _does_ say that in the arguments of a function, you can use the “destructuring assignment” syntax. It _doesn’t_ say that variable assignment can use the function vararg syntax.

---

<div class="post-metadata">

**Author:** ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)\
**Post date:** [January 17, 2023, 2:12pm UTC](https://discourse.julialang.org/t/syntax-surprises/92369/78 "2023-01-17T14:12:28Z")

</div>

> [@sijo](#):
>
> The documentation _does_ say that in the arguments of a function, you can use the “destructuring assignment” syntax.

Actually it states: “The destructuring feature can also be used within a function argument.” The relationship between this statement and the vararg function arguments is nowhere explicitly specified.

Please let’s stop this. I am telling, that the doc is unclear to me, what is my subjective opinion. If everybody else thinks it is clear, a accept this with astonishment.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 18, 2023, 7:36am UTC](https://discourse.julialang.org/t/syntax-surprises/92369/80 "2023-01-18T07:36:14Z")

</div>

I was today years old when I learned that you can discard the rest of the elements like this:

_ **Destructure Discard** _

```julia
julia> a = Array{Int}(undef, 3);

julia> a ,= [1, 2, 3]
3-element Vector{Int64}:
 1
 2
 3

julia> a
1

```

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 21, 2023, 5:15am UTC](https://discourse.julialang.org/t/syntax-surprises/92369/81 "2023-01-21T05:15:00Z")

</div>

> [@DNF](#):
>
> Perhaps `2e9` could be an integer

In how many scenarios would this be of benefit?

The big one that comes to mind is `range(start, stop, len)`; could it be suitably addressed with this?

```julia
julia> Base.range(start, stop, len::Float64) = range(start, stop, Int(len))

julia> range(0, 10, 2e9)
0.0:5.0000000025e-9:10.0

```

---

<div class="post-metadata">

**Author:** ![suavesito](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/suavesito/32/34386_2.png) [@suavesito](https://discourse.julialang.org/u/suavesito)\
**Post date:** [January 21, 2023, 6:11am UTC](https://discourse.julialang.org/t/syntax-surprises/92369/82 "2023-01-21T06:11:36Z")

</div>

That doesn’t seem like a good idea. The problem is the next

```julia
julia> Base.range(start, stop, len::Float64) = range(start, stop, Int(len))

julia> range(0, 10, 1.5)
ERROR: InexactError: Int64(1.5)
Stacktrace:
 [1] Int64
   @ ./float.jl:788 [inlined]
 [2] range(start::Int64, stop::Int64, len::Float64)
   @ Main ./REPL[1]:1
 [3] top-level scope
   @ REPL[3]:1

```

I think this should not be treated specially, and is conflating the _usual_ meaning of `Float64`.

[Previous page](https://discourse.julialang.org/t/syntax-surprises/92369.md?page=3)

[Next page](https://discourse.julialang.org/t/syntax-surprises/92369.md?page=5)
