`'a` is a label for a memory area, like goto labels in C but for data. You can read it as (memory) pool A. Roughly, when function entered, memory pool is created, then destroyed at exit.
`'static` is special label for static data (embedded constants).
`()` is nothing, like void in C.
`&()` is an reference to nothing (an address) like `void const *` in C.
`&&()` is an reference to reference to nothing, like `void const * const *` in C.
`& 'static & 'static ()` is like void `const * const *` to a built-in data in C.
`& 'a & 'b ()` tells compiler that second reference is stored in pool 'a, while data is stored in pool 'b. (First reference is in scope of current function.)
`_` is a special prefix for variables to instruct compiler to ignore warning about unused variable. Just `_` is a valid variable name too.
static UNIT: &'static &'static () = &&();
fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v }
Let's say that `&'a` is from a function `a()`, while `&'b` is from a function `b()`, which called from the function `a()`.The trick here is that we relabel reference from pool `'b`, from an inner function, to pool `'a` from outer function, so when program will exit from function `b()`, compiler will destroy memory pool `'b`, but will keep reference to data inside until end of the function `a()`.
This should not be allowed.
I guess stated another way, I don't generally have issues reading code from a wide swath of languages. If someone plopped me in front of a rust codebase I'd be at the mercy of the manual for quite a long time.
Thank you again, sincerely.
& is used for references in a lot of languages.
() is a tuple, same syntax as Python
'a isn't even novel: it was taken from OCaml, which uses it for generic types. Lifetimes are generic types in Rust, so even though it's not for an identical thing, it's related enough to be similar.
_ to ignore a name for something has a long tradition in programming, sometimes purely as a style thing (like _identifier or __identifier), but sometimes supported by the language.
fn name(args) -> {} as function syntax is not SUPER unusual. The overall shape is normal, though the choice between "fn," "fun," "func," or "function" varies between languages. The -> comes from languages like Haskell.
<> for generics is hotly debated, but certainly common among a variety of langauges.
the "static name: type = value;" (with let instead of static too) syntax is becoming increasingly normalized, thanks to how it plays with type inference, but has a long history before Rust.
So this leads to a very interesting thing, where like, it's not so much that Rust's syntax is entirely alien in the context of programming language syntax, but can feel that way unless you've used a lot of things in various places. And that also doesn't necessarily mean that just because it's influenced from many places that this means it is coherent. I think it does pretty good, but also, I'd refine some things if I were making a new language.
Which parts would you change?
I do think there's some good criticism of doing this, though, and so even a year later it's not clear to me it's a pure win.
I am sympathetic to the vague calls to action by Aria et al. to improve the syntax for various unsafe features. I understand why we ended up where we ended up but I think overall it was a mistake. I am not sure I agree with her specific proposals but I do agree with the general thrust of "this was the wrong place to provide syntactic salt." (my words, not hers, to be clear)
Ideally `as` wouldn't be a thing. Same deal, this is just one of those things that's the way it is due to history, but if we're ignoring all that, would be better to just not have it.
I am still undecided in the : vs = debate for structs.
I am sad that anonymous lifetimes in structs died six years ago, I think that would be a massive help.
Probably tons of other small things. Given the context and history, I think the Rust Project did a great job. All of this is very minor.
The = on functions idea is particularly interesting by comparison with Scala, which has shifted towards requiring = over time.
Therefore, it ends up being a really huge thing, with lots of design space. This is combined with the fact that
> they would also provide an easy, unambiguous way to "overload" functions
Not everyone sees this as a good thing.
Being slightly controversial, plus being really large, plus there being a lot of other things to do, would make me surprised if they ever land.
Here's a link from eight years ago with a link to lots of other related proposals: https://internals.rust-lang.org/t/pre-rfc-named-arguments/38...
In particular, explicit use of lifetimes tends to be seen as somewhat more of a last resort, although the language requires it more frequently than I like. Furthermore, the soupiest of the syntax requires the use of multiple layers of indirection for references, which itself tends to be a bit of a code smell (just like how in C/C++, T * tends to be somewhat rare).
The real question what is the use of Rust for you. Do you work on anything where Rust could be a value?
This is not a representative sample of Rust. That's explicitly triggering edge cases which requires abuse of syntax you wouldn't normally see.
Check out this for something more realistic that anyone should understand https://github.com/ratatui-org/ratatui/blob/main/examples/ca...
And even if not, this example isn’t particularly hard to decompose and understand once you have a basic grasp of the independent underlying bits (generics, lifetimes, borrows). It’s just combining all of them pathologically into an extremely terse minimal reproduction.
It’s like saying you could never understand Java because someone linked to an AbstractClientProxyFactoryFactoryFactoryBean.
Just because "int ((foo)(void ))[3]" is a valid C declaration doesn't mean that all of C code looks like that.
C++ has the same level of fuckery without memory safety. I don't think there is an extreme level of fuckery in Rust. I wish they got more influence from the ML languages than C++ but it is not unbearable.
(Have you ever looked at a fuzzer-generated failing piece of data and not though "oh whoa good point". That's interesting!)
[,{a,'z':q|0}[`${a?.x??b}`]]- https://github.com/pkolaczk/latte/blob/main/src/main.rs
- https://github.com/pkolaczk/latte/blob/main/src/exec.rs
There was one fundamental "aha" moment for me when it clicked: move semantics. Once I learned it, suddenly 99% of stuff became simple (including making async quite nice really, contrary to popular HN beliefs).
I would also generally agree that a single pass through the official book should mostly be enough to be able to read and understand the op.
I’ve written at least two other non-toy Rust programs and I haven’t hit “lifetimes everywhere” problem there either. I guess the most lifetime related problems stem from trying to program the Java/Python/JS style in Rust - from overusing references and indirection. If you model your program as a graph of objects referencing each other then I can imagine you have a hard time in Rust.
I mean, a read through the guide makes this very readable, but it doesn’t change that it looks like symbol soup and have lots of awkward repetitive strain to type it out.
I have a custom layout on my keyboards which makes each symbol reachable without moving my hands, which made it a lot more pleasant.