4 ms·
But in this it is not. let _tmp = Foo; The confusing bit is renaming the object from _tmp to _ changes the rules. I assume that in rust '_' is not an act
by gpderetta 2y ago
But in this it is not.
let _tmp = Foo;
The confusing bit is renaming the object from _tmp to _ changes the rules. I assume that in rust '_' is not an actual name, but a pattern to be matched, but even that the actual rule applied is not obvious (does it match everything? Only the lifetime of objects matched with a name is extended?)
- steveklabnik 2y agoCorrect, _ is a pattern that does not bind to any name. While the implications of that may not be simple, the description certainly is. Names that start with underscores are still names, and work like any other name. The “unused variable” into can be suppressed with a leading underscore like any other name, but that’s purely about the lint and not semantics.
- gpderetta 2y agoSo the issue really is that the match-and-discard wildcard uses a spelling that would otherwise be a valid identifier name causing an ambiguity to the reader, if not to the compiler. In retrospect using a different character (say '*') would have been better, clueing the reader that something different was happening; but I guess there is long history of this use of _ in ML languages.
- steveklabnik 2y agoI mean, it’s never a valid identifier, and that is spelled out in the reference too.
- gpderetta 2y agoof course it isn't, it acts as a keyword, but it looks like a valid identifier. As this difference doesn't matter 99% of the time, it can be be easily overlooked, becoming a pitfall the 1% that matters. Of course it too late to change it, but pointing it is a must. I understand rust has a linter pass specifically to catch this sort of issues.
- kazinator 2y agoI independently came up with a similar hack in TXR Lisp. When a variable is named by a gensym, unused warnings are suppressed. Gensyms are almost always symbols generated by macros. Machine generated code often has cases where variables are unused. This design decision is a trade off. Any situation in which a variable is unused is potentially a bug, even if the variable is in code written by a macro and named by a generated symbol. But it is a burden on macro writers to ensure that all possible cases of general code are free of unused variable warnings.
- jmyeet 2y agoThose are two different things. - A _ prefix tells the compiler not to warn you a variable isn't used. - A _ variable name is a reserved symbol to say something cannot be used. Trying to do so will cause a compiler error. So they're scoped differently. Consider this Go snippet: func A() { fmt.Println("A") } func B() { fmt.Println("B") } func main() { var B = A; B() } What function gets called? It's A but you can reasonably make a case for B given the capitalization of Go function names and variables. My point is that scoping and resolution rules and many other aspects of a language can be viewed as intuitive (or not) based simply on what you're used to. Even then they can be arbitrary.
- gpderetta 2y agoIn a language where functions are in the same namespace as variables (like the majority of languages), I would expect A, in a lisp-2 I would expect B. But I don't see how's that relevant, this is not about the scope of bindings, but about the lifetime of objects. As Steve explained in a sibling comment, _ is in fact not a variable name, and doesn't extend the lifetime of the object. The semantic is perfectly reasonable and I'm sure it has a good reason to be that way, but the difference between two similarly looking syntaxes is surprising and violates the principle of least astonishment. FWIW, C++ temporary lifetime extensions are also surprising in many cases. [Note: I don't know if rust is defined in term of temporary lifetime extensions, it is just a way to understand it for a c++ programmer like me]
- steveklabnik 2y agoThe definitions are a bit different than in C++ but the overall effect is the same: https://doc.rust-lang.org/stable/reference/expressions.html#temporaries https://doc.rust-lang.org/stable/reference/expressions.html#...
- kazinator 2y agoIf B is called, and the language is otherwise reasonable, then it must mean that there's an A variable in the program which is not showin in the above code. The language must have separate namespaces for functions and variables. But in that case var B = A must be resolving A in the variable namespace; it does not refer to the function A. The local B variable is initialized from some nonlocal A variable, and neither of those are related to the A or B functions, nor have any interaction with the B () call which ignores the variable space, looking up in the function space.