nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.58k stars 1.47k forks source link

Undocumented interaction between multiple variables declaration and assignment #18076

Open alaviss opened 3 years ago

alaviss commented 3 years ago

The way this form of declaration work in Nim is currently unspecified in the manual.

In CPS we need to know the exact semantics for AST simplification (turn IdentDefs with multiple variables into multiple IdentDefs with one variable each).

We will likely follow the current implementation in the compiler, but this should be documented and evaluated to see if it should stay that way.

Example

var i = 0

proc foo(): int =
  inc i
  result = i

let a, b, c = foo()
echo a
echo b
echo c

Current Output

Make a guess before opening :)

``` 1 2 3 ```

Additional Information

$ nim -v
Nim Compiler Version 1.5.1 [Linux: amd64]
Compiled at 2021-05-23
Copyright (c) 2006-2021 by Andreas Rumpf

git hash: 61630c6aee56acf688c48c00f5a6711a59e79616
active boot switches: -d:release -d:nimUseLinenoise
Araq commented 3 years ago

I made the correct guess because I remember this quirk. I think it's fine to follow what the compiler does but the compiler should produce a warning as it's very bad style.

Varriount commented 3 years ago

Might it be better to throw an error instead? I can't see this being all that useful, and it would be easy to accidentally do if you were refactoring code, and happened to change procedure return types.

timotheecour commented 3 years ago

IMO it should either be an error, or be equivalent to:

let c = foo()
let b = c
let a = b
saem commented 3 years ago

Quoting the manual:

Order of evaluation is strictly left-to-right, inside-out as it is typical for most others imperative programming languages

a, b, and, c are all siblings, they should go left-to-right, and the RHS applies to each individually.

Nim's imperative heritage means it should be in the order as written, unspecified, but not backwards. Assignment is presently distributive at the symbolic/expression level, not at time of evaluation thus far. Also, I'm pretty sure assignment in Nim is not an expression -- var a = 1 is void, not int.

It needs to be:

let a = foo()
let b = foo()
let c = foo()

If anything tuple destructuring further drives the point home, as it evaluates and assigns to one thing which happens to destructure.

This would be an issue if one returned an isolate or a reference, either under successive assignment would be surprising.