[rust-dev] Let’s avoid having both foo() and foo_opt()

Nick Cameron lists at ncameron.org
Tue Jan 7 22:37:33 PST 2014


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 <vadimcn at gmail.com> wrote:

> On Tue, Jan 7, 2014 at 6:39 PM, Nick Cameron <lists at ncameron.org> 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 <vadimcn at gmail.com> wrote:
>>
>>> I can see how '?.' would work when foo() returns a struct, but what
>>> about non-struct types, e.g. Option<i32> ?   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 <lists at ncameron.org>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<T'>
>>>> fType(T', f) = T
>>>> ------------------------------------
>>>> \Gamma e?f : Option<T>
>>>>
>>>> e?f ~~> match e { Some<e> => Some<e.f>, 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 <simon.sapin at exyr.org>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<T>` 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 at mozilla.org
>>>>> https://mail.mozilla.org/listinfo/rust-dev
>>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> Rust-dev mailing list
>>>> Rust-dev at mozilla.org
>>>> https://mail.mozilla.org/listinfo/rust-dev
>>>>
>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140108/a791dd73/attachment-0001.html>


More information about the Rust-dev mailing list