Suffix conditionals

I would really love if it I could use perl-like ifs:

println!("cool") if cool;

or

println!("working") unless done;

and ternary operator:

let x = done ? 0 : 1;

these forms of expression are more terse and natural than the way we currently have to express them, for example:

let x = if done { 0 } else { 1 };

is just sadly clumsy. also loops could benefit from:

do {
   println!("working");
} until done;

https://lang-team.rust-lang.org/frequently-requested-changes.html#suffix-modifiers-if-after-returnbreakcontinue-or-after-arbitrary-statements

17 Likes
3 Likes

Such a change would prioritize concise code over readable code

this is a bogus argument. quit if done is perfectly readable and it's how we we would write things in English i.e. it's natural

We don't want people to start out thinking they're reading an unconditional return statement, and only later see the if and realize it's a conditional return

another bogus argument. you either read the code or you don't. if you read only selective portions of the code you can't expect to understand it

you don't need to remove the previous notation. for those that prefer the syntax they can have it, but for us for whom ternary (since the days of C) is familiar, it's easier to read. as for ambiguity, there isn't any because it's contextual. ? is not the same as ?:

Both "if done, quit" and "quit if done" are valid English. Rust isn't English. Rust strives for minimal ambiguity, and for reading things in evaluation order whenever possible (avoiding things like Garden-path sentence - Wikipedia ). Rust shouldn't have constructs that start out looking like one thing and end up looking like another once you get to the end. Rust shouldn't have constructs that have non-obvious evaluation order.

Some human languages say "things are subject-object-verb", some say "things are subject-verb-object", some say "things are verb-subject-object", and in those languages, it's typically viewed as incorrect or at least non-standard to do it in a different order. Well, Rust (wherever possible) is an "in evaluation order" language.

quit() if done is relatively readable, though I'd argue not any more so than if done { quit() }, and it's still not standard for Rust that the thing that comes second is evaluated first and the thing that comes first might not be evaluated at all. But the bigger problem comes in when that line becomes:

long_function_name(some, arguments)
    .chained_call(more::stuff())?
    .build().await?
    .send_request().await?
    .parse_response().await?
    if long_conditional();

It isn't obvious at a glance (in particular, in reading order) that all that code is 1) conditional and 2) not evaluated at all until the conditional is run.

14 Likes

There is a linked post which asks how foo() ? - bar() ? -1 : 2 should be parsed. Rust's grammar has a goal of not requiring infinite lookahead (or knowing the return types of foo() or bar()), so how should one decide when encountering - bar() without knowing : is coming how that ? is intended to be parsed. That is an ambiguity and won't go anywhere.

Additionally, Rust is its own language; arguments of "but lang X does/has it" is not very convincing; it has to be good for Rust as it is.

I also remember posting about unless somewhere else (this request has come up before) and how modus ponens'ing conditionals just gets one's mind in a twist, but I can't find it. So even if we do get this, I would be very sad to see unless adopted.

11 Likes