Initialize a variable, otherwise return None (easy way)

I would like to initialize a variable under certain conditions, otherwise return None. For example:

fn my_func(text: &str) -> Option<()> {
    let s = "Lorem ipsum";
    let len = if text.starts_with(s) { Some(s.len()) } else { None }?;

    // .. snip ..

    Some(())
}

The previous code works perfectly, but I would like to find a shorter way to write it. Something like this:

let len = if!(text.starts_with(s)).then(s.len())?;

I'd like to eliminate all identifiers. They make languages boring.
It isn't a good idea to make your own when everyone else knows and expect to be reading standard code.

There are a few characters you can trim.

let len = if text.starts_with(s) { s.len() } else { None? };

Or functional. (not a fan.)

let len = Some(s.len()).filter(|_| text.starts_with(s))?;
4 Likes

Simple and obvious.

if !text.starts_with(s) {
    return None;
}
let len = s.len();

I'm not sure why you want the s.len() to be in a branch of the if anyway. You're doing early return either way. The above is how I would write it.

7 Likes

Nightly Rust has the experimental bool::then method:

let len = text.starts_with(s).then(s.len())?;
14 Likes

I knew it! I think this is a necessary feature to write concise code.

The if is imo much more readable.

9 Likes

Yes, but this is a very common situation and Rust is characterized to be "concise". The other solution is more like a "GOLANG solution".

I think semantically an ? should be thought of as an unwrap, and I don't think using it on bools corresponds to an unwrap at all, which is why I don't like it.

2 Likes

A agree. I don't understand the modern obsession with doing away with the age old structured programming "if', "then", "else", "while", etc.and squishing everything down to the shortest possible one liner using obscure replacement words for those things.

I'm not sold on the idea that brevity aids clarity and expressiveness,

Is there actually any practical benefit to all this?

5 Likes

I mean, the if in question might be similar to an if used for error handling, which is probably why it is compared to go, but we aren't actually handling an error here.

Coupling it to the len call semantically says the length might fail, but it would also be valid to put the check on some other variable without changing the behavior.

This is not a failure arising from computing the length, so the error shouldn't be thrown from the length computation.

6 Likes

I would not even make it a one-liner at all.

if !text.starts_with(s) {
    return None;
}
let len = s.len();

might be longer, but is understandable 10x as fast. (and it's only about 15 characters longer)

4 Likes

I have been happy with the ternop crate:

let len = ternary!(text.starts_with(s), Some(s.len()), None);

There is also a trick that is sometimes used in scala (sorry this was already mentioned but I actually like it):

let len = Some(s.len()).filter(|_| text.starts_with(s));

I cannot fathom why anybody would want to spell "if" as "ternary!" or "filter" and then hide the control flow in a function call. What is the reason for desiring this obscurity?

12 Likes

It saves you having to write redundant code. For example, the "?" operator is normally used in functions that return Option or Result. You can write in a single line a "trivial and common" concept. I like it :slight_smile:

1 Like

I agree that it is not so maintainable for developers new to a codebase, but if people are used to these shortcuts they are not obscure.

I mainly use tenary!() to save vertical space.

As always, things are judgement calls. One could even consider if itself an "obscure replacement word" for match { true => ..., false => ... }, at some level.

When does something become well-known enough to avoid such feelings? I don't know. Write the code however you (and your project's coding conventions) think is best.

3 Likes

I don't know.

All of programming is nothing but "sequence, selection and iteration". Since my first introduction to programming with BASIC in 1974 that was done with "if" and "for" and similar constructs. Having used ALGOL, PL/M, Ada, Pascal, Lucol, C, C++, Java, Javascript, and more since then Rust is the first language I have seen that had the conceptually more complex "match".

However "match" not what I'm questioning here. Nobody had mentioned "match" until you did.

1 Like

This post was flagged by the community and is temporarily hidden.

5 Likes

let len = if text.starts_with(s) { Some(s.len()) } else { None };

is about equally long. I wouldn't introduce anything new only to save 3 characters. Rust already is a very complex language.

4 Likes

This post was flagged by the community and is temporarily hidden.

3 Likes