I meant this can happen even within a crate. Into
is such an extremely vague and general purpose trait. A lot of people use Into
in their own crates for their own random reasons. Some of these people might also want to use or
on an overlapping set of types.
Believe me that there's a difference between âa tree is for decorationg a yardâ and âa tree is for chopping down to get woodâ, and that difference is not only a moral/fundamental purpose but also a practical purpose. Because of that we cultivate a different kinds of trees instead of e.g. apples that can serve as a yard decoration, bear some fruits, and we can chop them down on requirement.
But what if you works as a painter and opens multiple cans of paint per day with an edgy handle of a brush? Would you search for a better tool instead?
And what argument could be considered as convincing?
Because there is a tendency that each operator in a language has it's own trait, and we breaking it while users expect it to keep forward.
It's really easy to get lost in terminology here e.g. your example of null
handling defines a temporary variable and assignment inside of if
expression - is that imperative?
Or another example if a { b() } else { c(); }
, is a this expression before semicolon imperative? Could if
expression be also imperative because of it?
Again, it don't has a good and ergonomic syntax for simple use cases, and it can't do type inference based on From
trait.
Or another example
if a { b() } else { c(); }
, is a this expression before semicolon imperative? Couldif
expression be also imperative because of it?
if a { b() } else { c(); }
has two cases
b
returns()
- the if evaluates to
()
- the if evaluates to
b
does not return()
- compile time error because the two branches of the if evaluate to different types
any expression followed by a semicolon will always evaluate to ()
.
it canât do type inference based on
From
trait.
On the note of type inference, it is very hard to do type inference on such a generic trait, and calling From::from
can be rather expensive, so I would like for it to be visible.
I think Rust is not a Swiss army knife: if you are looking for a better tool that does not fit in Rust, why not just look for another tool set that have the tool you need?
For example, I believe procedure macro will let you define your own embedded DSL. You might probably write a subset of Rust with your specific language extension. If this makes you happy, so do most of us and don't forget to let me know your new tool
I fail to see the adequate motivation for either a coalesce or âtheâ ternary operation.
Could you explicitly spell out how a or b
is better than a.or_else(|| b)
/a.unwrap_or_else(b)
(based on type information)? (FWIW, I was unaware about this âchainingâ behavior from Kotlinâs ?:
.)
Could you explicitly spell out how c && a or b
is better than if c { a } else { b }
? Note that Python specifically chose to use a if c else b
because ternary operators are a hard sell.
Alongside this Iâd like to pose a challenge that could help motivate this pre-RFC. Provide a real-enough example (at a glance it looks like itâs doing a real computation, not using dummy names) in âcurrent rustâ and âwith this RFCâ styles, and argue why the latter is more understandable with local reasoning to a reader than the former. The people against the RFC can then propose a âcurrent rustâ formulation thatâs another way of attacking the problem, potentially better, and we can incrementally find the âbestâ representation both with and without this RFC for comparison.
No, it doesn't. I don't know where you think that happens.
But expression by itself could be imperative, since it could change a state as well as it could contain other expressions that could do the same. Return type really don't matter here.
Wouldn't it be inlined or optimised in any different way?
This is exactly what I'm trying do in this thread
I'm doubt that this tool would be better than tool I use currently
Overall, it's very good idea to a start more deep research and provide a better examples. That should be done early, but I've just assumed that not only I understand the problem and some examples and alternative proposals (different from "you can already do that with") would arrive ITT.
So, I start searching for a real world examples.
In destructuring
The return type of the function b
does matter, as it makes the difference of compiling, and not compiling.
Who would the compiler figure out what you want? It's not a problem of codegen, it's figuring out what the programmer wants.
Also, the optimizer is not a magic bullet, it can't optimize away everything, and From::from
calls can also to be expensive due to allocations, for example String::from(&str)
needs to perform an allocation, and therefore is expensive, and the optimizer cannot optimize that out. Finally, relying on an optimizer to get expected behavior is bad, as even slight changes have drastic, often unpredictable, effects.
Could you please, elaborate especially on the note of if let
. I think that if let
construct is perfect for handling nullable values. Also we have the Try operator ?
, which is useful when in functions that return Result
or Option
. When try
blocks land, this will be even easier.
So, I don't see the point you are trying to make.
That's right, but that's also not subject of the discussion. My thesis is that return type of ()
turns a returning expression into imperative statement, since ()
represents void
. And even if void
is a value, it's hard to say that it's a result, since it's useless.
It would know a concrete type I want.
Consider the following code:
option or Err(0);
It would be desugared:
match Or::into_option(option) {
Some(o) => From::from(o),
None => Err(0),
}
And then inlined:
match option {
Some(o) => Ok(o),
None => Err(0)
}
Or did you wanted to say that this couldn't happen?
That's good point. I think that some trait bound on Or
type parameter would be required to deny values that allocates in from
function. Or we can use another trait instead.
That requires further investigation...
Sometimes you need a more straightforward way to handle nullable values: option or value
, option or next_option
, option or result
...
Handling nullable values in if
and match
expressions is less straightforward than could be with or
.
Handling nullable with Option<T>
combinators is less straightforward than with if
and match
.
Handling null
as error using ?
and try
blocks is not straightforward at all.
Minor nit, there are no From
impls for Result
Option::unwrap_or
Option::or
and Option::or_else
Convert the result to an option with Result::ok
and then use one of the above methods.
I don't see why these are so bad.
Imagine that you are complete newcomer in Rust: how you would deal with all of that methods?
And from user perspective: what is the advantage of having multiple ways to do the same thing?
When I was a complete newcomer to Rust, I dealt with all of those methods by learning what they do and using them.
And from user perspective: what is the advantage of having multiple ways to do the same thing?
There are advantages and disadvantages to it, and it depends on what you mean by 'same' and 'multiple' and other matters of context. In general, if two peices of code do the same thing, we want them to look the same, but of course that is usually impossible to enforce and there are other considerations to take into account. For instance, if you're chaining method calls, you probably want to keep chaining method calls. If you're writing for
loops, then you want to keep writing them.
This is becoming a bit of a semantics game. To me, unwrap_or and or_else and so on do different things, just like + and - do different things, so the status quo is not âmultiple ways to do the same thingâ to me. And even if this feature were added, a newcomer would still need to understand the Option and Result types and what or
does with each of them, and theyâll still need to learn that Option/Result have a bunch of other methods to do various things that or
wonât.
But this is all nitpicking of nitpicks of nitpicks; no oneâs going to change their mind based on posts like this.
The core issue here is that thereâs (apparently?) no argument for this sugar other than the fact that it is a sugar, and the bar for sugar is relatively high (as it should be). If you want to persuade people that this is more useful than the dozens of other proposed sugars that have wisely not been tossed into the language, we should probably take a step back and try to come with some compelling examples of code before/after the sugar thatâs significantly easier to understand with the sugar (of course, I canât come up with any myself, which is why Iâm not a fan).
Speaking about the syntax choices, &&
and or
in the same expression look weird, IMHO. Especially if &&
in this context means something different from the normal short-circuiting boolean âandâ.
If weâre talking about chaining conditionals, Iâd prefer the syntax to be compatible to RFC 2497 (if let
and while let
chaining). Thereâs a possible future extension mentioned there for if-let-or
expressions, so, in the similar vein, Iâd expect the irrefutable âor chainsâ to look roughly like the following
let Some(x) = first_option
|| Some(x) = second_option
|| x = fallback_value;