Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Sorry, I didn't mean ignore errors as in unsafe, I meant that it allows the programmer to write code without having the error case be explicit. This is the (well, one of the) problems with null pointers in C and Java. You make a good point about errors from the API, and I guess this highlights a worthwhile difference between expected None (e.g., a fn which returns the age of a user, but the user could leave the field unspecified) and an exceptional None (the same method fails to connect to the database). It is perhaps worth having different mechanisms to deal with the two cases. Cheers, Nick On Wed, Jan 8, 2014 at 4:31 PM, Vadim wrote: > On Tue, Jan 7, 2014 at 6:39 PM, Nick Cameron wrote: > >> I think that you eventually have to deal with the Some or None-ness of an >> expression is an advantage of the ? operator, it means you can't ignore >> failure, but you don't have to deal with it at every step of a compound >> expression. Using an operator for unwrap has the same disadvantage as plain >> unwrap - it lets you ignore the failure case. >> > > First of all, it does not let me ignore errors - if I try to unwrap() a > None, it will kill my program (or at least the current task). Whether > this is what I want, depends on the use case. In my experience, more > often than not, an error returned by an API represents a bug in the > program. So what am I gonna do when I see that something has error'ed > out? I will probably just call fail!(). > > Anyways, I think this thread was about how to avoid having both foo() and > foo_opt() versions of every API, and many people (including myself), > consider unwrap() too noisy. So... > > Vadim > > > >> >> On Wed, Jan 8, 2014 at 1:42 PM, Vadim wrote: >> >>> I can see how '?.' would work when foo() returns a struct, but what >>> about non-struct types, e.g. Option ? Also, you'd still have to deal >>> with 'None' at the end of the chain. I think in most cases I'd rather >>> have it fail. >>> >>> I also don't really like refutable let-patterns proposal, because stuff >>> like "let Some(x) = foo();" does not work with chaining when foo() returns >>> a struct (and is still pretty wordy). >>> >>> Maybe we need an operator for "getting wrapped value"? This would be >>> similar to "deref" for [smart]pointers, except I think it should be a >>> postfix operator to allow for easy chaining. Let's say we chose '^' for >>> this purpose, and implemented its' trait for Option, Result, etc. Then one >>> could write: >>> let x = foo()^; >>> or >>> let y = foo()^.field; >>> >>> Vadim >>> >>> >>> >>> On Tue, Jan 7, 2014 at 11:30 AM, Nick Cameron wrote: >>> I agree with Simon that doubling the API is inelegant. I think the solution is adding sugar to make working with Option/Result easier - (semi-)independent of the foo/foo_opt issue, I find working with Option pretty painful. I prefer the Haskell do sugar to refutable patterns in let. Similar in spirit is the ? operator from Groovy, which I think is elegant and simple, it is an alternative to the . operator for field access/method call. In Rust it would have the following type and semantics: \Gamma e : Option fType(T', f) = T \Gamma e?f : Option e?f ~~> match e { Some => Some, None => None } and similarly for method call. The ? operator has the same advantages and disadvantages as Haskell's do, but is more concise. Just another alternative to consider. On Sat, Dec 7, 2013 at 9:41 AM, Simon Sapin wrote: > We have some functions and methods such as [std::str::from_utf8]( > http://static.rust-lang.org/doc/master/std/str/fn.from_utf8.html) > that may succeed and give a result, or fail when the input is invalid. > > 1. Sometimes we assume the input is valid and don’t want to deal with > the error case. Task failure works nicely. > > 2. Sometimes we do want to do something different on invalid input, so > returning an `Option` works best. > > And so we end up with both `from_utf8` and `from_utf8`. This > particular case is worse because we also have `from_utf8_owned` and > `from_utf8_owned_opt`, to cover everything. > > Multiplying names like this is just not good design. I’d like to > reduce this pattern. > > Getting behavior 1. when you have 2. is easy: just call `.unwrap()` on > the Option. I think we should rename every `foo_opt()` function or method > to just `foo`, remove the old `foo()` behavior, and tell people (through > documentation) to use `foo().unwrap()` if they want it back? > > The downsides are that unwrap is more verbose and gives less helpful > error messages on task failure. But I think it’s worth it. > > What do you think? > > (PS: I’m guilty of making this worse in #10828, but I’d like to > discuss this before
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
I realized something. A good near term working solution could make use of the pending procedural macros to make a nicer syntax for the and_then procedures! (or could the current syntax rules style macros work with that even?). Not sure If i'll have the time to do that experiment, but throwing the idea out there. On Tuesday, January 7, 2014, Vadim wrote: > I can see how '?.' would work when foo() returns a struct, but what > about non-struct types, e.g. Option ? Also, you'd still have to deal > with 'None' at the end of the chain. I think in most cases I'd rather > have it fail. > > I also don't really like refutable let-patterns proposal, because stuff > like "let Some(x) = foo();" does not work with chaining when foo() returns > a struct (and is still pretty wordy). > > Maybe we need an operator for "getting wrapped value"? This would be > similar to "deref" for [smart]pointers, except I think it should be a > postfix operator to allow for easy chaining. Let's say we chose '^' for > this purpose, and implemented its' trait for Option, Result, etc. Then one > could write: > let x = foo()^; > or > let y = foo()^.field; > > Vadim > > > > On Tue, Jan 7, 2014 at 11:30 AM, Nick Cameron wrote: > >> I agree with Simon that doubling the API is inelegant. I think the >> solution is adding sugar to make working with Option/Result easier - >> (semi-)independent of the foo/foo_opt issue, I find working with Option >> pretty painful. >> >> I prefer the Haskell do sugar to refutable patterns in let. Similar in >> spirit is the ? operator from Groovy, which I think is elegant and simple, >> it is an alternative to the . operator for field access/method call. In >> Rust it would have the following type and semantics: >> >> \Gamma e : Option >> fType(T', f) = T >> >> \Gamma e?f : Option >> >> e?f ~~> match e { Some => Some, None => None } >> >> and similarly for method call. >> >> The ? operator has the same advantages and disadvantages as Haskell's do, >> but is more concise. >> >> Just another alternative to consider. >> >> >> On Sat, Dec 7, 2013 at 9:41 AM, Simon Sapin wrote: >> >>> We have some functions and methods such as [std::str::from_utf8](http:// >>> static.rust-lang.org/doc/master/std/str/fn.from_utf8.html) that may >>> succeed and give a result, or fail when the input is invalid. >>> >>> 1. Sometimes we assume the input is valid and don’t want to deal with >>> the error case. Task failure works nicely. >>> >>> 2. Sometimes we do want to do something different on invalid input, so >>> returning an `Option` works best. >>> >>> And so we end up with both `from_utf8` and `from_utf8`. This particular >>> case is worse because we also have `from_utf8_owned` and >>> `from_utf8_owned_opt`, to cover everything. >>> >>> Multiplying names like this is just not good design. I’d like to reduce >>> this pattern. >>> >>> Getting behavior 1. when you have 2. is easy: just call `.unwrap()` on >>> the Option. I think we should rename every `foo_opt()` function or method >>> to just `foo`, remove the old `foo()` behavior, and tell people (through >>> documentation) to use `foo().unwrap()` if they want it back? >>> >>> The downsides are that unwrap is more verbose and gives less helpful >>> error messages on task failure. But I think it’s worth it. >>> >>> What do you think? >>> >>> (PS: I’m guilty of making this worse in #10828, but I’d like to discuss >>> this before sending pull requests with invasive API changes.) >>> >>> -- >>> Simon Sapin >>> ___ >>> Rust-dev mailing list >>> Rust-dev@mozilla.org >>> https://mail.mozilla.org/listinfo/rust-dev >>> >> >> >> ___ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> >> > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 8/01/2014, at 3:39 pm, Nick Cameron wrote: > I think that you eventually have to deal with the Some or None-ness of an > expression is an advantage of the ? operator, it means you can't ignore > failure, but you don't have to deal with it at every step of a compound > expression. Using an operator for unwrap has the same disadvantage as plain > unwrap - it lets you ignore the failure case. It's also worth pointing out that ? and do-notation solve different problems. ? is addressing that there's no partial application of the dot operator, so you can't write `maybe.and_then(.next)`. In do-notation, you'd still have to name the value inside the option. You can produce a limited form of the refutable do-notation with a macro: macro_rules! refute ( (let $bind:pat = $val:expr; $(let $rbind:pat = $rval:expr);+; $result:expr) => (match $val { $bind => refute!($(let $rbind = $rval);+; $result), fail => fail }); (let $bind:pat = $val:expr; $result:expr) => (match $val { $bind => $result, fail => fail }); ) fn add_opts(x: Option, y: Option) -> Option { refute!( let Some(a) = x; let Some(b) = y; Some(a + b) ) } Chaining the ? operator can't really be done in a tidy manner without having it be part of the language. `?.` has been really useful in CoffeeScript, and Rust has the advantage of being able to tie it into a trait and allow any relevant type to use it. -- Tim ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Tue, Jan 7, 2014 at 6:39 PM, Nick Cameron wrote: > I think that you eventually have to deal with the Some or None-ness of an > expression is an advantage of the ? operator, it means you can't ignore > failure, but you don't have to deal with it at every step of a compound > expression. Using an operator for unwrap has the same disadvantage as plain > unwrap - it lets you ignore the failure case. > First of all, it does not let me ignore errors - if I try to unwrap() a None, it will kill my program (or at least the current task). Whether this is what I want, depends on the use case. In my experience, more often than not, an error returned by an API represents a bug in the program. So what am I gonna do when I see that something has error'ed out? I will probably just call fail!(). Anyways, I think this thread was about how to avoid having both foo() and foo_opt() versions of every API, and many people (including myself), consider unwrap() too noisy. So... Vadim > > On Wed, Jan 8, 2014 at 1:42 PM, Vadim wrote: > >> I can see how '?.' would work when foo() returns a struct, but what about >> non-struct types, e.g. Option ? Also, you'd still have to deal with >> 'None' at the end of the chain. I think in most cases I'd rather have it >> fail. >> >> I also don't really like refutable let-patterns proposal, because stuff >> like "let Some(x) = foo();" does not work with chaining when foo() returns >> a struct (and is still pretty wordy). >> >> Maybe we need an operator for "getting wrapped value"? This would be >> similar to "deref" for [smart]pointers, except I think it should be a >> postfix operator to allow for easy chaining. Let's say we chose '^' for >> this purpose, and implemented its' trait for Option, Result, etc. Then one >> could write: >> let x = foo()^; >> or >> let y = foo()^.field; >> >> Vadim >> >> >> >> On Tue, Jan 7, 2014 at 11:30 AM, Nick Cameron wrote: >> >>> I agree with Simon that doubling the API is inelegant. I think the >>> solution is adding sugar to make working with Option/Result easier - >>> (semi-)independent of the foo/foo_opt issue, I find working with Option >>> pretty painful. >>> >>> I prefer the Haskell do sugar to refutable patterns in let. Similar in >>> spirit is the ? operator from Groovy, which I think is elegant and simple, >>> it is an alternative to the . operator for field access/method call. In >>> Rust it would have the following type and semantics: >>> >>> \Gamma e : Option >>> fType(T', f) = T >>> >>> \Gamma e?f : Option >>> >>> e?f ~~> match e { Some => Some, None => None } >>> >>> and similarly for method call. >>> >>> The ? operator has the same advantages and disadvantages as Haskell's >>> do, but is more concise. >>> >>> Just another alternative to consider. >>> >>> >>> On Sat, Dec 7, 2013 at 9:41 AM, Simon Sapin wrote: >>> We have some functions and methods such as [std::str::from_utf8]( http://static.rust-lang.org/doc/master/std/str/fn.from_utf8.html) that may succeed and give a result, or fail when the input is invalid. 1. Sometimes we assume the input is valid and don’t want to deal with the error case. Task failure works nicely. 2. Sometimes we do want to do something different on invalid input, so returning an `Option` works best. And so we end up with both `from_utf8` and `from_utf8`. This particular case is worse because we also have `from_utf8_owned` and `from_utf8_owned_opt`, to cover everything. Multiplying names like this is just not good design. I’d like to reduce this pattern. Getting behavior 1. when you have 2. is easy: just call `.unwrap()` on the Option. I think we should rename every `foo_opt()` function or method to just `foo`, remove the old `foo()` behavior, and tell people (through documentation) to use `foo().unwrap()` if they want it back? The downsides are that unwrap is more verbose and gives less helpful error messages on task failure. But I think it’s worth it. What do you think? (PS: I’m guilty of making this worse in #10828, but I’d like to discuss this before sending pull requests with invasive API changes.) -- Simon Sapin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev >>> >>> >>> ___ >>> Rust-dev mailing list >>> Rust-dev@mozilla.org >>> https://mail.mozilla.org/listinfo/rust-dev >>> >>> ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
I think that you eventually have to deal with the Some or None-ness of an expression is an advantage of the ? operator, it means you can't ignore failure, but you don't have to deal with it at every step of a compound expression. Using an operator for unwrap has the same disadvantage as plain unwrap - it lets you ignore the failure case. On Wed, Jan 8, 2014 at 1:42 PM, Vadim wrote: > I can see how '?.' would work when foo() returns a struct, but what about > non-struct types, e.g. Option ? Also, you'd still have to deal with > 'None' at the end of the chain. I think in most cases I'd rather have it > fail. > > I also don't really like refutable let-patterns proposal, because stuff > like "let Some(x) = foo();" does not work with chaining when foo() returns > a struct (and is still pretty wordy). > > Maybe we need an operator for "getting wrapped value"? This would be > similar to "deref" for [smart]pointers, except I think it should be a > postfix operator to allow for easy chaining. Let's say we chose '^' for > this purpose, and implemented its' trait for Option, Result, etc. Then one > could write: > let x = foo()^; > or > let y = foo()^.field; > > Vadim > > > > On Tue, Jan 7, 2014 at 11:30 AM, Nick Cameron wrote: > >> I agree with Simon that doubling the API is inelegant. I think the >> solution is adding sugar to make working with Option/Result easier - >> (semi-)independent of the foo/foo_opt issue, I find working with Option >> pretty painful. >> >> I prefer the Haskell do sugar to refutable patterns in let. Similar in >> spirit is the ? operator from Groovy, which I think is elegant and simple, >> it is an alternative to the . operator for field access/method call. In >> Rust it would have the following type and semantics: >> >> \Gamma e : Option >> fType(T', f) = T >> >> \Gamma e?f : Option >> >> e?f ~~> match e { Some => Some, None => None } >> >> and similarly for method call. >> >> The ? operator has the same advantages and disadvantages as Haskell's do, >> but is more concise. >> >> Just another alternative to consider. >> >> >> On Sat, Dec 7, 2013 at 9:41 AM, Simon Sapin wrote: >> >>> We have some functions and methods such as [std::str::from_utf8](http:// >>> static.rust-lang.org/doc/master/std/str/fn.from_utf8.html) that may >>> succeed and give a result, or fail when the input is invalid. >>> >>> 1. Sometimes we assume the input is valid and don’t want to deal with >>> the error case. Task failure works nicely. >>> >>> 2. Sometimes we do want to do something different on invalid input, so >>> returning an `Option` works best. >>> >>> And so we end up with both `from_utf8` and `from_utf8`. This particular >>> case is worse because we also have `from_utf8_owned` and >>> `from_utf8_owned_opt`, to cover everything. >>> >>> Multiplying names like this is just not good design. I’d like to reduce >>> this pattern. >>> >>> Getting behavior 1. when you have 2. is easy: just call `.unwrap()` on >>> the Option. I think we should rename every `foo_opt()` function or method >>> to just `foo`, remove the old `foo()` behavior, and tell people (through >>> documentation) to use `foo().unwrap()` if they want it back? >>> >>> The downsides are that unwrap is more verbose and gives less helpful >>> error messages on task failure. But I think it’s worth it. >>> >>> What do you think? >>> >>> (PS: I’m guilty of making this worse in #10828, but I’d like to discuss >>> this before sending pull requests with invasive API changes.) >>> >>> -- >>> Simon Sapin >>> ___ >>> Rust-dev mailing list >>> Rust-dev@mozilla.org >>> https://mail.mozilla.org/listinfo/rust-dev >>> >> >> >> ___ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> >> > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
I can see how '?.' would work when foo() returns a struct, but what about non-struct types, e.g. Option ? Also, you'd still have to deal with 'None' at the end of the chain. I think in most cases I'd rather have it fail. I also don't really like refutable let-patterns proposal, because stuff like "let Some(x) = foo();" does not work with chaining when foo() returns a struct (and is still pretty wordy). Maybe we need an operator for "getting wrapped value"? This would be similar to "deref" for [smart]pointers, except I think it should be a postfix operator to allow for easy chaining. Let's say we chose '^' for this purpose, and implemented its' trait for Option, Result, etc. Then one could write: let x = foo()^; or let y = foo()^.field; Vadim On Tue, Jan 7, 2014 at 11:30 AM, Nick Cameron wrote: > I agree with Simon that doubling the API is inelegant. I think the > solution is adding sugar to make working with Option/Result easier - > (semi-)independent of the foo/foo_opt issue, I find working with Option > pretty painful. > > I prefer the Haskell do sugar to refutable patterns in let. Similar in > spirit is the ? operator from Groovy, which I think is elegant and simple, > it is an alternative to the . operator for field access/method call. In > Rust it would have the following type and semantics: > > \Gamma e : Option > fType(T', f) = T > > \Gamma e?f : Option > > e?f ~~> match e { Some => Some, None => None } > > and similarly for method call. > > The ? operator has the same advantages and disadvantages as Haskell's do, > but is more concise. > > Just another alternative to consider. > > > On Sat, Dec 7, 2013 at 9:41 AM, Simon Sapin wrote: > >> We have some functions and methods such as [std::str::from_utf8](http:// >> static.rust-lang.org/doc/master/std/str/fn.from_utf8.html) that may >> succeed and give a result, or fail when the input is invalid. >> >> 1. Sometimes we assume the input is valid and don’t want to deal with the >> error case. Task failure works nicely. >> >> 2. Sometimes we do want to do something different on invalid input, so >> returning an `Option` works best. >> >> And so we end up with both `from_utf8` and `from_utf8`. This particular >> case is worse because we also have `from_utf8_owned` and >> `from_utf8_owned_opt`, to cover everything. >> >> Multiplying names like this is just not good design. I’d like to reduce >> this pattern. >> >> Getting behavior 1. when you have 2. is easy: just call `.unwrap()` on >> the Option. I think we should rename every `foo_opt()` function or method >> to just `foo`, remove the old `foo()` behavior, and tell people (through >> documentation) to use `foo().unwrap()` if they want it back? >> >> The downsides are that unwrap is more verbose and gives less helpful >> error messages on task failure. But I think it’s worth it. >> >> What do you think? >> >> (PS: I’m guilty of making this worse in #10828, but I’d like to discuss >> this before sending pull requests with invasive API changes.) >> >> -- >> Simon Sapin >> ___ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> > > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
I agree with Simon that doubling the API is inelegant. I think the solution is adding sugar to make working with Option/Result easier - (semi-)independent of the foo/foo_opt issue, I find working with Option pretty painful. I prefer the Haskell do sugar to refutable patterns in let. Similar in spirit is the ? operator from Groovy, which I think is elegant and simple, it is an alternative to the . operator for field access/method call. In Rust it would have the following type and semantics: \Gamma e : Option fType(T', f) = T \Gamma e?f : Option e?f ~~> match e { Some => Some, None => None } and similarly for method call. The ? operator has the same advantages and disadvantages as Haskell's do, but is more concise. Just another alternative to consider. On Sat, Dec 7, 2013 at 9:41 AM, Simon Sapin wrote: > We have some functions and methods such as [std::str::from_utf8](http:// > static.rust-lang.org/doc/master/std/str/fn.from_utf8.html) that may > succeed and give a result, or fail when the input is invalid. > > 1. Sometimes we assume the input is valid and don’t want to deal with the > error case. Task failure works nicely. > > 2. Sometimes we do want to do something different on invalid input, so > returning an `Option` works best. > > And so we end up with both `from_utf8` and `from_utf8`. This particular > case is worse because we also have `from_utf8_owned` and > `from_utf8_owned_opt`, to cover everything. > > Multiplying names like this is just not good design. I’d like to reduce > this pattern. > > Getting behavior 1. when you have 2. is easy: just call `.unwrap()` on the > Option. I think we should rename every `foo_opt()` function or method to > just `foo`, remove the old `foo()` behavior, and tell people (through > documentation) to use `foo().unwrap()` if they want it back? > > The downsides are that unwrap is more verbose and gives less helpful error > messages on task failure. But I think it’s worth it. > > What do you think? > > (PS: I’m guilty of making this worse in #10828, but I’d like to discuss > this before sending pull requests with invasive API changes.) > > -- > Simon Sapin > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
This is a very good point. Many of those same issues apply in Haskell too. Additionally, the examples people have given for refutable let thus far all seem to be special cases of a do notation / computation expression / monadic abstraction. That said, unless a special builtin trait is made, that line of recommendation seems like it's not viable until rusts type system gets a bit more enriched, what with higher kinded types being needed etc. On Tuesday, December 24, 2013, Lars Bergstrom wrote: > On Dec 23, 2013, at 11:23 AM, Patrick Walton > > > wrote: > > > > On 12/23/13 4:12 AM, Gábor Lehel wrote: > >> I don't like either that (a) the possible failure is silent, and > >> refutable lets look the same as irrefutable ones, nor (b) baking fail!() > >> into the semantics. Haskell has these also and I think it's a wart. The > >> proposed syntax solves both issues. > > > > For what it's worth, Rust's pattern matching is pretty heavily based on > OCaml's and the OCaml compiler complains with a warning if you use a > refutable pattern in `let`. > > At the time SML and Caml made those decisions, neither language provided > stack backtraces. According to the folks I've asked about it, the reason > that refutable patterns in let bindings were left in there with a warning > was that if you called Option.valOf on NONE, you just get: > uncaught exception Option > raised at: Basis/Implementation/option.sml:17.25-17.31 > - > > And the debugging is a real pain because "you failed in the basis library" > doesn't help you track it down and you're pretty much stuck with > printf-debugging (because there were also no debuggers / breakpoints). > Whereas if you fail on the binding, the exception is thrown on the line > where the binding attempt occurred: > uncaught exception Bind [nonexhaustive binding failure] > raised at: stdIn:1.10-3.10 > - > > This was supposedly an especially contentious decision in the SML language > design meetings. > > Given that modern ML implementations at least have the option to provide > stack backtraces in debugging builds, the people I've talked to have said > they would probably not allow refutable patterns today because large > codebases written in this style end up with hundreds to thousands of > "ignorable warnings" in their output, which both looks ugly and drowns out > any real warnings. But, they can't change things now because it would break > too much legacy code. > - Lars > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Dec 23, 2013, at 11:23 AM, Patrick Walton wrote: > > On 12/23/13 4:12 AM, Gábor Lehel wrote: >> I don't like either that (a) the possible failure is silent, and >> refutable lets look the same as irrefutable ones, nor (b) baking fail!() >> into the semantics. Haskell has these also and I think it's a wart. The >> proposed syntax solves both issues. > > For what it's worth, Rust's pattern matching is pretty heavily based on > OCaml's and the OCaml compiler complains with a warning if you use a > refutable pattern in `let`. At the time SML and Caml made those decisions, neither language provided stack backtraces. According to the folks I've asked about it, the reason that refutable patterns in let bindings were left in there with a warning was that if you called Option.valOf on NONE, you just get: uncaught exception Option raised at: Basis/Implementation/option.sml:17.25-17.31 - And the debugging is a real pain because "you failed in the basis library" doesn't help you track it down and you're pretty much stuck with printf-debugging (because there were also no debuggers / breakpoints). Whereas if you fail on the binding, the exception is thrown on the line where the binding attempt occurred: uncaught exception Bind [nonexhaustive binding failure] raised at: stdIn:1.10-3.10 - This was supposedly an especially contentious decision in the SML language design meetings. Given that modern ML implementations at least have the option to provide stack backtraces in debugging builds, the people I've talked to have said they would probably not allow refutable patterns today because large codebases written in this style end up with hundreds to thousands of "ignorable warnings" in their output, which both looks ugly and drowns out any real warnings. But, they can't change things now because it would break too much legacy code. - Lars ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
> For those of us that were not around or do not remember, can you explain what was tried and rejected? Heh, it was so long ago that I forgot that the `match` keyword used to be `alt`. Here's the relevant section from the 0.1 manual (Jan 2012): https://github.com/mozilla/rust/blob/16e4369fe3b5f00aa3cdc584a4e41c51c0d3ca8a/doc/tutorial.md#pattern-matching "If the arm with the wildcard pattern was left off in the above example, running it on a number greater than ten (or negative) would cause a run-time failure. When no arm matches, alt constructs do not silently fall through—they blow up instead." Back then, we had no facility to statically force exhaustiveness. This changed in 0.2, when exhaustive matches became the default, though you could still opt-in to non-exhaustive matches by using `alt check` rather than `alt`. https://github.com/mozilla/rust/blob/619c4fce891f31ec234a3ac162d40d3def95956e/RELEASES.txt#L581 Indeed, as you mention, at the time people were worried that this would lead to widespread proliferation of `_ => fail`, especially for uses such as matching on integers, which we lack the facilities to exhaustively check. However, in the years since, I can remember only a single person noticing this and lamenting it, and the peace of mind provided by statically-checked exhaustiveness is certainly pleasant. Furthermore, so few people opted-in to dynamic checking via `alt check` that we had dropped the functionality entirely by 0.4. On Mon, Dec 23, 2013 at 3:40 PM, Simon Sapin wrote: > On 23/12/2013 20:55, Benjamin Striegel wrote: > >> I too think it would be a big mistake to allow let patterns to be >> refutable, when we've already tried and rejected allowing the same in >> match statements (ancient Rust history quiz: who else remembers `match >> check`?). >> > > For those of us that were not around or do not remember, can you explain > what was tried and rejected? > > I sometimes find myself writing a `_ => ()` arm for match and wish it > could be implied… and sometimes `_ => fail!()`. That the two are sometimes > used is probably a sign that the status quo (require it to be explicit) is > better. > > -- > Simon Sapin > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 23/12/2013 20:55, Benjamin Striegel wrote: I too think it would be a big mistake to allow let patterns to be refutable, when we've already tried and rejected allowing the same in match statements (ancient Rust history quiz: who else remembers `match check`?). For those of us that were not around or do not remember, can you explain what was tried and rejected? I sometimes find myself writing a `_ => ()` arm for match and wish it could be implied… and sometimes `_ => fail!()`. That the two are sometimes used is probably a sign that the status quo (require it to be explicit) is better. -- Simon Sapin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
I too think it would be a big mistake to allow let patterns to be refutable, when we've already tried and rejected allowing the same in match statements (ancient Rust history quiz: who else remembers `match check`?). On Mon, Dec 23, 2013 at 2:44 PM, Gábor Lehel wrote: > That seems like a nice compromise, but I don't think it's a good one. > Either you intended the pattern to be refutable or you didn't. If you > didn't and it is, you should get an error, not a warning. If you did, you > shouldn't get a warning at all. Are you going to put a compiler pragma to > disable the warning at every use site where you intentionally want a let to > be refutable? At that point, you might as well have separate syntax for > refutable and irrefutable lets. Or are you just going to live with having > false positive warnings in your code? > > (FWIW, I'm basically fine with having only irrefutable lets, and using > `match` for the other cases, or in other words the status quo. But if we > *do* add refutable lets, I strongly think they should be explicit.) > > > > On Mon, Dec 23, 2013 at 7:03 PM, Carter Schonwald < > carter.schonw...@gmail.com> wrote: > >> that seems like a reasonable balance >> >> >> On Mon, Dec 23, 2013 at 12:23 PM, Patrick Walton wrote: >> >>> On 12/23/13 4:12 AM, Gábor Lehel wrote: >>> I don't like either that (a) the possible failure is silent, and refutable lets look the same as irrefutable ones, nor (b) baking fail!() into the semantics. Haskell has these also and I think it's a wart. The proposed syntax solves both issues. >>> >>> For what it's worth, Rust's pattern matching is pretty heavily based on >>> OCaml's and the OCaml compiler complains with a warning if you use a >>> refutable pattern in `let`. >>> >> >>> Patrick >>> >>> >>> ___ >>> Rust-dev mailing list >>> Rust-dev@mozilla.org >>> https://mail.mozilla.org/listinfo/rust-dev >>> >> >> >> ___ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> >> > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
That seems like a nice compromise, but I don't think it's a good one. Either you intended the pattern to be refutable or you didn't. If you didn't and it is, you should get an error, not a warning. If you did, you shouldn't get a warning at all. Are you going to put a compiler pragma to disable the warning at every use site where you intentionally want a let to be refutable? At that point, you might as well have separate syntax for refutable and irrefutable lets. Or are you just going to live with having false positive warnings in your code? (FWIW, I'm basically fine with having only irrefutable lets, and using `match` for the other cases, or in other words the status quo. But if we *do* add refutable lets, I strongly think they should be explicit.) On Mon, Dec 23, 2013 at 7:03 PM, Carter Schonwald < carter.schonw...@gmail.com> wrote: > that seems like a reasonable balance > > > On Mon, Dec 23, 2013 at 12:23 PM, Patrick Walton wrote: > >> On 12/23/13 4:12 AM, Gábor Lehel wrote: >> >>> I don't like either that (a) the possible failure is silent, and >>> refutable lets look the same as irrefutable ones, nor (b) baking fail!() >>> into the semantics. Haskell has these also and I think it's a wart. The >>> proposed syntax solves both issues. >>> >> >> For what it's worth, Rust's pattern matching is pretty heavily based on >> OCaml's and the OCaml compiler complains with a warning if you use a >> refutable pattern in `let`. >> > >> Patrick >> >> >> ___ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> > > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 12/23/13 10:48 AM, Benjamin Striegel wrote: > the OCaml compiler complains with a warning if you use a refutable pattern in `let`. And what does OCaml do at runtime if the pattern is refuted? Throws. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
> the OCaml compiler complains with a warning if you use a refutable pattern in `let`. And what does OCaml do at runtime if the pattern is refuted? On Mon, Dec 23, 2013 at 12:23 PM, Patrick Walton wrote: > On 12/23/13 4:12 AM, Gábor Lehel wrote: > >> I don't like either that (a) the possible failure is silent, and >> refutable lets look the same as irrefutable ones, nor (b) baking fail!() >> into the semantics. Haskell has these also and I think it's a wart. The >> proposed syntax solves both issues. >> > > For what it's worth, Rust's pattern matching is pretty heavily based on > OCaml's and the OCaml compiler complains with a warning if you use a > refutable pattern in `let`. > > Patrick > > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
that seems like a reasonable balance On Mon, Dec 23, 2013 at 12:23 PM, Patrick Walton wrote: > On 12/23/13 4:12 AM, Gábor Lehel wrote: > >> I don't like either that (a) the possible failure is silent, and >> refutable lets look the same as irrefutable ones, nor (b) baking fail!() >> into the semantics. Haskell has these also and I think it's a wart. The >> proposed syntax solves both issues. >> > > For what it's worth, Rust's pattern matching is pretty heavily based on > OCaml's and the OCaml compiler complains with a warning if you use a > refutable pattern in `let`. > > Patrick > > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 12/23/13 4:12 AM, Gábor Lehel wrote: I don't like either that (a) the possible failure is silent, and refutable lets look the same as irrefutable ones, nor (b) baking fail!() into the semantics. Haskell has these also and I think it's a wart. The proposed syntax solves both issues. For what it's worth, Rust's pattern matching is pretty heavily based on OCaml's and the OCaml compiler complains with a warning if you use a refutable pattern in `let`. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
> I may have missed it, but is there a reason not to have just that? Make > let similar to Erlang’s `=` and fail on refutation? Erlang is designed around handling failure. It has links, monitors, supervisors, and so forth. Rust has only some very basic tools for catching the failure of a task. I'll also note, that because Erlang has pattern matching in the clauses themselves, many failures occur even before the function bodies. Some of those features incur non-trivial runtime costs which is why Rust doesn't have them. jack. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Sun, Dec 22, 2013 at 7:37 PM, Léo Testard wrote: > Hello, > > Le 22 déc. 2013 à 18:59, Stefan Plantikow a > écrit : > > > Hi, > > > > Am 22.12.2013 um 16:47 schrieb Gábor Lehel : > > > > This is a nice idea. At first I thought it wouldn’t work with `if` but > in expressions `if` requires `else` so the grammar wouldn’t be ambiguous: > > > > No, it doesn't. As long as the if's "true block" returns unit. > let foo = if ... { }; is perfectly legal, even it doesn't make much sense > in practice. > > Leo > Thinking about this, if we say that `else` following a `let` is allowed if *and only if* the pattern is refutable, then this wouldn't actually be ambiguous, because something of type `()` can never be refutable. Therefore `let ... = if { ... } else { ... };` can only be legal if the `else` belongs to the `if`. I'm not completely clear on the relationship between grammatic and semantic ambiguity. Would the grammar still be ambiguous in this case? I would naively think that you're not allowed to take types and such into account at the grammar level, but Rust seemingly already does so w.r.t. whether or not things (such as `if`) return `()`, so I'm a little bit confused. Can someone explain? > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Mon, Dec 23, 2013 at 10:11 AM, Masklinn wrote: > > On 2013-12-23, at 05:12 , Corey Richardson wrote: > > > I find the ability to have refutable let > > I may have missed it, but is there a reason not to have just that? Make > let similar to Erlang’s `=` and fail on refutation? > I don't like either that (a) the possible failure is silent, and refutable lets look the same as irrefutable ones, nor (b) baking fail!() into the semantics. Haskell has these also and I think it's a wart. The proposed syntax solves both issues. Rust doesn't allow partial matches in `match`es either, for reasons, so I think it would be pretty strange to turn around and silently allow them in `let`s. The strongest arguments against IMHO are YAGNI (which is why I prefaced the whole thing with *if* there's demand for a refutable let), and the ambiguity with `if` (which is a technical issue that may or may not have a satisfactory solution). A meta-level process question: now that we have the `feature` attribute, wouldn't that be a great way to empirically decide questions like these? Implement the feature, put it behind a feature gate, and see how much use it gets, and/or if there are any problems with it? This isn't the first case where it seems like that might be more productive than trying to anticipate all of the answers from theory alone. And it seems to work pretty well for GHC. Just perhaps we could be more aggressive about removing features which weren't successful. > > You said you find the basic let’s irrefutability to be a useful property > but have not explained why, and why it makes sense to introduce a > separate-but-similar construct with subtly different semantics > (I also see this as a possible failure, would users of the language > really expect `let` to be irrefutable and `let [else]` to be refutable, > or would they expect `let [else]` to allow returning a value and `let` > to just fail on mismatch? If such different semantics are desired, > I’d suggest using a different keyword entirely) > If I'm understanding you correctly, this is a problem that would solve itself: if someone thinks a plain `let` is refutable and will just fail on mismatch, the compiler will quickly tell her otherwise. > > > more compelling than the > > ability to work around it with functions wrapping `match` > > That assertion seems ill supported so far: just about every example is > in terms of `Option`, and `Option` is the one type which does not need a > refutable let, owing to its truckload of convenience methods covering > just about every basic use cases the only reasons to use a `match` with > Option are personal preferences and insufficient knowledge of the type. > > > On Sun, Dec 22, 2013 at 11:00 PM, Carter Schonwald > > wrote: > >> Agreed! > >> > >> > >> On Sunday, December 22, 2013, Ziad Hatahet wrote: > >>> > >>> But we already have Option::unwrap_or() and Option::unwrap_or_else() > that > >>> behave similar to the 'else' syntax suggested above. > >>> > >>> -- > >>> Ziad > >>> > >>> > >>> On Sun, Dec 22, 2013 at 10:37 AM, Léo Testard > >>> wrote: > > Hello, > > Le 22 déc. 2013 à 18:59, Stefan Plantikow > a > écrit : > > > Hi, > > > > Am 22.12.2013 um 16:47 schrieb Gábor Lehel : > > > > This is a nice idea. At first I thought it wouldn’t work with `if` > but > > in expressions `if` requires `else` so the grammar wouldn’t be > ambiguous: > > > > No, it doesn't. As long as the if's "true block" returns unit. > let foo = if ... { }; is perfectly legal, even it doesn't make much > sense > in practice. > > Leo > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > >>> > >> > >> ___ > >> Rust-dev mailing list > >> Rust-dev@mozilla.org > >> https://mail.mozilla.org/listinfo/rust-dev > >> > > ___ > > Rust-dev mailing list > > Rust-dev@mozilla.org > > https://mail.mozilla.org/listinfo/rust-dev > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Hi, Am 23.12.2013 um 10:11 schrieb Masklinn : > > On 2013-12-23, at 05:12 , Corey Richardson wrote: > >> I find the ability to have refutable let > > I may have missed it, but is there a reason not to have just that? Make > let similar to Erlang’s `=` and fail on refutation? > I didn’t understand this to be about wether let should accept refutable patterns in general. Rather this is about wether there should be additional syntax for refutable patterns. The decision to make irrefutable let the default seems reasonable as it avoids silent breakage when new variants are introduced for an enum type. > You said you find the basic let’s irrefutability to be a useful property > but have not explained why, and why it makes sense to introduce a > separate-but-similar construct with subtly different semantics > (I also see this as a possible failure, would users of the language > really expect `let` to be irrefutable and `let [else]` to be refutable, > or would they expect `let [else]` to allow returning a value and `let` > to just fail on mismatch? If such different semantics are desired, > I’d suggest using a different keyword entirely) > >> more compelling than the >> ability to work around it with functions wrapping `match` > > That assertion seems ill supported so far: just about every example is > in terms of `Option`, and `Option` is the one type which does not need a > refutable let, owing to its truckload of convenience methods covering > just about every basic use cases the only reasons to use a `match` with > Option are personal preferences and insufficient knowledge of the type. > Sure, this discussion has used Option as a running example. I guess the more interesting use case is a library defined type without an unwrap() or similar method. A client of the library could of course implement his own helper method to solve that issue - or just use a variant of let with refutable patterns. The benefit of the refutable patterns would be less boilerplate for helper methods like unwrap(), the ability to „unwrap“ any type, and a nice syntax for trying multiple values in succession ( let Some(x) =? try_1(), try_2(), fail() ). Cheers, Stefan.___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 2013-12-23, at 05:12 , Corey Richardson wrote: > I find the ability to have refutable let I may have missed it, but is there a reason not to have just that? Make let similar to Erlang’s `=` and fail on refutation? You said you find the basic let’s irrefutability to be a useful property but have not explained why, and why it makes sense to introduce a separate-but-similar construct with subtly different semantics (I also see this as a possible failure, would users of the language really expect `let` to be irrefutable and `let [else]` to be refutable, or would they expect `let [else]` to allow returning a value and `let` to just fail on mismatch? If such different semantics are desired, I’d suggest using a different keyword entirely) > more compelling than the > ability to work around it with functions wrapping `match` That assertion seems ill supported so far: just about every example is in terms of `Option`, and `Option` is the one type which does not need a refutable let, owing to its truckload of convenience methods covering just about every basic use cases the only reasons to use a `match` with Option are personal preferences and insufficient knowledge of the type. > On Sun, Dec 22, 2013 at 11:00 PM, Carter Schonwald > wrote: >> Agreed! >> >> >> On Sunday, December 22, 2013, Ziad Hatahet wrote: >>> >>> But we already have Option::unwrap_or() and Option::unwrap_or_else() that >>> behave similar to the 'else' syntax suggested above. >>> >>> -- >>> Ziad >>> >>> >>> On Sun, Dec 22, 2013 at 10:37 AM, Léo Testard >>> wrote: Hello, Le 22 déc. 2013 à 18:59, Stefan Plantikow a écrit : > Hi, > > Am 22.12.2013 um 16:47 schrieb Gábor Lehel : > > This is a nice idea. At first I thought it wouldn’t work with `if` but > in expressions `if` requires `else` so the grammar wouldn’t be ambiguous: > No, it doesn't. As long as the if's "true block" returns unit. let foo = if ... { }; is perfectly legal, even it doesn't make much sense in practice. Leo ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev >>> >> >> ___ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
I find the ability to have refutable let more compelling than the ability to work around it with functions wrapping `match` On Sun, Dec 22, 2013 at 11:00 PM, Carter Schonwald wrote: > Agreed! > > > On Sunday, December 22, 2013, Ziad Hatahet wrote: >> >> But we already have Option::unwrap_or() and Option::unwrap_or_else() that >> behave similar to the 'else' syntax suggested above. >> >> -- >> Ziad >> >> >> On Sun, Dec 22, 2013 at 10:37 AM, Léo Testard >> wrote: >>> >>> Hello, >>> >>> Le 22 déc. 2013 à 18:59, Stefan Plantikow a >>> écrit : >>> >>> > Hi, >>> > >>> > Am 22.12.2013 um 16:47 schrieb Gábor Lehel : >>> > >>> > This is a nice idea. At first I thought it wouldn’t work with `if` but >>> > in expressions `if` requires `else` so the grammar wouldn’t be ambiguous: >>> > >>> >>> No, it doesn't. As long as the if's "true block" returns unit. >>> let foo = if ... { }; is perfectly legal, even it doesn't make much sense >>> in practice. >>> >>> Leo >>> >>> ___ >>> Rust-dev mailing list >>> Rust-dev@mozilla.org >>> https://mail.mozilla.org/listinfo/rust-dev >>> >> > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Agreed! On Sunday, December 22, 2013, Ziad Hatahet wrote: > But we already have Option::unwrap_or() and Option::unwrap_or_else() that > behave similar to the 'else' syntax suggested above. > > -- > Ziad > > > On Sun, Dec 22, 2013 at 10:37 AM, Léo Testard > > > wrote: > >> Hello, >> >> Le 22 déc. 2013 à 18:59, Stefan Plantikow >> > 'stefan.planti...@gmail.com');>> >> a écrit : >> >> > Hi, >> > >> > Am 22.12.2013 um 16:47 schrieb Gábor Lehel >> > >> >: >> > >> > This is a nice idea. At first I thought it wouldn’t work with `if` but >> in expressions `if` requires `else` so the grammar wouldn’t be ambiguous: >> > >> >> No, it doesn't. As long as the if's "true block" returns unit. >> let foo = if ... { }; is perfectly legal, even it doesn't make much sense >> in practice. >> >> Leo >> >> ___ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> >> > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
But we already have Option::unwrap_or() and Option::unwrap_or_else() that behave similar to the 'else' syntax suggested above. -- Ziad On Sun, Dec 22, 2013 at 10:37 AM, Léo Testard wrote: > Hello, > > Le 22 déc. 2013 à 18:59, Stefan Plantikow a > écrit : > > > Hi, > > > > Am 22.12.2013 um 16:47 schrieb Gábor Lehel : > > > > This is a nice idea. At first I thought it wouldn’t work with `if` but > in expressions `if` requires `else` so the grammar wouldn’t be ambiguous: > > > > No, it doesn't. As long as the if's "true block" returns unit. > let foo = if ... { }; is perfectly legal, even it doesn't make much sense > in practice. > > Leo > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Hello, Le 22 déc. 2013 à 18:59, Stefan Plantikow a écrit : > Hi, > > Am 22.12.2013 um 16:47 schrieb Gábor Lehel : > > This is a nice idea. At first I thought it wouldn’t work with `if` but in > expressions `if` requires `else` so the grammar wouldn’t be ambiguous: > No, it doesn't. As long as the if's "true block" returns unit. let foo = if ... { }; is perfectly legal, even it doesn't make much sense in practice. Leo signature.asc Description: Message signed with OpenPGP using GPGMail ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Hi, Am 22.12.2013 um 16:47 schrieb Gábor Lehel : > Using `match` works well enough, but if there's demand for a refutable `let` > which is lighter-weight, what about: > > let Some(result) = from_utf8(some_bytes) else fail!(); > This is a nice idea. At first I thought it wouldn’t work with `if` but in expressions `if` requires `else` so the grammar wouldn’t be ambiguous: let Some(result) = if cond { .. } else { … } else fail(); > In other words, if the `let` pattern is refutable, you have to provide > something `else` with return type `!` as the alternative for when the `let` > fails to match. > Shouldn't the return be the same for all expressions? This would allow: let Some(result) = from_utf8(some_bytes) else Some(defaultValue); Stefan. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
I quite like this proposal, though I'd suggest that the "else" clause is evaluated as the value for when the pattern fails. `!` would always be substitutable there. On Sun, Dec 22, 2013 at 10:47 AM, Gábor Lehel wrote: > Using `match` works well enough, but if there's demand for a refutable `let` > which is lighter-weight, what about: > > let Some(result) = from_utf8(some_bytes) else fail!(); > > In other words, if the `let` pattern is refutable, you have to provide > something `else` with return type `!` as the alternative for when the `let` > fails to match. > > > (I could imagine that being generalized to any number of `else`s of which > only the last "returns `!`" (i.o.w. never returns), for example > > let Some(result) = from_utf8(some_bytes) else > from_utf8(some_other_bytes) else fail!(); > > and/or to allowing anything `else` which always matches, e.g. > > let Some(result) = from_utf8(some_bytes) else Some("default"); > > of which anything that "returns" `!` would be only a special case. But these > have progressively diminishing returns, and I'm merely mentioning, not > endorsing them.) > > > On Tue, Dec 17, 2013 at 9:11 PM, Kevin Ballard wrote: >> >> On Dec 17, 2013, at 11:37 AM, Stefan Plantikow >> wrote: >> >> Hi, >> >> Am 17.12.2013 um 20:10 schrieb Corey Richardson : >> >> On Tue, Dec 17, 2013 at 2:06 PM, Stefan Plantikow >> wrote: >> >> Hi, >> >> >> Am 09.12.2013 um 16:53 schrieb Damien Radtke : >> >> I have no idea if it would be feasible in the standard library, but >> wouldn't the ideal solution be having one function (e.g. from_utf8()) that >> could return two possible values, a bare result and an Option? Letting the >> compiler decide which version to use based on type inference like this: >> >>let result: ~str = from_utf8(...); >>let result: Option<~str> = from_utf8(...); >> >> Assuming both of them are passed invalid UTF8, then the first version >> would fail, but the second version would just return None. >> >> >> >> >> We already have pattern matching in `let` (the LHS is a pattern), but >> it's only for irrefutable patterns. IOW, `let` can never fail, and >> that's a very very useful property IMO. >> >> >> oh ok I haven’t kept up on the syntax then. Given the utility of >> destructuring bind for error handling, wouldn't it make sense to have a >> variant of let that can fail? >> >> Now syntax is a matter of practicality and taste but spontaneously this >> comes to mind: >> >>let opt Some(~result) = from_utf8(..) >> >> comes to mind. >> >> >> You can do it with a bit more verbosity, which I think is perfectly fine >> as it makes failure much more obvious. >> >> let result = match from_utf8(..) { >> Some(~result) => result, >> _ => fail!("b0rk b0rk b0rk") >> }; >> >> Of course, in this particular example, you'd probably just write >> >> let result = from_utf8(..).unwrap(); >> >> but the longer match form will work for other enums. >> >> -Kevin >> >> ___ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> > > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
That is pretty elegant. Le 22 déc. 2013 16:47, "Gábor Lehel" a écrit : > Using `match` works well enough, but if there's demand for a refutable > `let` which is lighter-weight, what about: > > let Some(result) = from_utf8(some_bytes) else fail!(); > > In other words, if the `let` pattern is refutable, you have to provide > something `else` with return type `!` as the alternative for when the `let` > fails to match. > > > (I could imagine that being generalized to any number of `else`s of which > only the last "returns `!`" (i.o.w. never returns), for example > > let Some(result) = from_utf8(some_bytes) else > from_utf8(some_other_bytes) else fail!(); > > and/or to allowing anything `else` which always matches, e.g. > > let Some(result) = from_utf8(some_bytes) else Some("default"); > > of which anything that "returns" `!` would be only a special case. But > these have progressively diminishing returns, and I'm merely mentioning, > not endorsing them.) > > > On Tue, Dec 17, 2013 at 9:11 PM, Kevin Ballard wrote: > >> On Dec 17, 2013, at 11:37 AM, Stefan Plantikow < >> stefan.planti...@gmail.com> wrote: >> >> Hi, >> >> Am 17.12.2013 um 20:10 schrieb Corey Richardson : >> >> On Tue, Dec 17, 2013 at 2:06 PM, Stefan Plantikow >> wrote: >> >> Hi, >> >> >> Am 09.12.2013 um 16:53 schrieb Damien Radtke : >> >> I have no idea if it would be feasible in the standard library, but >> wouldn't the ideal solution be having one function (e.g. from_utf8()) that >> could return two possible values, a bare result and an Option? Letting the >> compiler decide which version to use based on type inference like this: >> >>let result: ~str = from_utf8(...); >>let result: Option<~str> = from_utf8(...); >> >> Assuming both of them are passed invalid UTF8, then the first version >> would fail, but the second version would just return None. >> >> >> >> >> We already have pattern matching in `let` (the LHS is a pattern), but >> it's only for irrefutable patterns. IOW, `let` can never fail, and >> that's a very very useful property IMO. >> >> >> oh ok I haven’t kept up on the syntax then. Given the utility of >> destructuring bind for error handling, wouldn't it make sense to have a >> variant of let that can fail? >> >> Now syntax is a matter of practicality and taste but spontaneously this >> comes to mind: >> >>let opt Some(~result) = from_utf8(..) >> >> comes to mind. >> >> >> You can do it with a bit more verbosity, which I think is perfectly fine >> as it makes failure much more obvious. >> >> let result = match from_utf8(..) { >> Some(~result) => result, >> _ => fail!("b0rk b0rk b0rk") >> }; >> >> Of course, in this particular example, you'd probably just write >> >> let result = from_utf8(..).unwrap(); >> >> but the longer match form will work for other enums. >> >> -Kevin >> >> ___ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> >> > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Using `match` works well enough, but if there's demand for a refutable `let` which is lighter-weight, what about: let Some(result) = from_utf8(some_bytes) else fail!(); In other words, if the `let` pattern is refutable, you have to provide something `else` with return type `!` as the alternative for when the `let` fails to match. (I could imagine that being generalized to any number of `else`s of which only the last "returns `!`" (i.o.w. never returns), for example let Some(result) = from_utf8(some_bytes) else from_utf8(some_other_bytes) else fail!(); and/or to allowing anything `else` which always matches, e.g. let Some(result) = from_utf8(some_bytes) else Some("default"); of which anything that "returns" `!` would be only a special case. But these have progressively diminishing returns, and I'm merely mentioning, not endorsing them.) On Tue, Dec 17, 2013 at 9:11 PM, Kevin Ballard wrote: > On Dec 17, 2013, at 11:37 AM, Stefan Plantikow > wrote: > > Hi, > > Am 17.12.2013 um 20:10 schrieb Corey Richardson : > > On Tue, Dec 17, 2013 at 2:06 PM, Stefan Plantikow > wrote: > > Hi, > > > Am 09.12.2013 um 16:53 schrieb Damien Radtke : > > I have no idea if it would be feasible in the standard library, but > wouldn't the ideal solution be having one function (e.g. from_utf8()) that > could return two possible values, a bare result and an Option? Letting the > compiler decide which version to use based on type inference like this: > >let result: ~str = from_utf8(...); >let result: Option<~str> = from_utf8(...); > > Assuming both of them are passed invalid UTF8, then the first version > would fail, but the second version would just return None. > > > > > We already have pattern matching in `let` (the LHS is a pattern), but > it's only for irrefutable patterns. IOW, `let` can never fail, and > that's a very very useful property IMO. > > > oh ok I haven’t kept up on the syntax then. Given the utility of > destructuring bind for error handling, wouldn't it make sense to have a > variant of let that can fail? > > Now syntax is a matter of practicality and taste but spontaneously this > comes to mind: > >let opt Some(~result) = from_utf8(..) > > comes to mind. > > > You can do it with a bit more verbosity, which I think is perfectly fine > as it makes failure much more obvious. > > let result = match from_utf8(..) { > Some(~result) => result, > _ => fail!("b0rk b0rk b0rk") > }; > > Of course, in this particular example, you'd probably just write > > let result = from_utf8(..).unwrap(); > > but the longer match form will work for other enums. > > -Kevin > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Tue, Dec 17, 2013 at 2:06 PM, Stefan Plantikow wrote: > Hi, > > > Am 09.12.2013 um 16:53 schrieb Damien Radtke : > >> I have no idea if it would be feasible in the standard library, but wouldn't >> the ideal solution be having one function (e.g. from_utf8()) that could >> return two possible values, a bare result and an Option? Letting the >> compiler decide which version to use based on type inference like this: >> >> let result: ~str = from_utf8(...); >> let result: Option<~str> = from_utf8(...); >> >> Assuming both of them are passed invalid UTF8, then the first version would >> fail, but the second version would just return None. > > > If rust allowed pattern matching in let, this problem would go away: > > let Some(~result) = from_utf8(…); > > This would fail if from_utf8(..) would not return None. This solution has > several benefits: > > - The code clearly expresses intent (a result was expected and thus it should > fail if instead None is returned) > - Only one function is needed and that functions signature covers all > possible return cases > - This approach isn’t limited to Option and could very well also work with > Result. The generated error message could contain the value that was not > matched (and thus have more detailed error information). > - IMHO the required syntax change won't break existing code (?) > We already have pattern matching in `let` (the LHS is a pattern), but it's only for irrefutable patterns. IOW, `let` can never fail, and that's a very very useful property IMO. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Hi, Am 09.12.2013 um 16:53 schrieb Damien Radtke : > I have no idea if it would be feasible in the standard library, but wouldn't > the ideal solution be having one function (e.g. from_utf8()) that could > return two possible values, a bare result and an Option? Letting the compiler > decide which version to use based on type inference like this: > > let result: ~str = from_utf8(...); > let result: Option<~str> = from_utf8(...); > > Assuming both of them are passed invalid UTF8, then the first version would > fail, but the second version would just return None. If rust allowed pattern matching in let, this problem would go away: let Some(~result) = from_utf8(…); This would fail if from_utf8(..) would not return None. This solution has several benefits: - The code clearly expresses intent (a result was expected and thus it should fail if instead None is returned) - Only one function is needed and that functions signature covers all possible return cases - This approach isn’t limited to Option and could very well also work with Result. The generated error message could contain the value that was not matched (and thus have more detailed error information). - IMHO the required syntax change won't break existing code (?) Cheers, Stefan ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Hi, Am 17.12.2013 um 20:10 schrieb Corey Richardson : > On Tue, Dec 17, 2013 at 2:06 PM, Stefan Plantikow > wrote: >> Hi, >> >> >> Am 09.12.2013 um 16:53 schrieb Damien Radtke : >> >>> I have no idea if it would be feasible in the standard library, but >>> wouldn't the ideal solution be having one function (e.g. from_utf8()) that >>> could return two possible values, a bare result and an Option? Letting the >>> compiler decide which version to use based on type inference like this: >>> >>>let result: ~str = from_utf8(...); >>>let result: Option<~str> = from_utf8(...); >>> >>> Assuming both of them are passed invalid UTF8, then the first version would >>> fail, but the second version would just return None. >> >> > > We already have pattern matching in `let` (the LHS is a pattern), but > it's only for irrefutable patterns. IOW, `let` can never fail, and > that's a very very useful property IMO. oh ok I haven’t kept up on the syntax then. Given the utility of destructuring bind for error handling, wouldn't it make sense to have a variant of let that can fail? Now syntax is a matter of practicality and taste but spontaneously this comes to mind: let opt Some(~result) = from_utf8(..) comes to mind. Cheers, Stefan. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Dec 17, 2013, at 11:37 AM, Stefan Plantikow wrote: > Hi, > > Am 17.12.2013 um 20:10 schrieb Corey Richardson : > >> On Tue, Dec 17, 2013 at 2:06 PM, Stefan Plantikow >> wrote: >>> Hi, >>> >>> >>> Am 09.12.2013 um 16:53 schrieb Damien Radtke : >>> I have no idea if it would be feasible in the standard library, but wouldn't the ideal solution be having one function (e.g. from_utf8()) that could return two possible values, a bare result and an Option? Letting the compiler decide which version to use based on type inference like this: let result: ~str = from_utf8(...); let result: Option<~str> = from_utf8(...); Assuming both of them are passed invalid UTF8, then the first version would fail, but the second version would just return None. >>> >>> >> >> We already have pattern matching in `let` (the LHS is a pattern), but >> it's only for irrefutable patterns. IOW, `let` can never fail, and >> that's a very very useful property IMO. > > oh ok I haven’t kept up on the syntax then. Given the utility of > destructuring bind for error handling, wouldn't it make sense to have a > variant of let that can fail? > > Now syntax is a matter of practicality and taste but spontaneously this comes > to mind: > >let opt Some(~result) = from_utf8(..) > > comes to mind. You can do it with a bit more verbosity, which I think is perfectly fine as it makes failure much more obvious. let result = match from_utf8(..) { Some(~result) => result, _ => fail!("b0rk b0rk b0rk") }; Of course, in this particular example, you'd probably just write let result = from_utf8(..).unwrap(); but the longer match form will work for other enums. -Kevin smime.p7s Description: S/MIME cryptographic signature ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Mon, Dec 9, 2013 at 10:53 AM, Damien Radtke wrote: > I have no idea if it would be feasible in the standard library, but wouldn't > the ideal solution be having one function (e.g. from_utf8()) that could > return two possible values, a bare result and an Option? Letting the > compiler decide which version to use based on type inference like this: > > let result: ~str = from_utf8(...); > let result: Option<~str> = from_utf8(...); > > Assuming both of them are passed invalid UTF8, then the first version would > fail, but the second version would just return None. > > Again, I don't know if it's possible given the current implementation, but I > do think it would be helpful to have a picture of the ideal, and then decide > on whatever solution comes closest. > > As a side note, even if the standard library sticks with two variants for > each option function, I would prefer the default one return an Option and > have the variant fail on invalid input. Task failure at runtime is a nastier > surprise than an invalid type error at compile time, especially for new > users who aren't entirely sure of the difference. I think this is too complex and error prone. I don't see the problem with just using `Option` and then calling `get` (currently `unwrap`) when you want to ignore the possibility of failure. The compiler should be printing a failure stack trace but for now you can still get one with `gdb`. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Why not have it be an auto-implemented trait like Send or Freeze? On Mon, Dec 9, 2013 at 10:05 AM, Simon Sapin wrote: > On 09/12/2013 15:53, Damien Radtke wrote: > >> I have no idea if it would be feasible in the standard library, but >> wouldn't the ideal solution be having one function (e.g. from_utf8()) >> that could return two possible values, a bare result and an Option? >> Letting the compiler decide which version to use based on type inference >> like this: >> >> let result: ~str = from_utf8(...); >> let result: Option<~str> = from_utf8(...); >> >> Assuming both of them are passed invalid UTF8, then the first version >> would fail, but the second version would just return None. >> >> Again, I don't know if it's possible given the current implementation, >> but I do think it would be helpful to have a picture of the ideal, and >> then decide on whatever solution comes closest. >> > > It is possible to have a generic return value, see for example the > .collect() method of iterators. > > https://github.com/mozilla/rust/blob/4e0cb316fc980f00e1b74f3fdb7a84 > 2b540be280/src/libstd/iter.rs#L447 > > But it involves creating a trait, and implementing it for every supported > type. IMO it’s a lot more involved than what we would want for every > operation that may fail on invalid input. > > > > As a side note, even if the standard library sticks with two variants >> for each option function, I would prefer the default one return an >> Option and have the variant fail on invalid input. Task failure at >> runtime is a nastier surprise than an invalid type error at compile >> time, especially for new users who aren't entirely sure of the difference. >> > > -- > Simon Sapin > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
> > let result: ~str = from_utf8(...); > let result: Option<~str> = from_utf8(...); That was what I called "implicit unwrap". I however recommend ``let result = from_utf8(...)`` to be the unwrapped version (ie, result is ~str) Do you think it is possible to add this syntaxic sugar? fn any_function() -> Result<~str> { ... } // When called : let s = any_function(); // unwrap() is automatically called, s is a ~str let res = any_function?(); // unwrap is not called, res is a Result<~str> let res2: Result<~str> = any_function(); // unwrap is not called, res is a Result<~str> if res.is_ok() { let s2 = res.unwrap() } Or maybe a simpler version, but the semantic is reversed, where a?() means a().unwrap(): let res = any_function(); // unwrap is not called, res is a Result<~str> let s = any_function?(); // unwrap() is automatically called, s is a ~str - Gaetan 2013/12/9 Simon Sapin > On 09/12/2013 15:53, Damien Radtke wrote: > >> I have no idea if it would be feasible in the standard library, but >> wouldn't the ideal solution be having one function (e.g. from_utf8()) >> that could return two possible values, a bare result and an Option? >> Letting the compiler decide which version to use based on type inference >> like this: >> >> let result: ~str = from_utf8(...); >> let result: Option<~str> = from_utf8(...); >> >> Assuming both of them are passed invalid UTF8, then the first version >> would fail, but the second version would just return None. >> >> Again, I don't know if it's possible given the current implementation, >> but I do think it would be helpful to have a picture of the ideal, and >> then decide on whatever solution comes closest. >> > > It is possible to have a generic return value, see for example the > .collect() method of iterators. > > https://github.com/mozilla/rust/blob/4e0cb316fc980f00e1b74f3fdb7a84 > 2b540be280/src/libstd/iter.rs#L447 > > But it involves creating a trait, and implementing it for every supported > type. IMO it’s a lot more involved than what we would want for every > operation that may fail on invalid input. > > > > As a side note, even if the standard library sticks with two variants >> for each option function, I would prefer the default one return an >> Option and have the variant fail on invalid input. Task failure at >> runtime is a nastier surprise than an invalid type error at compile >> time, especially for new users who aren't entirely sure of the difference. >> > > -- > Simon Sapin > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 09/12/2013 15:53, Damien Radtke wrote: I have no idea if it would be feasible in the standard library, but wouldn't the ideal solution be having one function (e.g. from_utf8()) that could return two possible values, a bare result and an Option? Letting the compiler decide which version to use based on type inference like this: let result: ~str = from_utf8(...); let result: Option<~str> = from_utf8(...); Assuming both of them are passed invalid UTF8, then the first version would fail, but the second version would just return None. Again, I don't know if it's possible given the current implementation, but I do think it would be helpful to have a picture of the ideal, and then decide on whatever solution comes closest. It is possible to have a generic return value, see for example the .collect() method of iterators. https://github.com/mozilla/rust/blob/4e0cb316fc980f00e1b74f3fdb7a842b540be280/src/libstd/iter.rs#L447 But it involves creating a trait, and implementing it for every supported type. IMO it’s a lot more involved than what we would want for every operation that may fail on invalid input. As a side note, even if the standard library sticks with two variants for each option function, I would prefer the default one return an Option and have the variant fail on invalid input. Task failure at runtime is a nastier surprise than an invalid type error at compile time, especially for new users who aren't entirely sure of the difference. -- Simon Sapin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 12/09/2013 04:53 PM, Damien Radtke wrote: I have no idea if it would be feasible in the standard library, but wouldn't the ideal solution be having one function (e.g. from_utf8()) that could return two possible values, a bare result and an Option? Letting the compiler decide which version to use based on type inference like this: let result: ~str = from_utf8(...); let result: Option<~str> = from_utf8(...); Assuming both of them are passed invalid UTF8, then the first version would fail, but the second version would just return None. Again, I don't know if it's possible given the current implementation, but I do think it would be helpful to have a picture of the ideal, [...] This is indeed close to an ideal version ;-), isn't it? Denis ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
I have no idea if it would be feasible in the standard library, but wouldn't the ideal solution be having one function (e.g. from_utf8()) that could return two possible values, a bare result and an Option? Letting the compiler decide which version to use based on type inference like this: let result: ~str = from_utf8(...); let result: Option<~str> = from_utf8(...); Assuming both of them are passed invalid UTF8, then the first version would fail, but the second version would just return None. Again, I don't know if it's possible given the current implementation, but I do think it would be helpful to have a picture of the ideal, and then decide on whatever solution comes closest. As a side note, even if the standard library sticks with two variants for each option function, I would prefer the default one return an Option and have the variant fail on invalid input. Task failure at runtime is a nastier surprise than an invalid type error at compile time, especially for new users who aren't entirely sure of the difference. On Sun, Dec 8, 2013 at 11:58 AM, Carter Schonwald < carter.schonw...@gmail.com> wrote: > Such sugar would would use some sort of monad trait right? > > > On Sunday, December 8, 2013, Ziad Hatahet wrote: > >> On Sat, Dec 7, 2013 at 2:21 PM, Gábor Lehel wrote: >> >>> I do wonder whether it wouldn't make sense to add sugar for Option, at >>> least eventually. (`int?` at the type level is really nice, too... too bad >>> it doesn't play so well with Rust's sigils. Introducing the potential >>> confusion between `~?T` and `?~T` is probably a step too far.) >>> >> >> Wouldn't it be better to add something similar to Haskell's `do` instead >> of another sigil? >> >> >> -- >> Ziad >> >> > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Such sugar would would use some sort of monad trait right? On Sunday, December 8, 2013, Ziad Hatahet wrote: > On Sat, Dec 7, 2013 at 2:21 PM, Gábor Lehel > > > wrote: > >> I do wonder whether it wouldn't make sense to add sugar for Option, at >> least eventually. (`int?` at the type level is really nice, too... too bad >> it doesn't play so well with Rust's sigils. Introducing the potential >> confusion between `~?T` and `?~T` is probably a step too far.) >> > > Wouldn't it be better to add something similar to Haskell's `do` instead > of another sigil? > > > -- > Ziad > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Sun, Dec 8, 2013 at 10:26 AM, Ziad Hatahet wrote: > On Sat, Dec 7, 2013 at 2:21 PM, Gábor Lehel wrote: > >> I do wonder whether it wouldn't make sense to add sugar for Option, at >> least eventually. (`int?` at the type level is really nice, too... too bad >> it doesn't play so well with Rust's sigils. Introducing the potential >> confusion between `~?T` and `?~T` is probably a step too far.) >> > > Wouldn't it be better to add something similar to Haskell's `do` instead > of another sigil? > > ...that's basically what I was saying. > -- > Ziad > > -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Sat, Dec 7, 2013 at 2:21 PM, Gábor Lehel wrote: > I do wonder whether it wouldn't make sense to add sugar for Option, at > least eventually. (`int?` at the type level is really nice, too... too bad > it doesn't play so well with Rust's sigils. Introducing the potential > confusion between `~?T` and `?~T` is probably a step too far.) > Wouldn't it be better to add something similar to Haskell's `do` instead of another sigil? -- Ziad ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
C# is actually adding null-chaining syntax sugar as well: http://adamralph.com/2013/12/06/ndc-diary-day-3/?1 C# is a very sugar-happy language, and I think it's wise for Rust to be conservative on this front (much easier to add things later than to remove them), but given how pervasive it is, I do wonder whether it wouldn't make sense to add sugar for Option, at least eventually. (`int?` at the type level is really nice, too... too bad it doesn't play so well with Rust's sigils. Introducing the potential confusion between `~?T` and `?~T` is probably a step too far.) On Sat, Dec 7, 2013 at 2:14 AM, Huon Wilson wrote: > On 07/12/13 12:08, Jordi Boggiano wrote: > >> On Sat, Dec 7, 2013 at 2:01 AM, spir wrote: >> >>> On 12/07/2013 01:12 AM, Gaetan wrote: >>> I am in favor of two version of the api: from_str which has already done the unwrap, and a from_str_safe for instance that returns a Result or option. >>> This provides the important semantic information (that I've evoked at the >>> end end of a long earlier reply in this thread) of whether func failure >>> is >>> expected and belongs to the logic of the present app and we must deal >>> with >>> it, or not. >>> >>> But I'm still shared on this topic for finding it also annoying, like >>> Simon, >>> to have to duplicate whole catogories of such funcs (of which we cannot >>> know >>> in advance whther they'll fail or not), if only the interface as >>> apparently >>> proposed by Gaëtan. >>> >> Syntax sugar like this would be nice: >> >> let str = std::str::from_utf8("Parse this optimistically, and fail >> otherwise"); >> // str is a string or the task fails >> >> vs. >> >> let opt_str = std::str::from_utf?("Parse this if valid"); // note the >> question mark >> if opt_str.is_some() { } >> >> Problem is, this sounds scary to implement at the compiler level, if >> it's possible at all :) I am just throwing it out there for others to >> judge. >> >> Cheers >> >> > I personally think a better solution is something like Haskell's do > notation[1], where you can chain several computations that return > Option<..> such that if any intermediate one returns None, the later ones > are not evaluated and the whole expression returns None, which saves having > to call .get()/.unwrap()/.expect() a lot. > > This can work for types like Result too (in fact, the Haskell > implementation of `do` is sugar around some monad functions, so any monad > can be used there; we currently don't have the power to express the monad > typeclass/trait in Rust so the fully general form probably isn't possible > as a syntax extension yet, although a limited version is). > > > Huon > > [1]: http://en.wikibooks.org/wiki/Haskell/do_Notation > > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
I agree with this proposal. I also strongly agree with spir that we should distinguish programmer errors from legitimate result possibilities. A function should only fail directly if, were it to return a `None` or `Err`, the only reasonable the thing caller could do would be to fail itself. Somewhat formally, a function has a domain and a codomain, i.o.w. the possible input and output values which make sense. If the type used for the domain is "too big", and allows values which don't make sense in the context of the function, then this opens up the possibility that the programmer might mess up and nonetheless pass in one of those values. In this case the right thing is for the function to fail at runtime: there's not much else it could do. (This is the null argument / NullPointerException situation in many other languages.) The converse case is if the codomain is too small, and doesn't provide a way to represent all of the possible output values. For example, a search function might not have a way to say "not found". In this case the function might also want to fail. But in Rust's type system it's much, much, much easier to make types bigger than it is to make them smaller, so there's no excuse not to do so. This function should just return an Option. Of course, it's not always black and white, and what "makes sense" can depend on the situation. Sometimes if the container we pass to the search function doesn't contain the value we're searching for, then it's a bug. The programmer can always signal this by just calling unwrap() (which I agree should have a better name, if we can find one) or expect(). But I think it's also reasonable to add convenience functions if this would be the case often enough to make them worthwhile. But they should be clearly presented as "added convenience functions, which fail in [these cases]" and not as the default option. Haskell has a bunch of partial functions which do their equivalent of failing in their Prelude, such as `head :: [a] -> a`, and they've been regretting it ever since. IMHO, let's try to keep our functions total whenever we possibly can. On Fri, Dec 6, 2013 at 9:41 PM, Simon Sapin wrote: > We have some functions and methods such as [std::str::from_utf8](http:// > static.rust-lang.org/doc/master/std/str/fn.from_utf8.html) that may > succeed and give a result, or fail when the input is invalid. > > 1. Sometimes we assume the input is valid and don’t want to deal with the > error case. Task failure works nicely. > > 2. Sometimes we do want to do something different on invalid input, so > returning an `Option` works best. > > And so we end up with both `from_utf8` and `from_utf8`. This particular > case is worse because we also have `from_utf8_owned` and > `from_utf8_owned_opt`, to cover everything. > > Multiplying names like this is just not good design. I’d like to reduce > this pattern. > > Getting behavior 1. when you have 2. is easy: just call `.unwrap()` on the > Option. I think we should rename every `foo_opt()` function or method to > just `foo`, remove the old `foo()` behavior, and tell people (through > documentation) to use `foo().unwrap()` if they want it back? > > The downsides are that unwrap is more verbose and gives less helpful error > messages on task failure. But I think it’s worth it. > > What do you think? > > (PS: I’m guilty of making this worse in #10828, but I’d like to discuss > this before sending pull requests with invasive API changes.) > > -- > Simon Sapin > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 12/07/2013 12:57 PM, Devin Jeanpierre wrote: On Sat, Dec 7, 2013 at 3:33 AM, spir wrote: But the issue exists anyway... dunno about solution. In fact we'd ned to invert the logic: instead of: x = foo() // Option element wrapping possible result x = foo().unwrap() // bare result think: x = foo().option() // Option element wrapping possible result x = foo().direct() // bare result In what way is this better? Seems to me it's a basically functionless layer of abstraction, and things that don't always have a usable result should always return option, and if you want them to fail, you can request failure via .unwrap(). If this is too verbose, then we should make it less verbose, e.g. `x = *foo()` or something. Or we can keep the status quo, which seems fine to me. I'm not really picky about verbosity. Possibly it's clear for you if you are used to the Option workaround, from other languages (I have been, in fact, from Ocaml). But with this solution the code does not say what it means (lol!), not to speak of idioms repeted everywhere in source as evoked by Gaetan (and similar to Java, in fact (lol bis!)). However, in my view, this is not a question of verbosity, but of having source code match (sic!) the semantics, what we actually mean. A solution would be to have such functions return either a bare result, or an Option wrapping a possible result, depending on how they are called (instead of '?', there may be a bool param, why not?). But not a functional either/or, this would doubly wrap the result! Instead really either one or the other. Indeed, this is not possible in standard in a statically typed language, reason for other solutions, such as one evoked in a previous mail: have an 'anomaly' flag somewhere, possibly a bare pointer for error data, and minimal syntactic support. In fact, simple error management (I don't mean exception handling) may require being taken into account in language design righ from the start, even more than testing & debugging, for instance; but all 3 of those "meta-programming" dimensions are related anyway. Denis ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
What do you think about implicit unwrap? I don't know if this could be done but I find it pretty elegant. It's a design choice. For me all API should follow the same pattern, not some returning bare result without failure case, or return a boolean and modify the content of a pointer, or use Result/Option. Most of function look like thing - function definition - check inputs are correct - process with inputs - return a value Most of std/extra methods currently look like: 1 function def 2 ... .unwrap()...unwrap() 3 continue to unwrap(), unwrap() 4 return Ok(...) or Err(..) or return Option while unwrap in part 2 may have sense (check if inputs are correct), they don't have in the third part of the fn. What I really advise is to go to a solution where the developer will avoid each time to call unwrap/get, without checking for the return state because it cost too much. When you call a system api you check for the result because it has great chance to fail, but when you know what you have in input, you call unwrap() without taking care of the failure cases, and if a failure occurs, you can expect things to be in suffisant bad shape to let the task completely fails. Maybe split the methods into two categories: API calls that may fails and return a Result, and obvious convert methods that has no sens to fails once the input has been properly check, so doesn't use Result. But at the end of this discussion, I also strongly advise to write the solution down in a reference page on the wiki, having the current "state of the art" for this matter is extremely important, because the source code has different design choices, with this page everyone will know what is the current best pratice for such function calls. PS: I really like the "?" solution, where func?() returns a Result and func() return the bare result, I find it in the same spirit than fmt!, that makes the language special but in a sexy way :) - Gaetan 2013/12/7 spir > On 12/07/2013 10:53 AM, Simon Sapin wrote: > >> On 07/12/2013 01:07, spir wrote: >> >>> Maybe it's only me, but this not at at all clear to my eyes. My imagined >>> soluton >>> (for a totally different lang) was something like this, on the caller >>> side: >>> >>> ucodes = s.utf8_decode()!// source should be correct, error on >>> failure >>> ucodes = s.utf8_decode()?// logical failure expected, return >>> None or >>> whatnot >>> >> >> >> This is interesting, but I’d like to discuss what to do in this particular >> language, Rust that is trying to go to 1.0 and will probably not accept >> such >> syntax change :) >> > > > You are right, indeed! ;-) > But the issue exists anyway... dunno about solution. In fact we'd ned to > invert the logic: instead of: > x = foo() // Option element wrapping possible result > x = foo().unwrap() // bare result > think: > x = foo().option() // Option element wrapping possible result > x = foo().direct() // bare result > or even > x = foo() // bare result > > Denis > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Sat, Dec 7, 2013 at 3:33 AM, spir wrote: > But the issue exists anyway... dunno about solution. In fact we'd ned to > invert the logic: instead of: > x = foo() // Option element wrapping possible result > x = foo().unwrap() // bare result > think: > x = foo().option() // Option element wrapping possible result > x = foo().direct() // bare result In what way is this better? Seems to me it's a basically functionless layer of abstraction, and things that don't always have a usable result should always return option, and if you want them to fail, you can request failure via .unwrap(). If this is too verbose, then we should make it less verbose, e.g. `x = *foo()` or something. Or we can keep the status quo, which seems fine to me. I'm not really picky about verbosity. -- Devin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 12/07/2013 02:08 AM, Jordi Boggiano wrote: On Sat, Dec 7, 2013 at 2:01 AM, spir wrote: On 12/07/2013 01:12 AM, Gaetan wrote: I am in favor of two version of the api: from_str which has already done the unwrap, and a from_str_safe for instance that returns a Result or option. This provides the important semantic information (that I've evoked at the end end of a long earlier reply in this thread) of whether func failure is expected and belongs to the logic of the present app and we must deal with it, or not. But I'm still shared on this topic for finding it also annoying, like Simon, to have to duplicate whole catogories of such funcs (of which we cannot know in advance whther they'll fail or not), if only the interface as apparently proposed by Gaëtan. Syntax sugar like this would be nice: let str = std::str::from_utf8("Parse this optimistically, and fail otherwise"); // str is a string or the task fails vs. let opt_str = std::str::from_utf?("Parse this if valid"); // note the question mark if opt_str.is_some() { } That's it! This makes it clear whenever the anomalous case nevertheless belongs to the present application's logic (hopefully rare). Problem is, this sounds scary to implement at the compiler level, if it's possible at all :) I am just throwing it out there for others to judge. Yes. Requires certainly a bit of machinary, even if thought so from the beginning. But optional tasks exist, semantically, whether the language acknowledges them or not. And an Option type only solves half of the issues: namely the ones of functions properly speaking (which compute a value); what about actions (which perform an effect)? How can Option help the caller know, without failing (halting the program on error), whether one has been unable to perform its task? How can one know whether this data structure was properly updated, this visual object moved, this msg given to the user, this file extended, renamed, deleted...? There are also, semantically, optional data in function def input and type defs... very annoying in a statically typed language ;-) Denis ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 12/07/2013 10:53 AM, Simon Sapin wrote: On 07/12/2013 01:07, spir wrote: Maybe it's only me, but this not at at all clear to my eyes. My imagined soluton (for a totally different lang) was something like this, on the caller side: ucodes = s.utf8_decode()!// source should be correct, error on failure ucodes = s.utf8_decode()?// logical failure expected, return None or whatnot This is interesting, but I’d like to discuss what to do in this particular language, Rust that is trying to go to 1.0 and will probably not accept such syntax change :) You are right, indeed! ;-) But the issue exists anyway... dunno about solution. In fact we'd ned to invert the logic: instead of: x = foo() // Option element wrapping possible result x = foo().unwrap() // bare result think: x = foo().option() // Option element wrapping possible result x = foo().direct() // bare result or even x = foo() // bare result Denis ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 12/07/2013 02:14 AM, Jordi Boggiano wrote: On Sat, Dec 7, 2013 at 2:07 AM, spir wrote: Maybe it's only me, but this not at at all clear to my eyes. My imagined soluton (for a totally different lang) was something like this, on the caller side: ucodes = s.utf8_decode()! // source should be correct, error on failure ucodes = s.utf8_decode()? // logical failure expected, return None or whatnot (But maybe _this_ is obscure to your eyes?) Looks like our mails had a race condition on this one, but highlighting the cases where we expect a perfect world (i.e. !) is probably better. However, if you just call the method without anything it would be the same as calling it with ? suffix as far as I understand, so I'm not sure what the point is of keeping that one. This is because you think in terms of Option, taking it for granted as if it were natural (thinking); "call the method without anything" here returns an Option element, thus (for you) the case '?' is doing nothing (more). In fact, from the point of view of a caller wanting an actual result, barely, the '?' case wraps it into an Option "box", while the '!' is the one doing nothing... Clear? Another way of doing that is having a transparent 'none' flag (or more generally 'failure' or 'naomaly') somewhere. In '!' case, an eventual anomaly during func exec causes the program to stop on error. In '?' case, it sets this flag, which then to be tested by the caller. The signs '!' '?' thus parameterise the behaviour of (possibly failing) called funcs in anomalous cases. There is an implementation of light exception handling for C (in ASM in fact) that sets the carry flag that way (carry, because it is meaningless in-between funcs, and is the only CPU flag set-able at will). Denis ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 07/12/13 20:55, Simon Sapin wrote: On 07/12/2013 01:14, Huon Wilson wrote: I personally think a better solution is something like Haskell's do notation[1], where you can chain several computations that return Option<..> such that if any intermediate one returns None, the later ones are not evaluated and the whole expression returns None, which saves having to call .get()/.unwrap()/.expect() a lot. We have that, it’s Option’s .and_then() method. This can work for types like Result too (in fact, the Haskell implementation of `do` is sugar around some monad functions, so any monad can be used there; we currently don't have the power to express the monad typeclass/trait in Rust so the fully general form probably isn't possible as a syntax extension yet, although a limited version is). Yes, that's what my syntax extension[1] (to which Ziad alludes) desugared to (well, the former name, .chain). However, even something simple like `foo.and_then(|x| bar.and_then(|y| baz.map(|z| x + y + z)))` is significantly worse than do x <- foo y <- bar z <- baz return $ x + y + z as it is in Haskell. And more complicated examples with additional within the closures are significantly worse for the .and_then form (leading to pyramids of doom, and Rust already has enough of those). Huon [1]: https://mail.mozilla.org/pipermail/rust-dev/2013-May/004182.html ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 07/12/2013 01:14, Huon Wilson wrote: I personally think a better solution is something like Haskell's do notation[1], where you can chain several computations that return Option<..> such that if any intermediate one returns None, the later ones are not evaluated and the whole expression returns None, which saves having to call .get()/.unwrap()/.expect() a lot. We have that, it’s Option’s .and_then() method. This can work for types like Result too (in fact, the Haskell implementation of `do` is sugar around some monad functions, so any monad can be used there; we currently don't have the power to express the monad typeclass/trait in Rust so the fully general form probably isn't possible as a syntax extension yet, although a limited version is). -- Simon Sapin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 07/12/2013 01:07, spir wrote: Maybe it's only me, but this not at at all clear to my eyes. My imagined soluton (for a totally different lang) was something like this, on the caller side: ucodes = s.utf8_decode()! // source should be correct, error on failure ucodes = s.utf8_decode()? // logical failure expected, return None or whatnot This is interesting, but I’d like to discuss what to do in this particular language, Rust that is trying to go to 1.0 and will probably not accept such syntax change :) -- Simon Sapin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Especially if Result is optimized into a single word, it seems ideal to me to get rid of str::from_utf_opt(&[u8]) -> Option<~str> and just have str::from_utf(&[u8]) -> Result<~str, ()>. This makes simple programs that don't care about error handling a little more complicated, of course, since it forces them to handle the error case. Although, the only extra complication is ".unwrap()" so, its not that bad. For more complex programs that do care about error handling it makes it explicit at the call site how the error condition should be handled which I think is a big win. Return code checking is a C idiom, and there is nothing wrong with that style of error handling. However, the C compiler doesn't do much of anything to force you to check the return codes which leads to lots of code that fails to do so. Using a Result<>, however, forces the caller to do those checks. Result<> still supports various chaining functions just like Option<> to make that easier. However, you don't have to worry about accidentally passing a None to a function that takes an Option<> as an input parameter with non-error semantics. Also, I like "unwrap()" since to me, nothing about "get()" says: this is an error handling function that might lead to killing the current task. get() sounds simple and safe, buts its not if called on an Option<>. -Palmer Cox On Fri, Dec 6, 2013 at 11:14 PM, Patrick Walton wrote: > On 12/6/13 6:46 PM, Niko Matsakis wrote: > >> I agree. I've personally been moving towards `Result` in >> preference to `Option` when one of the branches reflects an >> error. It's worth noting that the compiler could still optimize this >> into a pointer-null-pointer representation, though I doubt it does so >> now. >> > > IIRC it does. > > Patrick > > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
There was a whole thread about the need for once-stack-closures. They are really vital for simple programming with higher-order functions such as these. I'm not optimistic about them being added though :-( On Sat, Dec 7, 2013 at 8:15 AM, Brendan Zabarauskas wrote: > > On 7 Dec 2013, at 10:47 am, Simon Sapin wrote: > > > This is why we have methods like .map() and .and_then() > > I like using these higher order functions, but I run into lots of issues > with moved values because we don’t have once functions. I end up having to > use matches, which are awfully verbose for simple things. :( > > ~Brendan > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 7 Dec 2013, at 10:47 am, Simon Sapin wrote: > This is why we have methods like .map() and .and_then() I like using these higher order functions, but I run into lots of issues with moved values because we don’t have once functions. I end up having to use matches, which are awfully verbose for simple things. :( ~Brendan ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 12/6/13 6:46 PM, Niko Matsakis wrote: I agree. I've personally been moving towards `Result` in preference to `Option` when one of the branches reflects an error. It's worth noting that the compiler could still optimize this into a pointer-null-pointer representation, though I doubt it does so now. IIRC it does. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
I posted a question on the mailing list concerning this back in May: https://mail.mozilla.org/pipermail/rust-dev/2013-May/004176.html There were a couple of responses which implemented this in a macro. It would be nice if it were at the language level though. -- Ziad On Fri, Dec 6, 2013 at 5:14 PM, Huon Wilson wrote: > On 07/12/13 12:08, Jordi Boggiano wrote: > >> On Sat, Dec 7, 2013 at 2:01 AM, spir wrote: >> >>> On 12/07/2013 01:12 AM, Gaetan wrote: >>> I am in favor of two version of the api: from_str which has already done the unwrap, and a from_str_safe for instance that returns a Result or option. >>> This provides the important semantic information (that I've evoked at the >>> end end of a long earlier reply in this thread) of whether func failure >>> is >>> expected and belongs to the logic of the present app and we must deal >>> with >>> it, or not. >>> >>> But I'm still shared on this topic for finding it also annoying, like >>> Simon, >>> to have to duplicate whole catogories of such funcs (of which we cannot >>> know >>> in advance whther they'll fail or not), if only the interface as >>> apparently >>> proposed by Gaëtan. >>> >> Syntax sugar like this would be nice: >> >> let str = std::str::from_utf8("Parse this optimistically, and fail >> otherwise"); >> // str is a string or the task fails >> >> vs. >> >> let opt_str = std::str::from_utf?("Parse this if valid"); // note the >> question mark >> if opt_str.is_some() { } >> >> Problem is, this sounds scary to implement at the compiler level, if >> it's possible at all :) I am just throwing it out there for others to >> judge. >> >> Cheers >> >> > I personally think a better solution is something like Haskell's do > notation[1], where you can chain several computations that return > Option<..> such that if any intermediate one returns None, the later ones > are not evaluated and the whole expression returns None, which saves having > to call .get()/.unwrap()/.expect() a lot. > > This can work for types like Result too (in fact, the Haskell > implementation of `do` is sugar around some monad functions, so any monad > can be used there; we currently don't have the power to express the monad > typeclass/trait in Rust so the fully general form probably isn't possible > as a syntax extension yet, although a limited version is). > > > Huon > > [1]: http://en.wikibooks.org/wiki/Haskell/do_Notation > > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Fri, Dec 06, 2013 at 07:00:53PM -0500, Palmer Cox wrote: > Why not use Result instead of Option for these types of things? I agree. I've personally been moving towards `Result` in preference to `Option` when one of the branches reflects an error. It's worth noting that the compiler could still optimize this into a pointer-null-pointer representation, though I doubt it does so now. Niko ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Is do-notation in Haskell similar as: try{ block } ? 2013/12/7 Huon Wilson > On 07/12/13 12:08, Jordi Boggiano wrote: > >> On Sat, Dec 7, 2013 at 2:01 AM, spir wrote: >> >>> On 12/07/2013 01:12 AM, Gaetan wrote: >>> I am in favor of two version of the api: from_str which has already done the unwrap, and a from_str_safe for instance that returns a Result or option. >>> This provides the important semantic information (that I've evoked at the >>> end end of a long earlier reply in this thread) of whether func failure >>> is >>> expected and belongs to the logic of the present app and we must deal >>> with >>> it, or not. >>> >>> But I'm still shared on this topic for finding it also annoying, like >>> Simon, >>> to have to duplicate whole catogories of such funcs (of which we cannot >>> know >>> in advance whther they'll fail or not), if only the interface as >>> apparently >>> proposed by Gaëtan. >>> >> Syntax sugar like this would be nice: >> >> let str = std::str::from_utf8("Parse this optimistically, and fail >> otherwise"); >> // str is a string or the task fails >> >> vs. >> >> let opt_str = std::str::from_utf?("Parse this if valid"); // note the >> question mark >> if opt_str.is_some() { } >> >> Problem is, this sounds scary to implement at the compiler level, if >> it's possible at all :) I am just throwing it out there for others to >> judge. >> >> Cheers >> >> > I personally think a better solution is something like Haskell's do > notation[1], where you can chain several computations that return > Option<..> such that if any intermediate one returns None, the later ones > are not evaluated and the whole expression returns None, which saves having > to call .get()/.unwrap()/.expect() a lot. > > This can work for types like Result too (in fact, the Haskell > implementation of `do` is sugar around some monad functions, so any monad > can be used there; we currently don't have the power to express the monad > typeclass/trait in Rust so the fully general form probably isn't possible > as a syntax extension yet, although a limited version is). > > > Huon > > [1]: http://en.wikibooks.org/wiki/Haskell/do_Notation > > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- by *Liigo*, http://blog.csdn.net/liigo/ Google+ https://plus.google.com/105597640837742873343/ ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Sat, Dec 7, 2013 at 2:07 AM, spir wrote: > Maybe it's only me, but this not at at all clear to my eyes. My imagined > soluton (for a totally different lang) was something like this, on the > caller side: > > ucodes = s.utf8_decode()! // source should be correct, error > on failure > ucodes = s.utf8_decode()? // logical failure expected, return > None or whatnot > > (But maybe _this_ is obscure to your eyes?) Looks like our mails had a race condition on this one, but highlighting the cases where we expect a perfect world (i.e. !) is probably better. However, if you just call the method without anything it would be the same as calling it with ? suffix as far as I understand, so I'm not sure what the point is of keeping that one. Cheers -- Jordi Boggiano @seldaek - http://nelm.io/jordi ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 07/12/13 12:08, Jordi Boggiano wrote: On Sat, Dec 7, 2013 at 2:01 AM, spir wrote: On 12/07/2013 01:12 AM, Gaetan wrote: I am in favor of two version of the api: from_str which has already done the unwrap, and a from_str_safe for instance that returns a Result or option. This provides the important semantic information (that I've evoked at the end end of a long earlier reply in this thread) of whether func failure is expected and belongs to the logic of the present app and we must deal with it, or not. But I'm still shared on this topic for finding it also annoying, like Simon, to have to duplicate whole catogories of such funcs (of which we cannot know in advance whther they'll fail or not), if only the interface as apparently proposed by Gaëtan. Syntax sugar like this would be nice: let str = std::str::from_utf8("Parse this optimistically, and fail otherwise"); // str is a string or the task fails vs. let opt_str = std::str::from_utf?("Parse this if valid"); // note the question mark if opt_str.is_some() { } Problem is, this sounds scary to implement at the compiler level, if it's possible at all :) I am just throwing it out there for others to judge. Cheers I personally think a better solution is something like Haskell's do notation[1], where you can chain several computations that return Option<..> such that if any intermediate one returns None, the later ones are not evaluated and the whole expression returns None, which saves having to call .get()/.unwrap()/.expect() a lot. This can work for types like Result too (in fact, the Haskell implementation of `do` is sugar around some monad functions, so any monad can be used there; we currently don't have the power to express the monad typeclass/trait in Rust so the fully general form probably isn't possible as a syntax extension yet, although a limited version is). Huon [1]: http://en.wikibooks.org/wiki/Haskell/do_Notation ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Sat, Dec 7, 2013 at 2:01 AM, spir wrote: > On 12/07/2013 01:12 AM, Gaetan wrote: >> >> I am in favor of two version of the api: from_str which has already done >> the unwrap, and a from_str_safe for instance that returns a Result or >> option. > > This provides the important semantic information (that I've evoked at the > end end of a long earlier reply in this thread) of whether func failure is > expected and belongs to the logic of the present app and we must deal with > it, or not. > > But I'm still shared on this topic for finding it also annoying, like Simon, > to have to duplicate whole catogories of such funcs (of which we cannot know > in advance whther they'll fail or not), if only the interface as apparently > proposed by Gaëtan. Syntax sugar like this would be nice: let str = std::str::from_utf8("Parse this optimistically, and fail otherwise"); // str is a string or the task fails vs. let opt_str = std::str::from_utf?("Parse this if valid"); // note the question mark if opt_str.is_some() { } Problem is, this sounds scary to implement at the compiler level, if it's possible at all :) I am just throwing it out there for others to judge. Cheers -- Jordi Boggiano @seldaek - http://nelm.io/jordi ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 12/07/2013 01:55 AM, Simon Sapin wrote: On 07/12/2013 00:49, spir wrote: About the latter, in particular it should be obvious in code, without knowledge of language arcanes or weird idioms, that (or whether) the caller expects a success unconditionally -- because (and in other words that) the anomalous case just does not belong to this app; this is critical information to the reader. How to do that right? If my proposal is accepted (returning Option is favored), then calling .unwrap() is the way to express that success is expected. unwrap() causes task failure when called with None. Maybe it's only me, but this not at at all clear to my eyes. My imagined soluton (for a totally different lang) was something like this, on the caller side: ucodes = s.utf8_decode()! // source should be correct, error on failure ucodes = s.utf8_decode()? // logical failure expected, return None or whatnot (But maybe _this_ is obscure to your eyes?) Denis ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 12/07/2013 01:12 AM, Gaetan wrote: I am in favor of two version of the api: from_str which has already done the unwrap, and a from_str_safe for instance that returns a Result or option. This provides the important semantic information (that I've evoked at the end end of a long earlier reply in this thread) of whether func failure is expected and belongs to the logic of the present app and we must deal with it, or not. But I'm still shared on this topic for finding it also annoying, like Simon, to have to duplicate whole catogories of such funcs (of which we cannot know in advance whther they'll fail or not), if only the interface as apparently proposed by Gaëtan. Denis ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 07/12/2013 00:49, spir wrote: About the latter, in particular it should be obvious in code, without knowledge of language arcanes or weird idioms, that (or whether) the caller expects a success unconditionally -- because (and in other words that) the anomalous case just does not belong to this app; this is critical information to the reader. How to do that right? If my proposal is accepted (returning Option is favored), then calling .unwrap() is the way to express that success is expected. unwrap() causes task failure when called with None. -- Simon Sapin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 12/06/2013 09:41 PM, Simon Sapin wrote: We have some functions and methods such as [std::str::from_utf8](http://static.rust-lang.org/doc/master/std/str/fn.from_utf8.html) that may succeed and give a result, or fail when the input is invalid. 1. Sometimes we assume the input is valid and don’t want to deal with the error case. Task failure works nicely. 2. Sometimes we do want to do something different on invalid input, so returning an `Option` works best. And so we end up with both `from_utf8` and `from_utf8`. This particular case is worse because we also have `from_utf8_owned` and `from_utf8_owned_opt`, to cover everything. Multiplying names like this is just not good design. I’d like to reduce this pattern. Getting behavior 1. when you have 2. is easy: just call `.unwrap()` on the Option. I think we should rename every `foo_opt()` function or method to just `foo`, remove the old `foo()` behavior, and tell people (through documentation) to use `foo().unwrap()` if they want it back? The downsides are that unwrap is more verbose and gives less helpful error messages on task failure. But I think it’s worth it. What do you think? (PS: I’m guilty of making this worse in #10828, but I’d like to discuss this before sending pull requests with invasive API changes.) [A bit long, sorry, this is a topic about which i have thought for a while.] There may be a more complicated general pattern, of all kinds of functions that may not be able to perform their nominal task, due to invalid input, but the client cannot know whether the input is valid without more or less reproducing said task. Checking utf8 validity is about the same job as decoding, for instance, to reuse your example. Compare with a function computing the average value of a collection of numbers (or the sum, product, std-dev, etc...) which is passed an empty collection: here the client can know, thus: 1. if this abnormal case does not belong to the app's logic, the client should just call the func stupidly so that the func failure is a signal of logical error on the app side 2. if instead this case belongs to the app's logic, the client should first check, and never call the func in this special case Thus, despite very possible failure, there should here be only one version of the func (no *_opt), one that stupidly fails, with a stupid error msg. Back to the cases where the client cannot know before calling. To this category belong a whole series of search/find functions, and many dealing with the file system, user input, input in general. In the latter case, a func's input is in fact not (all) provided by the client. But there is the same pattern of anomalous cases which may, or not, belong to the app logic (1. or 2. above): is it correct (if special or exceptional) that such file does not exist, or such collection does not hold the searched item? Meaning, should I deal with such cases? If not, if such a case does not belong to the application logic, again I should stupidly call a func that stupidly fails with a stupid error msg, so I am told, simply and early, of my logical errors. These are true errors (not so-called exceptions), and the failure is a symptom or signal, a good thing (if, indeed, what you want is making good software). I *want* it; and want it so! I'm in favor of simple funcs doing simple tasks simply, and just failing in anomalous cases, for these reasons. [1] Remains the situation combined of such funcs, of which the client cannot know whether they will be able to perform their task, and of abnormal cases belonging to the logic of the app (there are also whole categories of maintenance and safety modes here). For such situations, it looks somewhat logical to have 2 versions, I guess. Playing a bit with words: 1. when I ask to _find_ something, I take it for granted the thing is somewhere there, and expect a location in return 2. when I ask to _search_ something, I do not take anything for granted, and expect in return _either_ "not there!" or a location This duality applies both to the so-called real world (despite blur natural language word meanings) and software worlds, and extends to all cases, it seems. We can certainly find a way, using Option or another mean, to combine both categories of situations (1. or 2.) using a single tool, but this should be very well done, and ensure that: * In cases of category 1., developers are warned about their errors exactly as if they had called a stupidly failing func. * At the semantic (conceptual) level, the duality of categories remains somehow preserved, including in source code. About the latter, in particular it should be obvious in code, without knowledge of language arcanes or weird idioms, that (or whether) the caller expects a success unconditionally -- because (and in other words that) the anomalous case just does not belong to this app; this is critical information to the reader. How to do that right? PS: I take the oppor
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 07/12/2013 00:12, Gaetan wrote: I am in favor of two version of the api: from_str which has already done the unwrap, and a from_str_safe for instance that returns a Result or option. This is what we have now. (Eg. from_utf8() and from_utf8_opt()) The point of my initial email was to argue against this. I think we should try to avoid doubling the amount of API. Or perhaps allow the propagation of Option/Result. This is why we have methods like .map() and .and_then() -- Simon Sapin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Isnt a way for Option to unwrap implicitely when check on error state is not done ? That would make the code less verbose but still allow the dev to check for error if want? Le 7 déc. 2013 01:12, "Gaetan" a écrit : > I also find the repeatition of unwrap all over the code being quite nasty > > Most of the time the result is just unwrapped without taking into account > the error case, so i think the usage of Option or Result useless. > > I think a good solution exits and can make the code more maintainable, and > easier to read. There should not have all these unwrap (or get) call for > code we know it cannot fails, because the necessary check has been done > earlier. > > I am in favor of two version of the api: from_str which has already done > the unwrap, and a from_str_safe for instance that returns a Result or > option. > > Or perhaps allow the propagation of Option/Result. > Le 7 déc. 2013 01:03, "Daniel Micay" a écrit : > >> On Fri, Dec 6, 2013 at 7:00 PM, Palmer Cox wrote: >> > Why not use Result instead of Option for these types of things? Result >> is >> > already defined to be able to return error codes using Err. The only >> way to >> > indicate an error when returning an Option is to return None which >> doesn't >> > allow for that. Also, IMO, None doesn't necessarily mean "error" to me. >> Lets >> > say we have a function defined as: >> > >> > fn do_something(value: Option<~str>); >> > >> > It seems like it would be much to easy to accidentally write something >> like: >> > do_something(str::from_utf8(...)) which might result in the error being >> > hidden since do_something might not consider None to be an error input. >> > >> > -Palmer Cox >> >> If there's only one reason it could fail, then `Option` is the >> idiomatic way to report the error case. It's exactly what `Option` is >> used for. A stack trace can report where the error occurred if you >> decide to ignore the error case and use `unwrap` (or `get`, if it's >> renamed). >> ___ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
I also find the repeatition of unwrap all over the code being quite nasty Most of the time the result is just unwrapped without taking into account the error case, so i think the usage of Option or Result useless. I think a good solution exits and can make the code more maintainable, and easier to read. There should not have all these unwrap (or get) call for code we know it cannot fails, because the necessary check has been done earlier. I am in favor of two version of the api: from_str which has already done the unwrap, and a from_str_safe for instance that returns a Result or option. Or perhaps allow the propagation of Option/Result. Le 7 déc. 2013 01:03, "Daniel Micay" a écrit : > On Fri, Dec 6, 2013 at 7:00 PM, Palmer Cox wrote: > > Why not use Result instead of Option for these types of things? Result is > > already defined to be able to return error codes using Err. The only way > to > > indicate an error when returning an Option is to return None which > doesn't > > allow for that. Also, IMO, None doesn't necessarily mean "error" to me. > Lets > > say we have a function defined as: > > > > fn do_something(value: Option<~str>); > > > > It seems like it would be much to easy to accidentally write something > like: > > do_something(str::from_utf8(...)) which might result in the error being > > hidden since do_something might not consider None to be an error input. > > > > -Palmer Cox > > If there's only one reason it could fail, then `Option` is the > idiomatic way to report the error case. It's exactly what `Option` is > used for. A stack trace can report where the error occurred if you > decide to ignore the error case and use `unwrap` (or `get`, if it's > renamed). > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Fri, Dec 6, 2013 at 7:00 PM, Palmer Cox wrote: > Why not use Result instead of Option for these types of things? Result is > already defined to be able to return error codes using Err. The only way to > indicate an error when returning an Option is to return None which doesn't > allow for that. Also, IMO, None doesn't necessarily mean "error" to me. Lets > say we have a function defined as: > > fn do_something(value: Option<~str>); > > It seems like it would be much to easy to accidentally write something like: > do_something(str::from_utf8(...)) which might result in the error being > hidden since do_something might not consider None to be an error input. > > -Palmer Cox If there's only one reason it could fail, then `Option` is the idiomatic way to report the error case. It's exactly what `Option` is used for. A stack trace can report where the error occurred if you decide to ignore the error case and use `unwrap` (or `get`, if it's renamed). ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Why not use Result instead of Option for these types of things? Result is already defined to be able to return error codes using Err. The only way to indicate an error when returning an Option is to return None which doesn't allow for that. Also, IMO, None doesn't necessarily mean "error" to me. Lets say we have a function defined as: fn do_something(value: Option<~str>); It seems like it would be much to easy to accidentally write something like: do_something(str::from_utf8(...)) which might result in the error being hidden since do_something might not consider None to be an error input. -Palmer Cox On Fri, Dec 6, 2013 at 4:52 PM, Simon Sapin wrote: > On 06/12/2013 21:50, Eric Reed wrote: > >> Personally, I prefer making functions that don't fail and use Option or >> Result and then composing them with functions that fail for certain >> outputs, but I think I'm in the minority there. >> > > Yes, this is what I’m suggesting. > > > -- > Simon Sapin > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 06/12/2013 21:50, Eric Reed wrote: Personally, I prefer making functions that don't fail and use Option or Result and then composing them with functions that fail for certain outputs, but I think I'm in the minority there. Yes, this is what I’m suggesting. -- Simon Sapin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 06/12/2013 21:44, Brian Anderson wrote: I agree in this case (and probably a lot of cases), especially since this is a relatively uncommon operation and since (I think) we're prefering 'get' to 'unwrap' and that's even shorter. There are some cases where I think failure is the right option by default though; in particular I was worried you were going to bring up the 'send' and 'recv' methods on channels which fail when disconnected. In this case I think it won't be common to handle the failure since it indicates some logic error, and these are very common operations. Maybe this should be a case-by-case decision, but send/try_send and recv/try_recv have the same issue as from_utf8/from_utf8_opt of two slightly different names for almost the same thing. -- Simon Sapin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
FYI, there's already a method on Option that is unwrap() with an error message: expect(). Personally, I prefer making functions that don't fail and use Option or Result and then composing them with functions that fail for certain outputs, but I think I'm in the minority there. On Fri, Dec 6, 2013 at 1:45 PM, Simon Sapin wrote: > On 06/12/2013 20:55, Léo Testard wrote: > >> Hi, >> >> Just a suggestion, don't know what it's worth... >> >> For the "not helpful error message" thing, couldn't we extend the >> option API, to be able to specify at the creation of a None value >> the error string that will be displayed if one calls unwrap() on this >> value ? This may be useful in several situations. >> > > That would require making the memory representation of every Option > bigger. Just for the (hopefully) uncommon case of task failure, it’s not > worth the cost in my opinion. > > We could instead have .unwrap() that take an error message, but that > leaves the responsibility to the user of the API. > > > -- > Simon Sapin > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 06/12/2013 20:55, Léo Testard wrote: Hi, Just a suggestion, don't know what it's worth... For the "not helpful error message" thing, couldn't we extend the option API, to be able to specify at the creation of a None value the error string that will be displayed if one calls unwrap() on this value ? This may be useful in several situations. That would require making the memory representation of every Option bigger. Just for the (hopefully) uncommon case of task failure, it’s not worth the cost in my opinion. We could instead have .unwrap() that take an error message, but that leaves the responsibility to the user of the API. -- Simon Sapin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 06/12/2013 20:48, Corey Richardson wrote: I'm in favor of this but it makes things less "pretty". Is the choice really between pretty and fast? I don’t think this is about speed. My concern is that having two almost-identical names for functions that do almost the same thing is not a good design, and should be avoided if possible. -- Simon Sapin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On 12/06/2013 12:41 PM, Simon Sapin wrote: We have some functions and methods such as [std::str::from_utf8](http://static.rust-lang.org/doc/master/std/str/fn.from_utf8.html) that may succeed and give a result, or fail when the input is invalid. 1. Sometimes we assume the input is valid and don’t want to deal with the error case. Task failure works nicely. 2. Sometimes we do want to do something different on invalid input, so returning an `Option` works best. And so we end up with both `from_utf8` and `from_utf8`. This particular case is worse because we also have `from_utf8_owned` and `from_utf8_owned_opt`, to cover everything. Multiplying names like this is just not good design. I’d like to reduce this pattern. Getting behavior 1. when you have 2. is easy: just call `.unwrap()` on the Option. I think we should rename every `foo_opt()` function or method to just `foo`, remove the old `foo()` behavior, and tell people (through documentation) to use `foo().unwrap()` if they want it back? The downsides are that unwrap is more verbose and gives less helpful error messages on task failure. But I think it’s worth it. What do you think? (PS: I’m guilty of making this worse in #10828, but I’d like to discuss this before sending pull requests with invasive API changes.) I agree in this case (and probably a lot of cases), especially since this is a relatively uncommon operation and since (I think) we're prefering 'get' to 'unwrap' and that's even shorter. There are some cases where I think failure is the right option by default though; in particular I was worried you were going to bring up the 'send' and 'recv' methods on channels which fail when disconnected. In this case I think it won't be common to handle the failure since it indicates some logic error, and these are very common operations. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
On Fri, Dec 6, 2013 at 3:41 PM, Simon Sapin wrote: > We have some functions and methods such as > [std::str::from_utf8](http://static.rust-lang.org/doc/master/std/str/fn.from_utf8.html) > that may succeed and give a result, or fail when the input is invalid. > > 1. Sometimes we assume the input is valid and don’t want to deal with the > error case. Task failure works nicely. > > 2. Sometimes we do want to do something different on invalid input, so > returning an `Option` works best. > > And so we end up with both `from_utf8` and `from_utf8`. This particular case > is worse because we also have `from_utf8_owned` and `from_utf8_owned_opt`, > to cover everything. > > Multiplying names like this is just not good design. I’d like to reduce this > pattern. > > Getting behavior 1. when you have 2. is easy: just call `.unwrap()` on the > Option. I think we should rename every `foo_opt()` function or method to > just `foo`, remove the old `foo()` behavior, and tell people (through > documentation) to use `foo().unwrap()` if they want it back? > > The downsides are that unwrap is more verbose and gives less helpful error > messages on task failure. But I think it’s worth it. > > What do you think? > > (PS: I’m guilty of making this worse in #10828, but I’d like to discuss this > before sending pull requests with invasive API changes.) > > -- > Simon Sapin A stack trace already tells you where the error came from so I don't think it's an important consideration. Rust can provide stack traces on failure by default if that's desired. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
Hi, Just a suggestion, don't know what it's worth... For the "not helpful error message" thing, couldn't we extend the option API, to be able to specify at the creation of a None value the error string that will be displayed if one calls unwrap() on this value ? This may be useful in several situations. Leo Le 6 déc. 2013 à 21:48, Corey Richardson a écrit : > I'm in favor of this but it makes things less "pretty". Is the choice > really between pretty and fast? > > On Fri, Dec 6, 2013 at 3:41 PM, Simon Sapin wrote: >> We have some functions and methods such as >> [std::str::from_utf8](http://static.rust-lang.org/doc/master/std/str/fn.from_utf8.html) >> that may succeed and give a result, or fail when the input is invalid. >> >> 1. Sometimes we assume the input is valid and don’t want to deal with the >> error case. Task failure works nicely. >> >> 2. Sometimes we do want to do something different on invalid input, so >> returning an `Option` works best. >> >> And so we end up with both `from_utf8` and `from_utf8`. This particular case >> is worse because we also have `from_utf8_owned` and `from_utf8_owned_opt`, >> to cover everything. >> >> Multiplying names like this is just not good design. I’d like to reduce this >> pattern. >> >> Getting behavior 1. when you have 2. is easy: just call `.unwrap()` on the >> Option. I think we should rename every `foo_opt()` function or method to >> just `foo`, remove the old `foo()` behavior, and tell people (through >> documentation) to use `foo().unwrap()` if they want it back? >> >> The downsides are that unwrap is more verbose and gives less helpful error >> messages on task failure. But I think it’s worth it. >> >> What do you think? >> >> (PS: I’m guilty of making this worse in #10828, but I’d like to discuss this >> before sending pull requests with invasive API changes.) >> >> -- >> Simon Sapin >> ___ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev signature.asc Description: Message signed with OpenPGP using GPGMail ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
I'm in favor of this but it makes things less "pretty". Is the choice really between pretty and fast? On Fri, Dec 6, 2013 at 3:41 PM, Simon Sapin wrote: > We have some functions and methods such as > [std::str::from_utf8](http://static.rust-lang.org/doc/master/std/str/fn.from_utf8.html) > that may succeed and give a result, or fail when the input is invalid. > > 1. Sometimes we assume the input is valid and don’t want to deal with the > error case. Task failure works nicely. > > 2. Sometimes we do want to do something different on invalid input, so > returning an `Option` works best. > > And so we end up with both `from_utf8` and `from_utf8`. This particular case > is worse because we also have `from_utf8_owned` and `from_utf8_owned_opt`, > to cover everything. > > Multiplying names like this is just not good design. I’d like to reduce this > pattern. > > Getting behavior 1. when you have 2. is easy: just call `.unwrap()` on the > Option. I think we should rename every `foo_opt()` function or method to > just `foo`, remove the old `foo()` behavior, and tell people (through > documentation) to use `foo().unwrap()` if they want it back? > > The downsides are that unwrap is more verbose and gives less helpful error > messages on task failure. But I think it’s worth it. > > What do you think? > > (PS: I’m guilty of making this worse in #10828, but I’d like to discuss this > before sending pull requests with invasive API changes.) > > -- > Simon Sapin > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev