[rust-dev] Safely writing iterators over idiomatic C structures
Imagine that we have a structure of the form: typedef struct { int payload1; foo *link; int payload2; } foo; This structure is characterized by two things: 1) It is a singly linked list, and thus has a simple ownership structure which can be captured by Rust's owned pointers 2) The payload of this struct is interleaved with links, in order to save space and an extra indirection. The layout may be fixed, by virtue of being exposed by a C library. The question now is: can we write an Iteratormut foo for the corresponding Rust structure foo, without using any unsafe code? There is a fundamental problem with this structure: iterator invalidation. If we are able to issue a mut foo reference, then the link field could get mutated. Rust's borrow checker would reject this, since the only possible internal state for the iterator (a mutable reference to the next element) aliases with the mutable reference returned by next(). I am not sure how to solve this without changing the layout of the struct; perhaps there might be a way if one could selectively turn off the mutability of some fields. Suppose we are willing to change the struct, as per the extra::dlist implementation, we still fall short of a safe implementation: the internal state of the iterator utilizes a raw pointer (head), which provides a function resolve() which simply mints a mutable reference to the element in question. It seems to be using Rawlink to hide the fact that it has its fingers on a mutable borrowed reference to the list. It recovers some safety by maintaining a mutable reference to the whole list in the iterator structure as well, but it would be better if no unsafe code was necessary at all, and I certainly don't feel qualified to reason about the correctness of this code. (Though, I understand and appreciate the fact that the back pointers have to be handled unsafely.) So, is it possible? I just want (provably) safe, mutable iteration over singly-linked lists... Edward ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Safely writing iterators over idiomatic C structures
On 06/12/13 19:11, Edward Z. Yang wrote: Imagine that we have a structure of the form: typedef struct { int payload1; foo *link; int payload2; } foo; This structure is characterized by two things: 1) It is a singly linked list, and thus has a simple ownership structure which can be captured by Rust's owned pointers 2) The payload of this struct is interleaved with links, in order to save space and an extra indirection. The layout may be fixed, by virtue of being exposed by a C library. The question now is: can we write an Iteratormut foo for the corresponding Rust structure foo, without using any unsafe code? There is a fundamental problem with this structure: iterator invalidation. If we are able to issue a mut foo reference, then the link field could get mutated. Rust's borrow checker would reject this, since the only possible internal state for the iterator (a mutable reference to the next element) aliases with the mutable reference returned by next(). I am not sure how to solve this without changing the layout of the struct; perhaps there might be a way if one could selectively turn off the mutability of some fields. Suppose we are willing to change the struct, as per the extra::dlist implementation, we still fall short of a safe implementation: the internal state of the iterator utilizes a raw pointer (head), which provides a function resolve() which simply mints a mutable reference to the element in question. It seems to be using Rawlink to hide the fact that it has its fingers on a mutable borrowed reference to the list. It recovers some safety by maintaining a mutable reference to the whole list in the iterator structure as well, but it would be better if no unsafe code was necessary at all, and I certainly don't feel qualified to reason about the correctness of this code. (Though, I understand and appreciate the fact that the back pointers have to be handled unsafely.) So, is it possible? I just want (provably) safe, mutable iteration over singly-linked lists... Edward ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev One could have an Iterator(mut int, mut int), where the references point to just the fields. Off the top of my head: struct List { payload1: int, next: Option~Foo, payload2: f64 } struct ListMutIterator'a { elem: Option'a mut List } impl'a Iterator('a mut int, 'a mut f64) for ListMutIterator'a { fn next(mut self) - Option('a mut int, 'a mut f64) { let elem = std::util::replace(self, None); // I think this might be necessary to get around the borrow checker. let (ret, next) = match elem { Some(List { payload1: ref mut payload1, next: ref mut next, payload2: ref mut payload2 }) = { (Some((payload1, payload2)), next.as_mut_ref()) } None = (None, None) }; *self = next; ret } } (The List pattern match will look nicer if https://github.com/mozilla/rust/issues/6137 gets solved; `List { ref mut payload1, ref mut next, ref mut payload2 }`.) I imagine this will end up being very ugly if there are more than just 2 fields before and after, although one could easily replace the tuple with a struct `ListMutRef'a { payload1: 'a mut int, payload2: 'a mut f64 }`. Huon ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Safely writing iterators over idiomatic C structures
Maybe the language should be changed to allow Iterator to be changed to have a signature like this: pub trait IteratorA { fn next'a('a mut self) - Option'a A; } Then you could return the mut by reborrowing and would be able to advance the iterator without issue afterwards. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Let’s avoid having both foo() and foo_opt()
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 `OptionT` 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
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 simon.sa...@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 `OptionT` 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] Safely writing iterators over idiomatic C structures
OK, with a little bit of tweaking I have come up with a version that seems to work: struct List { payload1: int, next: Option~List, payload2: f64 } struct ListMutIterator'a { elem: Option'a mut List } impl'a Iterator('a mut int, 'a mut f64) for ListMutIterator'a { fn next(mut self) - Option('a mut int, 'a mut f64) { let elem = std::util::replace(self, ListMutIterator{elem:None}); // I think this might be necessary to get around the borrow checker. let (ret, next) = match elem { ListMutIterator{elem: Some(List { payload1: ref mut payload1, next: ref mut next, payload2: ref mut payload2 })} = { (Some((payload1, payload2)), match *next { None = None, Some(ref mut p) = Some(mut **p) }) } ListMutIterator{elem: None} = (None, None) }; *self = ListMutIterator{elem:next}; ret } } Perhaps dlist should be updated to use this implementation strategy? Edward ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Safely writing iterators over idiomatic C structures
Excerpts from Huon Wilson's message of 2013-12-06 00:26:36 -0800: One could have an Iterator(mut int, mut int), where the references point to just the fields. Off the top of my head: Sure. (This is not so good when there are a lot of fields.) impl'a Iterator('a mut int, 'a mut f64) for ListMutIterator'a { fn next(mut self) - Option('a mut int, 'a mut f64) { let elem = std::util::replace(self, None); // I think this might be necessary to get around the borrow checker. let (ret, next) = match elem { Some(List { payload1: ref mut payload1, next: ref mut next, payload2: ref mut payload2 }) = { (Some((payload1, payload2)), next.as_mut_ref()) I fixed some of the egregious type-checking errors, but this one has me stuck. There is no as_mut_ref() in the version of Rust I'm running, and the plausible replacement mut_ref() doesn't do what I want: Huon.rs|24 col 37 error| mismatched types: expected `std::option::Optionmut List` but found `std::option::Optionmut ~List` (expected struct List but found ~-ptr) (Because, of course, the thing inside the option is a ~List, not a List). Cheers, Edward ___ 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 simon.sa...@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 `OptionT` 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()
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 `OptionT` 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 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 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()
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 simon.sa...@exyr.org 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 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()
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()
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 simon.sa...@exyr.org 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()
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 danielmi...@gmail.com a écrit : On Fri, Dec 6, 2013 at 7:00 PM, Palmer Cox palmer...@gmail.com 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()
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 gae...@xeberon.net 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 danielmi...@gmail.com a écrit : On Fri, Dec 6, 2013 at 7:00 PM, Palmer Cox palmer...@gmail.com 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 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()
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 `OptionT` 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
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/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 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 Sat, Dec 7, 2013 at 2:01 AM, spir denis.s...@gmail.com 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 07/12/13 12:08, Jordi Boggiano wrote: On Sat, Dec 7, 2013 at 2:01 AM, spir denis.s...@gmail.com 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:07 AM, spir denis.s...@gmail.com 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()
Is do-notation in Haskell similar as: try{ block } ? 2013/12/7 Huon Wilson dbau...@gmail.com On 07/12/13 12:08, Jordi Boggiano wrote: On Sat, Dec 7, 2013 at 2:01 AM, spir denis.s...@gmail.com 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()
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 dbau...@gmail.com wrote: On 07/12/13 12:08, Jordi Boggiano wrote: On Sat, Dec 7, 2013 at 2:01 AM, spir denis.s...@gmail.com 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 12/6/13 6:46 PM, Niko Matsakis wrote: I agree. I've personally been moving towards `ResultT, ()` in preference to `OptionT` 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()
On 7 Dec 2013, at 10:47 am, Simon Sapin simon.sa...@exyr.org 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()
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 bjz...@yahoo.com.auwrote: On 7 Dec 2013, at 10:47 am, Simon Sapin simon.sa...@exyr.org 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()
Especially if ResultT, () 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 pcwal...@mozilla.comwrote: On 12/6/13 6:46 PM, Niko Matsakis wrote: I agree. I've personally been moving towards `ResultT, ()` in preference to `OptionT` 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
[rust-dev] Higher-Kinded Types vs C++ Combos
Rust newb here. I have theoretical questions. Recently I noticed that Higher-Kinded Types (HKTs) have been mentioned on the mailing list a lot, but I had no idea what a HKT was, or what it might be good for. After reading about them a little, they reminded me of C++'s template template parameters. In C++ you can almost write something like this: template template typename class collection struct Numbers { collectionint integers; collectionfloat floats; }; So then you can write Numbersvector for a structure that contains vectorT collections, and Numberslist for a structure that contains listT collections. EXCEPT that it doesn't actually work, because vectorT has two template parameters (the second one, the allocator, is normally left at its default). Let's ignore that, though. So that brings me to my first question: is this what higher-kinded types means? What is the difference, if any, between HKT and C++ template templates? However, as a C++ developer I never actually used a template template parameter because I didn't know they existed for a long time. So instead I would have written this, which has the same end-result: struct VectorTrait { templatetypename T struct collection { typedef vectorT type; }; }; struct ListTrait { templatetypename T struct collection { typedef listT type; }; }; templatetypename Traits struct Numbers { Traits::collectionint::type integers; Traits::collectionfloat::type floats; }; // Use NumbersVectorTrait for vectorT, NumbersListTrait for listT. This is clunkier, but it would have been a bit simpler if C++ supported templatized typedefs: struct VectorTrait { templatetypename T typedef vectorT collection; }; struct ListTrait { templatetypename T typedef vectorT collection; }; templatetypename Traits struct Numbers { Traits::collectionint integers; Traits::collectionfloat floats; }; // Now write NumbersVectorTrait instead of Numbersvector, // NumbersListTrait instead of Numberslist. I have found that because of the existence of typedef, template template parameters are never actually necessary; so far, I've never seen a situation where the typedef-based solution wasn't almost as good. Also, I have found that trait types filled with typedefs seem to be a more general thing than template template; they allow you to do things that would be very difficult or impossible without them. For example you can use typedefs-in-a-struct to create circular references among types that don't know about each other: // I call this a Combo; I don't know if the technique has a standard name struct MyCombo { typedef ConcreteATraits A; typedef ConcreteBTraits B; typedef ConcreteCTraits C; }; templatetypename Combo class ConcreteA { Combo::B* b; ... }; templatetypename Combo class ConcreteB { Combo::C* c; ... }; templatetypename Combo class ConcreteC { Combo::A* b; ... }; Here I've created a network of types (ConcreteAMyCombo, ConcreteBMyCombo, and ConcreteCMyCombo) that are linked together through the Combo type MyCombo, so the types can all use each other, but none of the types refer to each other directly. This design allows you to freely swap in different implementations of A, B, and C; it has similar advantages to dependency injection or inversion of control in languages like Java and C#, except that the linkages are all defined statically at compile-time, so no dynamic dispatch is required. Without the ability to define typedefs, this approach is not possible at all if there is a cyclic relationship. Also, if the combo declares more than three types, it becomes impractical to specify all those types on the classes directly as type parameters. In C# I learned that this quickly becomes a major problem if you need to parameterize on more than one or two types. I tried to do generic math (which requires at least two type parameters due to the under-designed standard libraries) and I also implemented a GiST data structure (see http://en.wikipedia.org/wiki/GiST), and found out that the lack of any analog to C++ typedef makes both of those tasks very clumsy, while also making the code hard to read, because you end up with a rats' nest of type parameters (or if you omit (otherwise necessary) type parameters, you might use lots of casts instead.) So I guess that leads me to two more questions. 2. Does Rust have a typedef equivalent that can be used in this way? 3. Does it make sense to just suggest just use typedefs instead of Higher-Kinded Types? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Higher-Kinded Types vs C++ Combos
Of course this leads (assuming we had a `Collection` trait) to the horrendously ugly `Numbers::i32, ~[i32], f32, ~[f32](...)` if you wanted to be explicit. But hopefully your code would be such that Rust could infer the bounds. This will be alleviated in the future by associated items, but that will probably be post 1.0. (I might be getting a little off-topic here) ~Brendan On 7 Dec 2013, at 5:27 pm, Brendan Zabarauskas bjz...@yahoo.com.au wrote: I’m not sure I understand everything in your post, but this is how I’d write you first C++ example: struct NumbersIV, FV { priv iv: IV,// priv so the struct can only be constructed in this module priv fv: FV, } implI: Int, IV: CollectionI, F: Float, FV: CollectionF NumbersIV, FV { pub fn new(iv: IV, fv: FV) - NumbersIV, FV { Numbers { iv: iv, fv: fv } } } You can also write type aliases with type parameters, but I don’t think you can enforce trait bounds on them afaik: type AT = (T, int); ~Brendan On 7 Dec 2013, at 5:10 pm, David Piepgrass qwertie...@gmail.com wrote: Rust newb here. I have theoretical questions. Recently I noticed that Higher-Kinded Types (HKTs) have been mentioned on the mailing list a lot, but I had no idea what a HKT was, or what it might be good for. After reading about them a little, they reminded me of C++'s template template parameters. In C++ you can almost write something like this: template template typename class collection struct Numbers { collectionint integers; collectionfloat floats; }; So then you can write Numbersvector for a structure that contains vectorT collections, and Numberslist for a structure that contains listT collections. EXCEPT that it doesn't actually work, because vectorT has two template parameters (the second one, the allocator, is normally left at its default). Let's ignore that, though. So that brings me to my first question: is this what higher-kinded types means? What is the difference, if any, between HKT and C++ template templates? However, as a C++ developer I never actually used a template template parameter because I didn't know they existed for a long time. So instead I would have written this, which has the same end-result: struct VectorTrait { templatetypename T struct collection { typedef vectorT type; }; }; struct ListTrait { templatetypename T struct collection { typedef listT type; }; }; templatetypename Traits struct Numbers { Traits::collectionint::type integers; Traits::collectionfloat::type floats; }; // Use NumbersVectorTrait for vectorT, NumbersListTrait for listT. This is clunkier, but it would have been a bit simpler if C++ supported templatized typedefs: struct VectorTrait { templatetypename T typedef vectorT collection; }; struct ListTrait { templatetypename T typedef vectorT collection; }; templatetypename Traits struct Numbers { Traits::collectionint integers; Traits::collectionfloat floats; }; // Now write NumbersVectorTrait instead of Numbersvector, // NumbersListTrait instead of Numberslist. I have found that because of the existence of typedef, template template parameters are never actually necessary; so far, I've never seen a situation where the typedef-based solution wasn't almost as good. Also, I have found that trait types filled with typedefs seem to be a more general thing than template template; they allow you to do things that would be very difficult or impossible without them. For example you can use typedefs-in-a-struct to create circular references among types that don't know about each other: // I call this a Combo; I don't know if the technique has a standard name struct MyCombo { typedef ConcreteATraits A; typedef ConcreteBTraits B; typedef ConcreteCTraits C; }; templatetypename Combo class ConcreteA { Combo::B* b; ... }; templatetypename Combo class ConcreteB { Combo::C* c; ... }; templatetypename Combo class ConcreteC { Combo::A* b; ... }; Here I've created a network of types (ConcreteAMyCombo, ConcreteBMyCombo, and ConcreteCMyCombo) that are linked together through the Combo type MyCombo, so the types can all use each other, but none of the types refer to each other directly. This design allows you to freely swap in different implementations of A, B, and C; it has similar advantages to dependency injection or inversion of control in languages like Java and C#, except that the linkages are all defined statically at compile-time, so no dynamic dispatch is required. Without the ability to define typedefs, this approach is not possible at all if there is a cyclic relationship. Also, if the combo declares more than three types, it becomes impractical to specify all those types on the classes directly as type parameters. In C# I learned that this quickly becomes a