Can be 'if' on the left side in Rust?

Usually I use 'if' on the right side of expressions, for example:

let exp = if some_cont {c} else {d};

It works great, but sometimes you need something different, for example:

trait Oper {
    fn plus(&mut self, val: i32);
    fn minus(&mut self, val: i32);
}
struct Val {
    it: i32,
}

impl Oper for Val {
    fn plus(&mut self, val: i32) {
        self.it += val
    }
    fn minus(&mut self, val: i32) {
        self.it -= val
    }
}
fn main() {
    let mut v = Val { it: 4 };
    let cond = 7;
    v. if cond < 5 {plus(5)} else {minus(3)};
    println!("result {}", v.it)
}

I want to select a called function by a condition, but Rust tells:

error: expected identifier, found keyword `if`
  --> /media/exhdd/Dev/modu/oper/oper.rs:20:8
   |
20 |     v. if cond < 5 {plus(5)} else {minus(3)};
   |        ^^ expected identifier, found keyword

error: expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `cond`
  --> /media/exhdd/Dev/modu/oper/oper.rs:20:11
   |
20 |     v. if cond < 5 {plus(5)} else {minus(3)};
   |           ^^^^ expected one of 7 possible tokens

error: aborting due to 2 previous errors

You may say - why is it so strange request?, it can be done like:

trait Oper {
    fn plus(&mut self, val: i32);
    fn minus(&mut self, val: i32);
}
struct Val {
    it: i32,
}

impl Oper for Val {
    fn plus(&mut self, val: i32) {
        self.it += val
    }
    fn minus(&mut self, val: i32) {
        self.it -= val
    }
}
fn main() {
    let mut v = Val { it: 4 };
    let cond = 7;
    if cond < 5 {
        v.plus(5)
    } else {
        v.minus(3)
    };
    println!("result {}", v.it)
}

But sometimes, v is calculated by a quite complex expression and I do not want to duplicate it in both branches if the 'if'. What are my other options in the case? Calculate v, store it and then apply 'if', right?

Essentially, yes. There is no construct like v. if cond < 5 {plus(5)} else {minus(3)}; that you tried; frankly I'm unaware of any language that has that sort of thing.

I'm not sure if this is exactly what you're looking for, but you can always pull out the method to be called conditionally and apply it so long as they share the same signature. Like:

fn main() {
    let mut v = Val { it: 4 };
    let cond = 7;
    let op = if cond < 5 {
        Val::plus
    } else {
        Val::minus
    };
    op(&mut v, 5);
    println!("result {}", v.it)
}

It's often cleaner to assign complex temporaries than it is to immediately chain method calls to the end of them anyway, IMO.

But here's one very generic way to sort-of replicate what you asked about.

// Probably there's a better name than this.
trait WithMut {
    fn with_mut<'s, R, F>(&'s mut self, mut f: F) -> R 
    where
        F: FnMut(&'s mut Self) -> R,
    {
        f(self)
    }
}

impl<T: ?Sized> WithMut for T {}

Usage:

    v.with_mut(|v| if cond < 5 { v.plus(5) } else { v.minus(3) });

yeah, that's the simple and obvious solution.

what's the non-simple or non-obvious version? well, there are plenty.

first of all, you can make custom syntax with macros, but you might need to adjust the syntax a bit for easier macro parsing, because certain tokens are not allowed to follow some types of macro catprues. especially for the $v:expr metavatiable, none of . and { are not allowed to follow an expr fragment, only ,, ;, and => are allowed.

here's an example with adjusted syntax (playground):

    xx! {
        v; if cond < 5 => plus(5) else => minus(3)
    };

another option is to tap it, or pipe it:

    v.pipe_ref_mut(|v| if cond < 5 {
        v.plus(5)
    } else {
        v.minus(3)
    });

and here's the least "obvious" (and most obnoxious) approach combining pipe and partial function application (playground):

    v.pipe_ref_mut(if cond < 5 {
        bind_2nd(Val::plus, 5)
    } else {
        bind_2nd(Val::minus, 3)
    });

It's an interesting approach. Could you a bit elaborate if I need to call more than one function, but a chain of them, similarly to a builder. For example I want to execute one set of build operations at one condition and other at another condition?

Generally, it is another question and you answered it. I liked Kotlin's with directive when you can do a set of operations with a certain structure.

I had never thought of it or seen it. At first look it was nonsense. After reading a few times, I wonder why it doesn't just work.

FYI languages with partial application and a pipeline operator do support something like this. Mostly ML-style languages like elm, F#, haskell etc. (and I believe concatenative languages)

v |> (if cond < 5 then plus 5 else minus 3)

(Also, I agree that a let v = ... followed by full application is more clear)

in languages where functions are first class types, it's very simple with partial application. bonus if the language support some form of syntax extensions, like macros in lisps, and custom operators in haskell.

for example, I think the cond-> macro in Clojure is very close to what OP wants (except it does not short circuit, so the condition needs to be repeated for an if-else branch). the hypothetical (invalide) rust code in OP can roughtly translate to:

(cond->  v
    (< cond 5) (Val.plus 5)
    (not (< cond 5)) (Val.minus 3))

you can use the fn() type;

let f:fn(Args)->Out=if condition{
      |args|{//code
       }
}else{
        |args|{//code
         }
};

let out=(f)(args)

this will work as long as the two closures do not capture anything if they do you need something like this or use a box dyn if you want to only create the closure that's needed

let closure1=|args|{//code
                     };
let closure2=|args|{//code
                     };
let f: &dyn Fn(Args)->Out=if condition{
       &closure1
}else{
       &closure2
}

let out=(f)(args)