Try fn + try {...} chat... (CLOSED)

Newcomer, you may want to skip this thread. Its idea was based on an untenable thesis. Thanks for the feedback!


Ok/Err wrapping is the number one benefit of try fn. You can easily return both success values and failures without conversions or wrapping.

Now, with rfc #1624 in stable Rust we can break loops with a value - without the need of labels.

let foo = loop {
    break v;
};

Would it not be possible to make try {...} blocks similar to loop {...} blocks in this regard but also do automatic wrapping? You may then exit a try block by means of the ? operator, early exiting with break (success or failure), or by just ending the block with a success value.

try fns can be early returned from in the same manner.


What makes this design better?

  • No need for throw/fail keywords: return/break have your back.
  • Early success exits from try blocks are possible. Just use break.
  • The try block/fn just introduces the fallibility semantics to the block or function, and makes the idea of errors (already present with the ? operator) a more pivotal notion in Rust, without much feature baggage.

Go ahead, shoot me down!

2 Likes

This is rather unclear. What does try { ... break x ... } mean? Is x unconditionally Ok-wrapped? If so, how do you early-exit with an error? How and where does error conversion happen?

3 Likes

Err(e)? works, though I think it would be better to at least have a macro throw!(e) if not an actual keyword.

Invariant Ok wrapping on break would make sense. If the tail expression is Ok wrapped, then break, as an alternative exit point for the block, should match.

Yes, that was certainly a bit vague. I guess I wanted to begin the discussion at a low resolution.

I have no real solution to the auto-wrapping yet. The success variant and the error variant would have to be distinct, and the type of the block/fn (or closure) would have to be determined.

Early return from the block sounds like a nice to have, but repurposing of the keyword may be confusing:

for i in foo {
    let x = try {
       break y;
    };
}
1 Like

I think having break e; be equivalent of return Err(e); (if I understood your proposal correctly) will be quite confusing, thus separate throw/fail keyword with Ok wrapping for try fn returns will be a much better solution.

1 Like

break e; would be equivalent to Err(e)? if e is an error. It could also be a success value.

return e; is required to exit a fn early. With an error or a success value.

Well, it will be even more confusing. What do you expect to happen on break "foo"; if function returns Result<&str, &str>?

1 Like

Maybe confusing, or maybe not more confusing than in the case of nested loops?

As the innermost block that can break with value try would have precedence over loops outside.

Firstly, a return would have to be used to exit a fn. As for the auto-wrapping ambiguity, I have no solution I’m afraid, except for forbidding equal variants. Any idea?

Not using brake like this in the first place? :wink: See my previous proposal on this topic: one, two.

@newpavlov

I see that I even liked that first post of yours. :blush:

This is valid critique though an a serious issue that I don’t have a good answer for. I honestly hoped that someone else would come along and do all the hard thinking once I kicked this off. :wink:

Since this topic is interesting; let’s continue it anyways and discuss other solutions?

One thing you could do inside try { .. } is to let return expr be Ok-wrapping and return to the block and not the function. As always, re-purposing return this way may lead to some confusion for people since there’s an expectation that return always returns from the function.

However, try fn, which I’m in favor of, would not have that pedagogical problem wrt. return. But it would be nice for try fn and try { .. } to be more in sync.

1 Like