Live data from Hacker News

Weird Expressions in Rust

wakunguma.com

41–50 of 155 posts

Re: Weird Expressions in Rust

#41
post #11
post #10

Earlier quoted context omitted.

What's the joke exactly? English is not my native language.

https://www.basicfun.com/lincoln-logs/ This would be something the Boomer generation grew up with, and I think maybe the previous generation too. They're still around but they've certainly faded; they used to be Lego-level popular kids toys back then. They are named after President Lincoln, but only as a marketing tactic to use some of his reputation, there's no real connection. I would imagine even some native Engli…

> They were named after President Lincoln, but only as a marketing tactic

> there's no real connection

Funny--I always thought it was meant to be a pun on linkin', as in you're linkin' the logs together because they have those slots that fit precisely together on the ends.

Re: Weird Expressions in Rust

#42
post #32
post #5

they exist because whole language built to treat expressions as firstclass citizens : blocks, ifs, matches, even macros as expressions that return values. so once you internalize that, all these weirdo one liners are artifacts. just artifact of a system where expressions compose infinitely. the syntax tree runs deeper than most people's habbits allow. you hit that depth and brain says this is wrong but compiler's all…

That sounds superficially reasonable to me and I'm all for regularity in programming language semantics but on thinking about it further, I actually think it's a design flaw. It makes no more sense to me for "return " to have a type than it does to make "if " or "break" or "{" or any other keyword to have a type. These are syntactic elements. Rust's type system is clearly inspired by Hindley-Milner and most languages…

it doesn't need to make sense on a higher abstraction level of logic/semantics

I mean you don't see any of the nonsense in the blog post in any realistic PR (so they don't matter),

but you would run into subtle edge case issues if some expressions where more special then other expressions (so that does matter),

especially in context of macros/proc macros or partial "in-progress" code changes (which is also why `use` allows some "strange" {-brace usage or why a lot of things allow optional trailing `,` all of that makes auto code gen simpler).

Re: Weird Expressions in Rust

#43
post #25
post #5

they exist because whole language built to treat expressions as firstclass citizens : blocks, ifs, matches, even macros as expressions that return values. so once you internalize that, all these weirdo one liners are artifacts. just artifact of a system where expressions compose infinitely. the syntax tree runs deeper than most people's habbits allow. you hit that depth and brain says this is wrong but compiler's all…

If a language that claims to be security focused is easily able to express constructs that human minds find barely comprehensible, or worse, then this is itself arguably a security issue: it's impossible to check the correctness of logic that is incomprehensible.

What's the threat model? If you're reviewing untrusted or security-critical code and it's incomprehensible, for any reason, then it's a reject.

Syntax alone can't stop sufficiently determined fools. Lisp has famously simple syntax, but can easily be written in an incomprehensible way. Assembly languages have very restrictive syntax, but that doesn't make them easy to comprehend.

Rust already has a pretty strong type system and tons of lints that stop more bad programs than many other languages.

Re: Weird Expressions in Rust

#44
post #9
post #4

Note that for Rust devs these are also weird syntaxes. I feel like some people assume that an experienced dev can read these, but it takes a while to get what's going on.

Kind of like obfuscated C code I suspect.

yes, but less risky (and less power full) because you often very fast can conclude that "whatever it does it's safe, sound and doesn't affect unrelated code"

Re: Weird Expressions in Rust

#45
post #15

Why assigning a variable to a function that returns nothing is not a compilation error?

Do you mean a function which returns "nothing" in the sense that it does return but it has no particular value to return, like Vec::clear which gets rid of the values but preserves the capacity of the container ?

In Rust the return type of this function is the unit type, the empty tuple (). So, the variable has this type, there's no problem with this in Rust, even though some lesser languages can't handle the idea of a type this small.

Or did you mean a function which never returns, like std::process::exit ? In Rust this function's return type is ! the Never type, an empty type that you ordinarily can't name in stable Rust.

Because this type is empty, a variable of this type will evaporate, the compiler knows that we can't bring values into existence if there are no values of that type, the code paths in which this variable exists will never be executed, so no need to emit machine code.

In a language with generic programming like Rust this isn't an error, it's actually a convenience. We can write generic error handling code, and then for cases where there will never be an error our error handling code doesn't even compile, it evaporates entirely, yet for cases which can have actual errors, the error handling code is emitted.

Re: Weird Expressions in Rust

#46
post #32
post #5

they exist because whole language built to treat expressions as firstclass citizens : blocks, ifs, matches, even macros as expressions that return values. so once you internalize that, all these weirdo one liners are artifacts. just artifact of a system where expressions compose infinitely. the syntax tree runs deeper than most people's habbits allow. you hit that depth and brain says this is wrong but compiler's all…

That sounds superficially reasonable to me and I'm all for regularity in programming language semantics but on thinking about it further, I actually think it's a design flaw. It makes no more sense to me for "return " to have a type than it does to make "if " or "break" or "{" or any other keyword to have a type. These are syntactic elements. Rust's type system is clearly inspired by Hindley-Milner and most languages…

This makes the language more uniform. Instead of having a special ternary ?: operator for if-else in expression position, you have one syntax everywhere.

It makes generic code work without need to add exceptions for "syntactic elements". You can have methods like `map(callback)` that take a generic `fn() -> T` and pass through `T`. This can work uniformly for functions that do return values as well as for functions that just have `return;`. Having nothingness as a real type makes it just work using one set of rules for types, rather than having rules for real types plus exceptions for "syntactic elements".

Re: Weird Expressions in Rust

#47
post #5

they exist because whole language built to treat expressions as firstclass citizens : blocks, ifs, matches, even macros as expressions that return values. so once you internalize that, all these weirdo one liners are artifacts. just artifact of a system where expressions compose infinitely. the syntax tree runs deeper than most people's habbits allow. you hit that depth and brain says this is wrong but compiler's all…

Hmm my read is this is a slight overstatement - Rust was always built with the idea of expressions as first class citizens, but practicality and performance requires expression-breaking keywords like “return” which don’t fit neatly in an ML-ish language and have a few plain old hacks associated with implementing them (not “hack” as in lacking robustness; I mean theoretically/formally inelegant). Likewise there’s some stuff (u8) which is a simple syntax quirk. But a lot of these return/etc oddities are because Rust is ultimately an imperative language with strong influence from functional programming.

Re: Weird Expressions in Rust

#48
I figured out how return-as-a-value made sense only upon realizing that in the following code,

    fn funny(){
        fn f(_x: ()){}
        f(return);
    }
f() is never called because funny() returns before it gets called.

The reason you want return to be coercible to any type is so that you can write something like

    let x: i32 = if y {
        4
    } else {
        return; // type ! coerced into i32
    }
And you pick the return value of ! because return never actually produces a value that is propagated on at runtime, it immediately exits the function.

(Note this all works even with returning a value)

Re: Weird Expressions in Rust

#49
post #15

Why assigning a variable to a function that returns nothing is not a compilation error?

assuming you mean returning () (the empty tuple/void type)

because it doesn't compose well with generics, macros, proc-macros etc.

e.g. if you have this dump way to wrap clone: `fn foo(v: T) -> (T, T) { let new = v.clone(); (v, new) }` it would implicitly not work with T = (), because then `v.clone()` would be a "function which returns nothing".

In isolation this might seem fine but if you compose abstractions you sooner or later run into an edge case where it isn't fine.

And this becomes even more a problem when macros/proc-macros are involved.

It also makes changing code easier, lets say you have something like `let x = foo(); dbg!(x);` and you change the return type it will keep compiling as long as the type implements `Debug`, even if you change the type to `()` (i.e. return nothing). And again for normal code that is a minor nit pick, but for macros, proc macros, generic code of sufficient complexity sooner or later you run into edge cases where it really matters that it's allowed. Not often but often enough.

Lastly and most importantly assigning `()` to a variable hurts no one, you won't see any such code in normal PRs.

So it it doesn't hurt anyone but can be quite use full in edge cases.

Lastly linters (mainly clippy) do warn or error for some of this nonsensical things, depending on the lint-set you enabled.

Re: Weird Expressions in Rust

#50
Many of them are on the same theme - the theme is `return -> !`.

Here's my favourite on that theme, which I was missing from the list:

    return return return return return return return return return 1
Post reply on HN