From williamw520 at gmail.com Fri Nov 1 03:02:20 2013 From: williamw520 at gmail.com (William Wong) Date: Fri, 1 Nov 2013 03:02:20 -0700 Subject: [rust-dev] GZip and Deflate Message-ID: I wanted to add full compression support to Rust. Full support means stream compression (good for http compression) and multiple call compression (compressing large file with multiple batches of read). To get to that point, the miniz.cpp and deflate API in Rust runtime need to be enhanced to overcome a few limitations. I've worked with the author of miniz.c (Rich Geldreich) to merge changes into miniz.c on his codeline for the needed API for Rust, and resolved the decompression bug in miniz's code when working with gzip'ed file. http://code.google.com/p/miniz/issues/detail?id=25&can=1 http://code.google.com/p/miniz/issues/detail?id=23&can=1 I've implemented a full set of deflate API in Rust to support stream compression and multiple call compression, with caller-driven and callee-driven pipe style API. Also I've written the Rust GZip library with stream support like GZipReader and GZipWriter. For testing, I've re-implemented most of the gzip command line program on top of the Rust GZip library. Some performance data for the interested: Rust compression is about 1.8 times slower, decompression is about 3 times slower than gzip. Overall it seems solid. See https://github.com/williamw520/rustyzipfor the source. Now I need help to merge the changes into the Rust master codeline. There are couple things. 1. What license to assign for the new files? I use MPL currently. 2. There's a new version of miniz.cpp needed for things to work. Is the Rust runtime still open for C++ file changes? 3. There are two new files for the deflate library (deflate.rs) and the gzip library (gzip.rs). Which Rust runtime library is the appropriate one to put them in? 4. Should the command line tool rgzip stay in an outside codeline or be merged into the Rust runtime? If merging in, where is a good place for tools? Thanks William -------------- next part -------------- An HTML attachment was scrubbed... URL: From ben.striegel at gmail.com Fri Nov 1 08:40:18 2013 From: ben.striegel at gmail.com (Benjamin Striegel) Date: Fri, 1 Nov 2013 11:40:18 -0400 Subject: [rust-dev] GZip and Deflate In-Reply-To: References: Message-ID: I can't answer your questions, but I do want to say that this is very interesting! > Rust compression is about 1.8 times slower, decompression is about 3 times slower than gzip. Have you tried profiling this to see where our bottlenecks are? It would be great if we could use this as an opportunity to improve our performance. On Fri, Nov 1, 2013 at 6:02 AM, William Wong wrote: > I wanted to add full compression support to Rust. Full support means > stream compression (good for http compression) and multiple call > compression (compressing large file with multiple batches of read). To get > to that point, the miniz.cpp and deflate API in Rust runtime need to be > enhanced to overcome a few limitations. > > I've worked with the author of miniz.c (Rich Geldreich) to merge changes > into miniz.c on his codeline for the needed API for Rust, and resolved the > decompression bug in miniz's code when working with gzip'ed file. > > http://code.google.com/p/miniz/issues/detail?id=25&can=1 > http://code.google.com/p/miniz/issues/detail?id=23&can=1 > > I've implemented a full set of deflate API in Rust to support stream > compression and multiple call compression, with caller-driven and > callee-driven pipe style API. Also I've written the Rust GZip library with > stream support like GZipReader and GZipWriter. For testing, I've > re-implemented most of the gzip command line program on top of the Rust > GZip library. Some performance data for the interested: Rust compression > is about 1.8 times slower, decompression is about 3 times slower than > gzip. Overall it seems solid. See > https://github.com/williamw520/rustyzip for the source. > > Now I need help to merge the changes into the Rust master codeline. There > are couple things. > > 1. What license to assign for the new files? I use MPL currently. > 2. There's a new version of miniz.cpp needed for things to work. Is the > Rust runtime still open for C++ file changes? > 3. There are two new files for the deflate library (deflate.rs) and the > gzip library (gzip.rs). Which Rust runtime library is the appropriate > one to put them in? > 4. Should the command line tool rgzip stay in an outside codeline or be > merged into the Rust runtime? If merging in, where is a good place for > tools? > > Thanks > > William > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Fri Nov 1 09:14:26 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 01 Nov 2013 09:14:26 -0700 Subject: [rust-dev] GZip and Deflate In-Reply-To: References: Message-ID: <5273D362.8040908@mozilla.com> On 11/1/13 8:40 AM, Benjamin Striegel wrote: > I can't answer your questions, but I do want to say that this is very > interesting! > > > Rust compression is about 1.8 times slower, decompression is about 3 > times slower than gzip. > > Have you tried profiling this to see where our bottlenecks are? It would > be great if we could use this as an opportunity to improve our performance. It sounds like the problem is in miniz, so not in Rust code. (BTW, compile times for small crates are very gated on decompression of metadata. Improvement of decompression speed improves compile times. Although maybe we should just switch to Snappy or something.) Patrick From loebel.marvin at gmail.com Fri Nov 1 11:20:12 2013 From: loebel.marvin at gmail.com (=?ISO-8859-1?Q?Marvin_L=F6bel?=) Date: Fri, 01 Nov 2013 19:20:12 +0100 Subject: [rust-dev] RFC about std::option and std::result API Message-ID: <5273F0DC.4040702@gmail.com> Hello everyone! In the last week I've been trying to update both std::Result and std::Option's API to match each other more, and I'd like to see the opinion of the community and the Devs on a few areas it touches. # Option today The baseline here is Options current API, which roughly looks like this: 1. Methods for querying the variant - fn is_some(&self) -> bool - fn is_none(&self) -> bool 2. Adapter for working with references - fn as_ref<'r>(&'r self) -> Option<&'r T> - fn as_mut<'r>(&'r mut self) -> Option<&'r mut T> 3. Methods for getting to the contained value - fn expect(self, msg: &str) -> T - fn unwrap(self) -> T - fn unwrap_or(self, def: T) -> T - fn unwrap_or_else(self, f: &fn() -> T) -> T 4. Methods for transforming the contained value - fn map(self, f: &fn(T) -> U) -> Option - fn map_default(self, def: U, f: &fn(T) -> U) -> U - fn mutate(&mut self, f: &fn(T) -> T) -> bool - fn mutate_default(&mut self, def: T, f: &fn(T) -> T) -> bool 5. Iterator constructors - fn iter<'r>(&'r self) -> OptionIterator<&'r T> - fn mut_iter<'r>(&'r mut self) -> OptionIterator<&'r mut T> - fn move_iter(self) -> OptionIterator 6. Boolean-like operations on the values, eager and lazy - fn and(self, optb: Option) -> Option - fn and_then(self, f: &fn(T) -> Option) -> Option - fn or(self, optb: Option) -> Option - fn or_else(self, f: &fn() -> Option) -> Option 7. Other useful methods - fn take(&mut self) -> Option - fn filtered(self, f: &fn(t: &T) -> bool) -> Option - fn while_some(self, blk: &fn(v: T) -> Option) 8. Common special cases that are shorthand for chaining two other methods together. - fn take_unwrap(&mut self) -> T - fn get_ref<'a>(&'a self) -> &'a T - fn get_mut_ref<'a>(&'a mut self) -> &'a mut T Based on this, I have a few areas of the API of both modules to discuss: # Renaming `unwrap` to `get` This is a known issue (https://github.com/mozilla/rust/issues/9784), and I think we should just go through with it. There are a few things that speak in favor for this: - The name `unwrap` implies destruction of the original `Option`, which is not the case for implicitly copyable types, so it's a bad name. - Ever since we got the reference adapters, Options primary usage is to take self by value, with `unwrap` being the main method for getting the value out of an Option. `get` is a shorter name than `unwrap`, so it would make using Option less painful. - `Option` already has two shorthands for `.as_ref().unwrap()` and `as_mut().unwrap()`: `.get_ref()` and `.get_mut_ref`, so the name `get` has precedence in the current API. # Renaming `map_default` and `mutate_default` to `map_or` and `mutate_or_set` I can't find an issue for this, but I remember there being an informal agreement to not use the `_default` prefix in methods unless they are related to the `std::default::Default` trait, a confirmation of this would be nice. The names `map_or` and `mutate_or_set` would fit in the current naming scheme. # The problem with Result Now, the big issue. Up until now, work on the result module tried to converge on option's API, except adapted to work with Result. For example, option has `fn or_else(self, f: &fn() -> Option) -> Option` to evaluate a function in case of a `None` value, while result has `pub fn or_else(self, op: &fn(E) -> Result) -> Result` to evaluate a function in case of an `Err` value. However, while some of the operations are directly compatible with this approach, most others require two methods each, one for the `Ok` and one for the `Err` variant: - `fn unwrap(self) -> T` vs `fn unwrap_err(self) -> E` - `fn expect(self, &str) -> T` vs `fn expect_err(self, &str) -> E` - `fn map_default(self, def: U, op: &fn(T) -> U) -> U` vs `fn map_err_default(self, def: F, op: &fn(E) -> F) -> F` - ... and many other methods in blocks 3, 4 and 5. As you can see, this leads to API duplication twofold: All those methods already exist on Option, and all those methods exist both for the `Ok` and the `Err` variant. This is not an Result-only issue: Every enum that is laid out like Result either suffers the same kind of method duplication, or simply does not provide any, instead requiring the user to match and manipulate them manually. Examples would be `std::either::Either`, or `std::unstable::sync::UnsafeArcUnwrap` To solve this problem, I'm proposing a convention for all enums that consist of only newtype-like variants: # Variant adapters for newtype variant enums Basically, we should start the convention that every enum of the form enum Foo { VariantA(A), VariantB(B), VariantC(C), ... } should implement two sets of methods: 1. Reference adapters for the type itself: - fn as_ref<'r>(&'r self) -> Foo<&'r A, &'r B, &'r C, ...> - fn as_mut<'r>(&'r mut self) -> Foo<&'r mut A, &'r mut B, &'r mut C, ...> 2. Option adapters for each variant: - fn variant_a(self) -> Option - fn variant_b(self) -> Option - fn variant_c(self) -> Option - ... This would enable users to compose together any combination of any variant using the option API, while still having full control over ownership with the by-ref adapters. # Example If we combine the proposal above with the two renamings, we get this: - `res.unwrap_err()` becomes `res.err().get()` - `res.expect("!")` becomes `res.ok().expect("!")` - `res.expect_err("!")` becomes `res.err().expect("!")` - `res.map_err_default(0, |a| a + 5)` becomes `res.err().map_or(0, |a| a + 5)` As you can see, it becomes a bit more cumbersome to use, but not necessarily longer. We can also do the same for `Result` as we do for `Option`: Keep frequently used methods as a shortcut, even if they are expressible by combining a few other. # Possible problems for Result specifically There are two potential issues that get in the way with this approach: - Because `ok()` throws away the `Err` variant, something like `unwrap()` can no longer print a useful error message. However, the shortcut implementations still could, and as they will probably be used the most this might not be a problem in practice. - There was talk about making `Result` use an `~Error` trait object instead of a generic type `E`, which could invalidate most of this email. However, this could also just mean that you usually will see `Result` in the wild, for which this proposal still applies. Additionally, even if the Pattern becomes useless for Result, the problem still exists for any other newtype variant enums, so I'd like to see it get used anyway. # Support for this pattern Both reference adapters and variant Option adapters are fairly mechanically implementations, so we could actually support their generation with an attribute like `#[impl_enum_variant_accessors]`. So, what are your thoughts about this? I think it would greatly increase composability of enums in general and reduce the amount of boilerplate code. :) Kimundi From banderson at mozilla.com Fri Nov 1 11:42:43 2013 From: banderson at mozilla.com (Brian Anderson) Date: Fri, 01 Nov 2013 11:42:43 -0700 Subject: [rust-dev] GZip and Deflate In-Reply-To: References: Message-ID: <5273F623.5040502@mozilla.com> On 11/01/2013 03:02 AM, William Wong wrote: > I wanted to add full compression support to Rust. Full support means > stream compression (good for http compression) and multiple call > compression (compressing large file with multiple batches of read). > To get to that point, the miniz.cpp and deflate API in Rust runtime > need to be enhanced to overcome a few limitations. > > I've worked with the author of miniz.c (Rich Geldreich) to merge > changes into miniz.c on his codeline for the needed API for Rust, and > resolved the decompression bug in miniz's code when working with > gzip'ed file. > > http://code.google.com/p/miniz/issues/detail?id=25&can=1 > http://code.google.com/p/miniz/issues/detail?id=23&can=1 Awesome! > > I've implemented a full set of deflate API in Rust to support stream > compression and multiple call compression, with caller-driven and > callee-driven pipe style API. Also I've written the Rust GZip library > with stream support like GZipReader and GZipWriter. For testing, I've > re-implemented most of the gzip command line program on top of the > Rust GZip library. Some performance data for the interested: Rust > compression is about 1.8 times slower, decompression is about 3 times > slower than gzip. Overall it seems solid. See > https://github.com/williamw520/rustyzip for the source. Even more awesome! > > Now I need help to merge the changes into the Rust master codeline. > There are couple things. > > 1. What license to assign for the new files? I use MPL currently. APL2/MIT dual license. Just copy the same headers that exist on all the other .rs files. > 2. There's a new version of miniz.cpp needed for things to work. Is > the Rust runtime still open for C++ file changes? This change is fine. > 3. There are two new files for the deflate library (deflate.rs > ) and the gzip library (gzip.rs ). > Which Rust runtime library is the appropriate one to put them in? Replace extra::flate with these two. > 4. Should the command line tool rgzip stay in an outside codeline or > be merged into the Rust runtime? If merging in, where is a good place > for tools? Not in mainline. Note that libextra is slated to be broken up into a number of supported but external crates in the near future, and this will probably end up in its own crate. For now though I think the above strategy will work. Regards, Brian -------------- next part -------------- An HTML attachment was scrubbed... URL: From banderson at mozilla.com Fri Nov 1 11:44:33 2013 From: banderson at mozilla.com (Brian Anderson) Date: Fri, 01 Nov 2013 11:44:33 -0700 Subject: [rust-dev] GZip and Deflate In-Reply-To: <5273F623.5040502@mozilla.com> References: <5273F623.5040502@mozilla.com> Message-ID: <5273F691.3060604@mozilla.com> On 11/01/2013 11:42 AM, Brian Anderson wrote: > On 11/01/2013 03:02 AM, William Wong wrote: >> I wanted to add full compression support to Rust. Full support means >> stream compression (good for http compression) and multiple call >> compression (compressing large file with multiple batches of read). >> To get to that point, the miniz.cpp and deflate API in Rust runtime >> need to be enhanced to overcome a few limitations. >> >> I've worked with the author of miniz.c (Rich Geldreich) to merge >> changes into miniz.c on his codeline for the needed API for Rust, and >> resolved the decompression bug in miniz's code when working with >> gzip'ed file. >> >> http://code.google.com/p/miniz/issues/detail?id=25&can=1 >> http://code.google.com/p/miniz/issues/detail?id=23&can=1 > > Awesome! > >> >> I've implemented a full set of deflate API in Rust to support stream >> compression and multiple call compression, with caller-driven and >> callee-driven pipe style API. Also I've written the Rust GZip >> library with stream support like GZipReader and GZipWriter. For >> testing, I've re-implemented most of the gzip command line program on >> top of the Rust GZip library. Some performance data for the >> interested: Rust compression is about 1.8 times slower, decompression >> is about 3 times slower than gzip. Overall it seems solid. See >> https://github.com/williamw520/rustyzip for the source. > > Even more awesome! > >> >> Now I need help to merge the changes into the Rust master codeline. >> There are couple things. >> >> 1. What license to assign for the new files? I use MPL currently. > > APL2/MIT dual license. Just copy the same headers that exist on all > the other .rs files. Er, that's ASL2 (Apache License 2.0) -------------- next part -------------- An HTML attachment was scrubbed... URL: From banderson at mozilla.com Fri Nov 1 12:22:44 2013 From: banderson at mozilla.com (Brian Anderson) Date: Fri, 01 Nov 2013 12:22:44 -0700 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: <5273F0DC.4040702@gmail.com> References: <5273F0DC.4040702@gmail.com> Message-ID: <5273FF84.7050009@mozilla.com> On 11/01/2013 11:20 AM, Marvin L?bel wrote: > Hello everyone! > > In the last week I've been trying to update both std::Result and > std::Option's API > to match each other more, and I'd like to see the opinion of the > community and the > Devs on a few areas it touches. > > # Option today > > The baseline here is Options current API, which roughly looks like this: > > 1. Methods for querying the variant > - fn is_some(&self) -> bool > - fn is_none(&self) -> bool > > 2. Adapter for working with references > - fn as_ref<'r>(&'r self) -> Option<&'r T> > - fn as_mut<'r>(&'r mut self) -> Option<&'r mut T> > > 3. Methods for getting to the contained value > - fn expect(self, msg: &str) -> T > - fn unwrap(self) -> T > - fn unwrap_or(self, def: T) -> T > - fn unwrap_or_else(self, f: &fn() -> T) -> T > > 4. Methods for transforming the contained value > - fn map(self, f: &fn(T) -> U) -> Option > - fn map_default(self, def: U, f: &fn(T) -> U) -> U > - fn mutate(&mut self, f: &fn(T) -> T) -> bool > - fn mutate_default(&mut self, def: T, f: &fn(T) -> T) -> bool > > 5. Iterator constructors > - fn iter<'r>(&'r self) -> OptionIterator<&'r T> > - fn mut_iter<'r>(&'r mut self) -> OptionIterator<&'r mut T> > - fn move_iter(self) -> OptionIterator > > 6. Boolean-like operations on the values, eager and lazy > - fn and(self, optb: Option) -> Option > - fn and_then(self, f: &fn(T) -> Option) -> Option > - fn or(self, optb: Option) -> Option > - fn or_else(self, f: &fn() -> Option) -> Option > > 7. Other useful methods > - fn take(&mut self) -> Option > - fn filtered(self, f: &fn(t: &T) -> bool) -> Option > - fn while_some(self, blk: &fn(v: T) -> Option) > > 8. Common special cases that are shorthand for chaining two other > methods together. > - fn take_unwrap(&mut self) -> T > - fn get_ref<'a>(&'a self) -> &'a T > - fn get_mut_ref<'a>(&'a mut self) -> &'a mut T > > Based on this, I have a few areas of the API of both modules to discuss: > > # Renaming `unwrap` to `get` > > This is a known issue (https://github.com/mozilla/rust/issues/9784), > and I > think we should just go through with it. > There are a few things that speak in favor for this: > - The name `unwrap` implies destruction of the original `Option`, > which is > not the case for implicitly copyable types, so it's a bad name. > - Ever since we got the reference adapters, Options primary > usage is to take self by value, with `unwrap` being the main method for > getting the value out of an Option. > `get` is a shorter name than `unwrap`, so it would make using Option > less painful. > - `Option` already has two shorthands for `.as_ref().unwrap()` and > `as_mut().unwrap()`: > `.get_ref()` and `.get_mut_ref`, so the name `get` has precedence in > the current API. I think this (consistency) is the best argument in favor, though I do love how evocative the word 'unwrap' is. I will not argue against this change. > > # Renaming `map_default` and `mutate_default` to `map_or` and > `mutate_or_set` > > I can't find an issue for this, but I remember there being an informal > agreement to > not use the `_default` prefix in methods unless they are related to the > `std::default::Default` trait, a confirmation of this would be nice. > > The names `map_or` and `mutate_or_set` would fit in the current naming > scheme. Your reasoning makes sense, and this seems to be consistent with other names. > > # The problem with Result > > Now, the big issue. Up until now, work on the result module tried to > converge on > option's API, except adapted to work with Result. > > For example, option has `fn or_else(self, f: &fn() -> Option) -> > Option` > to evaluate a function in case of a `None` value, while result has > `pub fn or_else(self, op: &fn(E) -> Result) -> Result` > to evaluate a function in case of an `Err` value. > > However, while some of the operations are directly compatible with > this approach, > most others require two methods each, one for the `Ok` and one for the > `Err` variant: > > - `fn unwrap(self) -> T` vs > `fn unwrap_err(self) -> E` > - `fn expect(self, &str) -> T` vs > `fn expect_err(self, &str) -> E` > - `fn map_default(self, def: U, op: &fn(T) -> U) -> U` vs > `fn map_err_default(self, def: F, op: &fn(E) -> F) -> F` > - ... and many other methods in blocks 3, 4 and 5. > > As you can see, this leads to API duplication twofold: All those methods > already exist on Option, and all those methods exist both for the `Ok` > and the `Err` > variant. > > This is not an Result-only issue: Every enum that is laid out like > Result either > suffers the same kind of method duplication, or simply does not > provide any, > instead requiring the user to match and manipulate them manually. > > Examples would be `std::either::Either`, or > `std::unstable::sync::UnsafeArcUnwrap` > > To solve this problem, I'm proposing a convention for all enums that > consist of > only newtype-like variants: > > # Variant adapters for newtype variant enums > > Basically, we should start the convention that every enum of the form > > enum Foo { > VariantA(A), > VariantB(B), > VariantC(C), > ... > } > > should implement two sets of methods: > > 1. Reference adapters for the type itself: > - fn as_ref<'r>(&'r self) -> Foo<&'r A, &'r B, &'r C, ...> > - fn as_mut<'r>(&'r mut self) -> Foo<&'r mut A, &'r mut B, &'r mut > C, ...> > 2. Option adapters for each variant: > - fn variant_a(self) -> Option > - fn variant_b(self) -> Option > - fn variant_c(self) -> Option > - ... > > This would enable users to compose together any combination of any > variant using > the option API, while still having full control over ownership with > the by-ref adapters. > > # Example > > If we combine the proposal above with the two renamings, we get this: > > - `res.unwrap_err()` becomes > `res.err().get()` > - `res.expect("!")` becomes > `res.ok().expect("!")` > - `res.expect_err("!")` becomes > `res.err().expect("!")` > - `res.map_err_default(0, |a| a + 5)` becomes > `res.err().map_or(0, |a| a + 5)` > > As you can see, it becomes a bit more cumbersome to use, but not > necessarily longer. > We can also do the same for `Result` as we do for `Option`: Keep > frequently > used methods as a shortcut, even if they are expressible by combining > a few other. My first reaction is that it's not obvious the difference between `is_ok` and `ok`. Also, it would seem that `ok()` is required to return a different type to make this work, which seems fairly burdensome. If it *is* required to return a different type, then the obvious thing to do is just transform it into `Option` which is fairly nice since it just defers the problem to `Option` completely. > > # Possible problems for Result specifically > > There are two potential issues that get in the way with this approach: > - Because `ok()` throws away the `Err` variant, something like > `unwrap()` can no longer > print a useful error message. However, the shortcut implementations > still could, > and as they will probably be used the most this might not be a > problem in practice. > - There was talk about making `Result` use an `~Error` trait object > instead of a > generic type `E`, which could invalidate most of this email. > However, this could also just mean that you usually will see > `Result` > in the wild, for which this proposal still applies. > Additionally, even if the Pattern becomes useless for Result, the > problem > still exists for any other newtype variant enums, so I'd like to see > it get used > anyway. > > # Support for this pattern > > Both reference adapters and variant Option adapters are fairly > mechanically > implementations, so we could actually support their generation with an > attribute > like `#[impl_enum_variant_accessors]`. > > So, what are your thoughts about this? I think it would greatly > increase composability of > enums in general and reduce the amount of boilerplate code. :) My first thought is unrelated: it would be awesome if we had a lint mode that detected methods like `get`, `get_ref`, etc. - all these common patterns - and confirmed that their result type looked like what we expect. We could apply this to all the official libraries to try to stay consistent. From pcwalton at mozilla.com Fri Nov 1 12:29:30 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 01 Nov 2013 12:29:30 -0700 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: <5273FF84.7050009@mozilla.com> References: <5273F0DC.4040702@gmail.com> <5273FF84.7050009@mozilla.com> Message-ID: <5274011A.2080408@mozilla.com> On 11/1/13 12:22 PM, Brian Anderson wrote: > I think this (consistency) is the best argument in favor, though I do > love how evocative the word 'unwrap' is. I will not argue against this > change. I prefer `get` too. I find the argument that `unwrap` doesn't always move to be persuasive. Patrick From alex at crichton.co Fri Nov 1 12:30:00 2013 From: alex at crichton.co (Alex Crichton) Date: Fri, 1 Nov 2013 12:30:00 -0700 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: <5273F0DC.4040702@gmail.com> References: <5273F0DC.4040702@gmail.com> Message-ID: > # Renaming `unwrap` to `get` I would personally find this change a little odd because we still have a large number of `unwrap` methods thorughout the codebase. Most of these do indeed imply destruction of the enclosing type. A change like this would mean that when you decide to write your unwrapping method you must internally think about whether this always implies that the outer type would be destroyed or not. In my opinion, unwrap() on Option does exactly what it should and it's just a bug vs state of mind kind of thing. I would rather strive for consistency across all APIs than have a special case based on whether the type just happens to not be destroyed because the whole thing is implicitly copyable. From williamw520 at gmail.com Fri Nov 1 12:49:06 2013 From: williamw520 at gmail.com (William Wong) Date: Fri, 1 Nov 2013 12:49:06 -0700 Subject: [rust-dev] GZip and Deflate Message-ID: Date: Fri, 1 Nov 2013 11:40:18 -0400 > From: Benjamin Striegel > Cc: "rust-dev at mozilla.org" > Subject: Re: [rust-dev] GZip and Deflate > Message-ID: > < > CAAvrL-nzHeOnTsRP2ubSggrJpbjTCF0YtrJho8O3pHezxMwT4Q at mail.gmail.com> > Content-Type: text/plain; charset="iso-8859-1" > > I can't answer your questions, but I do want to say that this is very > interesting! > > > Rust compression is about 1.8 times slower, decompression is about 3 > times slower than gzip. > > Have you tried profiling this to see where our bottlenecks are? It would be > great if we could use this as an opportunity to improve our performance. > > I haven't profiled the code yet; will get to it once I get some time. The first priority was just to get things working correctly; there were some tricky edge cases on some large files with different sizes. They had been flushed out and fixed. Without profiling, it's uncertain to see where the bottlenecks are. The CPU was max'ed out so I suspect it's the compression code rather than the IO code. -------------- next part -------------- An HTML attachment was scrubbed... URL: From bjzaba at yahoo.com.au Fri Nov 1 12:49:19 2013 From: bjzaba at yahoo.com.au (Brendan Zabarauskas) Date: Sat, 2 Nov 2013 06:49:19 +1100 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: <5273FF84.7050009@mozilla.com> References: <5273F0DC.4040702@gmail.com> <5273FF84.7050009@mozilla.com> Message-ID: <553FA180-9ACB-460F-8DBB-5039BE8DC216@yahoo.com.au> > My first thought is unrelated: it would be awesome if we had a lint mode that detected methods like `get`, `get_ref`, etc. - all these common patterns - and confirmed that their result type looked like what we expect. We could apply this to all the official libraries to try to stay consistent. This could help to ensure that our APIs could remain reasonably intact through a transition to higher kinded types. ~Brendan From loebel.marvin at gmail.com Fri Nov 1 12:59:34 2013 From: loebel.marvin at gmail.com (=?ISO-8859-1?Q?Marvin_L=F6bel?=) Date: Fri, 01 Nov 2013 20:59:34 +0100 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: <5273FF84.7050009@mozilla.com> References: <5273F0DC.4040702@gmail.com> <5273FF84.7050009@mozilla.com> Message-ID: <52740826.7090702@gmail.com> On 11/01/2013 08:22 PM, Brian Anderson wrote: > My first reaction is that it's not obvious the difference between > `is_ok` and `ok`. Also, it would seem that `ok()` is required to > return a different type to make this work, which seems fairly > burdensome. If it *is* required to return a different type, then the > obvious thing to do is just transform it into `Option` which is > fairly nice since it just defers the problem to `Option` completely. The idea is that for example for `res: Result`, `res.ok()` returns `Option` and `res.err()` returns `Option`. So yes, it would just defer to Option. About the difference between `is_ok` and `ok` - fair enough. However I think the only way to make this more clear is to rename `ok()` and `err()` to something longer, which would make the chaining more verbose and has the problem that all short words that would fit are already heavily overloaded in rust terminology: - `as_ok()` and `as_err()` - `to_ok()` and `to_err()` - `get_ok()` and `get_err()` - `ok_get()` and `err_get()` Maybe a abbreviation of variant would work: - `ok_var()` and `err_var()` Seems to read nice at least: ~~~ res.ok_var().get(); res.err_var().get(); res.err_var().expect("..."); ~~~ -------------- next part -------------- An HTML attachment was scrubbed... URL: From williamw520 at gmail.com Fri Nov 1 13:01:26 2013 From: williamw520 at gmail.com (William Wong) Date: Fri, 1 Nov 2013 13:01:26 -0700 Subject: [rust-dev] (no subject) Message-ID: Date: Fri, 01 Nov 2013 09:14:26 -0700 > From: Patrick Walton > To: rust-dev at mozilla.org > Subject: Re: [rust-dev] GZip and Deflate > Message-ID: <5273D362.8040908 at mozilla.com> > Content-Type: text/plain; charset=ISO-8859-1; format=flowed > > On 11/1/13 8:40 AM, Benjamin Striegel wrote: > > I can't answer your questions, but I do want to say that this is very > > interesting! > > > > > Rust compression is about 1.8 times slower, decompression is about 3 > > times slower than gzip. > > > > Have you tried profiling this to see where our bottlenecks are? It would > > be great if we could use this as an opportunity to improve our > performance. > > It sounds like the problem is in miniz, so not in Rust code. > > (BTW, compile times for small crates are very gated on decompression of > metadata. Improvement of decompression speed improves compile times. > Although maybe we should just switch to Snappy or something.) > > Patrick > > I suspect that's the case but without profiling it's difficult to pinpoint the bottleneck. Snappy looks interesting. I'll look into it later when I get some times. -------------- next part -------------- An HTML attachment was scrubbed... URL: From williamw520 at gmail.com Fri Nov 1 13:04:32 2013 From: williamw520 at gmail.com (William Wong) Date: Fri, 1 Nov 2013 13:04:32 -0700 Subject: [rust-dev] GZip and Deflate Message-ID: > From: Brian Anderson > To: rust-dev at mozilla.org > Subject: Re: [rust-dev] GZip and Deflate > Message-ID: <5273F691.3060604 at mozilla.com> > Content-Type: text/plain; charset="iso-8859-1"; Format="flowed" > > >> 1. What license to assign for the new files? I use MPL currently. > > > > APL2/MIT dual license. Just copy the same headers that exist on all > > the other .rs files. > > Er, that's ASL2 (Apache License 2.0) > That's great. Thanks. I'll use that. -------------- next part -------------- An HTML attachment was scrubbed... URL: From loebel.marvin at gmail.com Fri Nov 1 13:26:20 2013 From: loebel.marvin at gmail.com (=?ISO-8859-1?Q?Marvin_L=F6bel?=) Date: Fri, 01 Nov 2013 21:26:20 +0100 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: References: <5273F0DC.4040702@gmail.com> Message-ID: <52740E6C.9000906@gmail.com> On 11/01/2013 08:30 PM, Alex Crichton wrote: >> # Renaming `unwrap` to `get` > I would personally find this change a little odd because we still have > a large number of `unwrap` methods thorughout the codebase. Most of > these do indeed imply destruction of the enclosing type. A change like > this would mean that when you decide to write your unwrapping method > you must internally think about whether this always implies that the > outer type would be destroyed or not. In my opinion, unwrap() on > Option does exactly what it should and it's just a bug vs state > of mind kind of thing. I would rather strive for consistency across > all APIs than have a special case based on whether the type just > happens to not be destroyed because the whole thing is implicitly > copyable. Imo we still keep consistency even with this rename. `get` is simply the more general term which we'd use for generic situations where we don't know anything about the type, while specific implementations can choose either name depending on situation. I think it's more useful to say "use the name unwrap if the function does something non-trivial". For example, `ARC::unwrap()` should probably not be renamed to `get` because it can block the task. From thadguidry at gmail.com Fri Nov 1 14:24:51 2013 From: thadguidry at gmail.com (Thad Guidry) Date: Fri, 1 Nov 2013 16:24:51 -0500 Subject: [rust-dev] (no subject) In-Reply-To: References: Message-ID: For my data experiments, I would rather like to see an LZ4 implementation https://code.google.com/p/lz4/ (a lossless, very, very, very, very, very, very, very, very fast decompression, with same compression - the very's are dependent on how many cpu cores you have :-) ) and it's BSD licensed. -- -Thad +ThadGuidry Thad on LinkedIn -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevin at sb.org Fri Nov 1 21:17:05 2013 From: kevin at sb.org (Kevin Ballard) Date: Fri, 1 Nov 2013 21:17:05 -0700 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: <52740826.7090702@gmail.com> References: <5273F0DC.4040702@gmail.com> <5273FF84.7050009@mozilla.com> <52740826.7090702@gmail.com> Message-ID: <36BEDF4E-24FF-4ED9-BC7B-36A6FFC29A7A@sb.org> On Nov 1, 2013, at 12:59 PM, Marvin L?bel wrote: > Maybe a abbreviation of variant would work: > > - `ok_var()` and `err_var()` > > Seems to read nice at least: > > ~~~ > res.ok_var().get(); > res.err_var().get(); > res.err_var().expect("..."); > ~~~ "var" here makes me think "variable". My two cents says go with `res.ok().get()` and `res.err().get()`. It's unfortunate that `ok()` can be read as if it were `is_ok()`, but I think people will get used to it pretty fast. -Kevin -------------- next part -------------- An HTML attachment was scrubbed... URL: From me at kevincantu.org Fri Nov 1 21:33:33 2013 From: me at kevincantu.org (Kevin Cantu) Date: Fri, 1 Nov 2013 21:33:33 -0700 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: <553FA180-9ACB-460F-8DBB-5039BE8DC216@yahoo.com.au> References: <5273F0DC.4040702@gmail.com> <5273FF84.7050009@mozilla.com> <553FA180-9ACB-460F-8DBB-5039BE8DC216@yahoo.com.au> Message-ID: Yeah, many of the overlaps between these APIs should or could be expressed as additional traits... -- Kevin On Nov 1, 2013 12:49 PM, "Brendan Zabarauskas" wrote: > > My first thought is unrelated: it would be awesome if we had a lint mode > that detected methods like `get`, `get_ref`, etc. - all these common > patterns - and confirmed that their result type looked like what we expect. > We could apply this to all the official libraries to try to stay consistent. > > This could help to ensure that our APIs could remain reasonably intact > through a transition to higher kinded types. > > ~Brendan > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at steveklabnik.com Fri Nov 1 23:02:15 2013 From: steve at steveklabnik.com (Steve Klabnik) Date: Fri, 1 Nov 2013 23:02:15 -0700 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: References: <5273F0DC.4040702@gmail.com> <5273FF84.7050009@mozilla.com> <553FA180-9ACB-460F-8DBB-5039BE8DC216@yahoo.com.au> Message-ID: <29443F7B-1D05-451F-9259-25EE5047755D@steveklabnik.com> Would a ruby-style ok?/ok work to replace is_ok/ok ? From oren at ben-kiki.org Sat Nov 2 00:40:14 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Sat, 2 Nov 2013 09:40:14 +0200 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: <29443F7B-1D05-451F-9259-25EE5047755D@steveklabnik.com> References: <5273F0DC.4040702@gmail.com> <5273FF84.7050009@mozilla.com> <553FA180-9ACB-460F-8DBB-5039BE8DC216@yahoo.com.au> <29443F7B-1D05-451F-9259-25EE5047755D@steveklabnik.com> Message-ID: I would love it if '?' was allowed at the end of any identifier, to make it natural to name boolean variables, methods, constants, etc. Having to say is_xxx is ugly IMO. A lint option ensuring this is only applied to boolean typed constructs could help reduce abuse, if this is seen as an issue. On Nov 2, 2013 8:02 AM, "Steve Klabnik" wrote: > Would a ruby-style ok?/ok work to replace is_ok/ok ? > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From andres.osinski at gmail.com Sat Nov 2 05:38:55 2013 From: andres.osinski at gmail.com (Andres Osinski) Date: Sat, 2 Nov 2013 10:38:55 -0200 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: References: <5273F0DC.4040702@gmail.com> <5273FF84.7050009@mozilla.com> <553FA180-9ACB-460F-8DBB-5039BE8DC216@yahoo.com.au> <29443F7B-1D05-451F-9259-25EE5047755D@steveklabnik.com> Message-ID: A '?' suffix for boolean methods would be fantastic. On Sat, Nov 2, 2013 at 4:40 AM, Oren Ben-Kiki wrote: > I would love it if '?' was allowed at the end of any identifier, to make it > natural to name boolean variables, methods, constants, etc. Having to say > is_xxx is ugly IMO. A lint option ensuring this is only applied to boolean > typed constructs could help reduce abuse, if this is seen as an issue. > > On Nov 2, 2013 8:02 AM, "Steve Klabnik" wrote: >> >> Would a ruby-style ok?/ok work to replace is_ok/ok ? >> _______________________________________________ >> 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 > -- Andr?s Osinski http://www.andresosinski.com.ar/ From niko at alum.mit.edu Sat Nov 2 08:34:57 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Sat, 2 Nov 2013 11:34:57 -0400 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: <5273F0DC.4040702@gmail.com> References: <5273F0DC.4040702@gmail.com> Message-ID: <20131102153457.GE1305@Mr-Bennet> I am generally in favor of this proposal. It seems to be a reasonable way forward. It is unclear to me how many types would benefit from this approach of having methods for each variant, but `Result` certainly does. With respect to possible confusion between `is_ok()` and `ok()` -- I think that the presence of a boolean return type should help with that. (That is, if you write `if foo.ok() { ... }` the compiler will catch it readily enough) Some of the methods on `Result`, however, can't be implemented in terms of this approach. For example, `chain` and `chain_err` really need to keep the `Result` return type. But I guess that's clear enough. One specific comment on your message: > - There was talk about making `Result` use an `~Error` trait object > instead of a generic type `E`, which could invalidate most of this > email. However, this could also just mean that you usually will see > `Result` in the wild, for which this proposal still > applies. Additionally, even if the Pattern becomes useless for > Result, the problem still exists for any other newtype variant > enums, so I'd like to see it get used anyway. It is not clear to me why moving to a `~Error` object would have any effect on this proposal. `err()` would just return `Option<~Error>` in that case, right? Niko From astrieanna at gmail.com Sat Nov 2 12:10:34 2013 From: astrieanna at gmail.com (Leah Hanson) Date: Sat, 2 Nov 2013 15:10:34 -0400 Subject: [rust-dev] How would you map one vector to a vector of a different element type? Message-ID: Hi, I have a ~[~str]. I have code that will turn a ~str into a Port. I want to end up with a [Port]. (or ~ or @ or whatever. I just want to be able to iterate over the Ports later.) Since I'm not sure what looping construct to use, I tried with a for-each loop. ~~~ let ports = for s in myvect.iter() { let (pport, cchan) = stream(); do spawn { cchan.send(fun(*s)) } pport }; ~~~ As you might, expect I got an error: error: mismatched types: expected `()` but found `std::comm::Port` (expected () but found struct std::comm::Port) >From this, I take it that for loops must return `()`, rather than an actual value. When I searched for a map function in the documentation, I only found a Map type. How would you map one vector to a vector of a different element type? Thanks, Leah -------------- next part -------------- An HTML attachment was scrubbed... URL: From bytbox at gmail.com Sat Nov 2 12:23:30 2013 From: bytbox at gmail.com (Scott Lawrence) Date: Sat, 2 Nov 2013 15:23:30 -0400 (EDT) Subject: [rust-dev] How would you map one vector to a vector of a different element type? In-Reply-To: References: Message-ID: I would think: let ports = do myvect.iter().map { |e| something(e) } On Sat, 2 Nov 2013, Leah Hanson wrote: > Hi, > > I have a ~[~str]. I have code that will turn a ~str into a Port. > > I want to end up with a [Port]. (or ~ or @ or whatever. I just want > to be able to iterate over the Ports later.) > > Since I'm not sure what looping construct to use, I tried with a for-each > loop. > > ~~~ > let ports = for s in myvect.iter() { > let (pport, cchan) = stream(); > do spawn { > cchan.send(fun(*s)) > } > pport > }; > ~~~ > > As you might, expect I got an error: > error: mismatched types: expected `()` but found `std::comm::Port` > (expected () but found struct std::comm::Port) > >> From this, I take it that for loops must return `()`, rather than an actual > value. When I searched for a map function in the documentation, I only > found a Map type. > > How would you map one vector to a vector of a different element type? > > Thanks, > Leah > -- Scott Lawrence From astrieanna at gmail.com Sat Nov 2 13:04:24 2013 From: astrieanna at gmail.com (Leah Hanson) Date: Sat, 2 Nov 2013 16:04:24 -0400 Subject: [rust-dev] How would you map one vector to a vector of a different element type? In-Reply-To: References: Message-ID: Thanks, Scott, I think that's closer. However, now I'm having trouble with my pointer types. Using the element inside a spawn means that I need to capture the owned string in the right way so that the compiler allows me to give it to the other task. This version: ~~~ let ports = do myvect.iter().map |s| { let (pport, cchan) = stream(); do spawn { cchan.send(fun(*s)) } pport }; ~~~ gives me pointer-type related errors: - error: cannot move out of dereference of & pointer - cchan.send(fun(*s)) - error: cannot borrow immutable local variable as mutable - when I iterate over the Ports later - error: cannot capture variable of type `&~str`, which does not fulfill `Send`, in a bounded closure - cchan.send(fun(*s)) I also tried a version with |&s| and cchan.send(fun(s)), which gave me different errors: - error: cannot move out of captured outer variable in a heap closure - cchan.send(fun(*s)) - error: cannot move out of dereference of & pointer - on the |&s| - error: cannot borrow immutable local variable as mutable - when I iterate over the Ports later I'm very new to Rust. What do I need to do to let the compiler know that I'm not going to use anything in the first vec anymore? That I just want the ~str pointers directly? (I put the |s| outside the {} because putting it inside seemed to confuse things -- in that case, rustc expected an identifier instead of the `let` that comes next, so I assumed that `do v.iter().map {|s| ...}` is a syntax error.) Thanks, Leah On Sat, Nov 2, 2013 at 3:23 PM, Scott Lawrence wrote: > I would think: > > let ports = do myvect.iter().map { |e| something(e) } > > > On Sat, 2 Nov 2013, Leah Hanson wrote: > > Hi, >> >> I have a ~[~str]. I have code that will turn a ~str into a Port. >> >> I want to end up with a [Port]. (or ~ or @ or whatever. I just want >> to be able to iterate over the Ports later.) >> >> Since I'm not sure what looping construct to use, I tried with a for-each >> loop. >> >> ~~~ >> let ports = for s in myvect.iter() { >> let (pport, cchan) = stream(); >> do spawn { >> cchan.send(fun(*s)) >> } >> pport >> }; >> ~~~ >> >> As you might, expect I got an error: >> error: mismatched types: expected `()` but found `std::comm::Port` >> (expected () but found struct std::comm::Port) >> >> From this, I take it that for loops must return `()`, rather than an >>> actual >>> >> value. When I searched for a map function in the documentation, I only >> found a Map type. >> >> How would you map one vector to a vector of a different element type? >> >> Thanks, >> Leah >> >> > -- > Scott Lawrence > -------------- next part -------------- An HTML attachment was scrubbed... URL: From bjzaba at yahoo.com.au Sat Nov 2 13:24:10 2013 From: bjzaba at yahoo.com.au (Brendan Zabarauskas) Date: Sun, 3 Nov 2013 07:24:10 +1100 Subject: [rust-dev] How would you map one vector to a vector of a different element type? In-Reply-To: References: Message-ID: <1422576C-8467-413D-AB93-BB96924174CC@yahoo.com.au> You?re trying to move the ~strs out of the vector. You?ll need to use `move_iter`: ~~~ let ports = do myvect.move_iter().map |s| { let (pport, cchan) = stream(); do spawn { cchan.send(fun(s)) } pport }.to_owned_vec(); ~~~ Also note the use of `to_owned_vec`. `map` lazily returns a `Map` iterator - you need to explicitly drain it. (Note I haven?t tried compiling this) ~Brendan On 3 Nov 2013, at 7:04 am, Leah Hanson wrote: > Thanks, Scott, I think that's closer. > > However, now I'm having trouble with my pointer types. Using the element inside a spawn means that I need to capture the owned string in the right way so that the compiler allows me to give it to the other task. > > This version: > ~~~ > let ports = do myvect.iter().map |s| { > let (pport, cchan) = stream(); > do spawn { > cchan.send(fun(*s)) > } > pport > }; > ~~~ > gives me pointer-type related errors: > ? error: cannot move out of dereference of & pointer > ? cchan.send(fun(*s)) > ? error: cannot borrow immutable local variable as mutable > ? when I iterate over the Ports later > ? error: cannot capture variable of type `&~str`, which does not fulfill `Send`, in a bounded closure > ? cchan.send(fun(*s)) > I also tried a version with |&s| and cchan.send(fun(s)), which gave me different errors: > ? error: cannot move out of captured outer variable in a heap closure > ? cchan.send(fun(*s)) > ? error: cannot move out of dereference of & pointer > ? on the |&s| > ? error: cannot borrow immutable local variable as mutable > ? when I iterate over the Ports later > > I'm very new to Rust. What do I need to do to let the compiler know that I'm not going to use anything in the first vec anymore? That I just want the ~str pointers directly? > > (I put the |s| outside the {} because putting it inside seemed to confuse things -- in that case, rustc expected an identifier instead of the `let` that comes next, so I assumed that `do v.iter().map {|s| ...}` is a syntax error.) > > Thanks, > Leah > > > > > On Sat, Nov 2, 2013 at 3:23 PM, Scott Lawrence wrote: > I would think: > > let ports = do myvect.iter().map { |e| something(e) } > > > On Sat, 2 Nov 2013, Leah Hanson wrote: > > Hi, > > I have a ~[~str]. I have code that will turn a ~str into a Port. > > I want to end up with a [Port]. (or ~ or @ or whatever. I just want > to be able to iterate over the Ports later.) > > Since I'm not sure what looping construct to use, I tried with a for-each > loop. > > ~~~ > let ports = for s in myvect.iter() { > let (pport, cchan) = stream(); > do spawn { > cchan.send(fun(*s)) > } > pport > }; > ~~~ > > As you might, expect I got an error: > error: mismatched types: expected `()` but found `std::comm::Port` > (expected () but found struct std::comm::Port) > > From this, I take it that for loops must return `()`, rather than an actual > value. When I searched for a map function in the documentation, I only > found a Map type. > > How would you map one vector to a vector of a different element type? > > Thanks, > Leah > > > -- > Scott Lawrence > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From astrieanna at gmail.com Sat Nov 2 14:05:05 2013 From: astrieanna at gmail.com (Leah Hanson) Date: Sat, 2 Nov 2013 17:05:05 -0400 Subject: [rust-dev] How would you map one vector to a vector of a different element type? In-Reply-To: <1422576C-8467-413D-AB93-BB96924174CC@yahoo.com.au> References: <1422576C-8467-413D-AB93-BB96924174CC@yahoo.com.au> Message-ID: Thanks, Brendan. :) You?re trying to move the ~strs out of the vector. You?ll need to use > `move_iter`: > Is this "moving" about moving memory around or about promising the compiler that I won't use those elements of the vector again? > ~~~ > let ports = do myvect.move_iter().map |s| { > let (pport, cchan) = stream(); > do spawn { > cchan.send(fun(s)) > } > pport > }.to_owned_vec(); > There is still a problem because something (I guess the `do spawn {...}`) is a "heap closure". - error: cannot move out of captured outer variable in a heap closure - cchan.send(fun(s)) I think that this error message is complaining because I'm trying to move s, the ~str that the `do spawn {...}` closes over, to a new task. And I'm not allowed to move it because it is apparently a heap closure. Is there some other kind of closure that does work here? Or some way to make this not a closure? Thanks, Leah On Sat, Nov 2, 2013 at 4:24 PM, Brendan Zabarauskas wrote: > You?re trying to move the ~strs out of the vector. You?ll need to use > `move_iter`: > > ~~~ > let ports = do myvect.move_iter().map |s| { > let (pport, cchan) = stream(); > do spawn { > cchan.send(fun(s)) > } > pport > }.to_owned_vec(); > ~~~ > > Also note the use of `to_owned_vec`. `map` lazily returns a `Map` iterator > - you need to explicitly drain it. > > (Note I haven?t tried compiling this) > > ~Brendan > > On 3 Nov 2013, at 7:04 am, Leah Hanson wrote: > > > Thanks, Scott, I think that's closer. > > > > However, now I'm having trouble with my pointer types. Using the element > inside a spawn means that I need to capture the owned string in the right > way so that the compiler allows me to give it to the other task. > > > > This version: > > ~~~ > > let ports = do myvect.iter().map |s| { > > let (pport, cchan) = stream(); > > do spawn { > > cchan.send(fun(*s)) > > } > > pport > > }; > > ~~~ > > gives me pointer-type related errors: > > ? error: cannot move out of dereference of & pointer > > ? cchan.send(fun(*s)) > > ? error: cannot borrow immutable local variable as mutable > > ? when I iterate over the Ports later > > ? error: cannot capture variable of type `&~str`, which does not > fulfill `Send`, in a bounded closure > > ? cchan.send(fun(*s)) > > I also tried a version with |&s| and cchan.send(fun(s)), which gave me > different errors: > > ? error: cannot move out of captured outer variable in a heap > closure > > ? cchan.send(fun(*s)) > > ? error: cannot move out of dereference of & pointer > > ? on the |&s| > > ? error: cannot borrow immutable local variable as mutable > > ? when I iterate over the Ports later > > > > I'm very new to Rust. What do I need to do to let the compiler know that > I'm not going to use anything in the first vec anymore? That I just want > the ~str pointers directly? > > > > (I put the |s| outside the {} because putting it inside seemed to > confuse things -- in that case, rustc expected an identifier instead of the > `let` that comes next, so I assumed that `do v.iter().map {|s| ...}` is a > syntax error.) > > > > Thanks, > > Leah > > > > > > > > > > On Sat, Nov 2, 2013 at 3:23 PM, Scott Lawrence wrote: > > I would think: > > > > let ports = do myvect.iter().map { |e| something(e) } > > > > > > On Sat, 2 Nov 2013, Leah Hanson wrote: > > > > Hi, > > > > I have a ~[~str]. I have code that will turn a ~str into a Port. > > > > I want to end up with a [Port]. (or ~ or @ or whatever. I just want > > to be able to iterate over the Ports later.) > > > > Since I'm not sure what looping construct to use, I tried with a for-each > > loop. > > > > ~~~ > > let ports = for s in myvect.iter() { > > let (pport, cchan) = stream(); > > do spawn { > > cchan.send(fun(*s)) > > } > > pport > > }; > > ~~~ > > > > As you might, expect I got an error: > > error: mismatched types: expected `()` but found `std::comm::Port` > > (expected () but found struct std::comm::Port) > > > > From this, I take it that for loops must return `()`, rather than an > actual > > value. When I searched for a map function in the documentation, I only > > found a Map type. > > > > How would you map one vector to a vector of a different element type? > > > > Thanks, > > Leah > > > > > > -- > > Scott Lawrence > > > > _______________________________________________ > > Rust-dev mailing list > > Rust-dev at mozilla.org > > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From tkuehn at cmu.edu Sat Nov 2 14:20:59 2013 From: tkuehn at cmu.edu (Tim Kuehn) Date: Sat, 2 Nov 2013 17:20:59 -0400 Subject: [rust-dev] How would you map one vector to a vector of a different element type? In-Reply-To: References: <1422576C-8467-413D-AB93-BB96924174CC@yahoo.com.au> Message-ID: Instead of `do spawn` try `do spawn_with(s) |s| { ... }`. Then the closure won't close over s, but rather take it as an argument, allowing it to move it out. Cheers On Sat, Nov 2, 2013 at 5:05 PM, Leah Hanson wrote: > Thanks, Brendan. :) > > You?re trying to move the ~strs out of the vector. You?ll need to use >> `move_iter`: >> > Is this "moving" about moving memory around or about promising the > compiler that I won't use those elements of the vector again? > > >> ~~~ >> let ports = do myvect.move_iter().map |s| { >> let (pport, cchan) = stream(); >> do spawn { >> cchan.send(fun(s)) >> } >> pport >> }.to_owned_vec(); >> > > There is still a problem because something (I guess the `do spawn {...}`) > is a "heap closure". > > - error: cannot move out of captured outer variable in a heap closure > - cchan.send(fun(s)) > > I think that this error message is complaining because I'm trying to move > s, the ~str that the `do spawn {...}` closes over, to a new task. > And I'm not allowed to move it because it is apparently a heap closure. > Is there some other kind of closure that does work here? Or some way to > make this not a closure? > > Thanks, > Leah > > > > On Sat, Nov 2, 2013 at 4:24 PM, Brendan Zabarauskas wrote: > >> You?re trying to move the ~strs out of the vector. You?ll need to use >> `move_iter`: >> >> ~~~ >> let ports = do myvect.move_iter().map |s| { >> let (pport, cchan) = stream(); >> do spawn { >> cchan.send(fun(s)) >> } >> pport >> }.to_owned_vec(); >> ~~~ >> >> Also note the use of `to_owned_vec`. `map` lazily returns a `Map` >> iterator - you need to explicitly drain it. >> >> (Note I haven?t tried compiling this) >> >> ~Brendan >> >> On 3 Nov 2013, at 7:04 am, Leah Hanson wrote: >> >> > Thanks, Scott, I think that's closer. >> > >> > However, now I'm having trouble with my pointer types. Using the >> element inside a spawn means that I need to capture the owned string in the >> right way so that the compiler allows me to give it to the other task. >> > >> > This version: >> > ~~~ >> > let ports = do myvect.iter().map |s| { >> > let (pport, cchan) = stream(); >> > do spawn { >> > cchan.send(fun(*s)) >> > } >> > pport >> > }; >> > ~~~ >> > gives me pointer-type related errors: >> > ? error: cannot move out of dereference of & pointer >> > ? cchan.send(fun(*s)) >> > ? error: cannot borrow immutable local variable as mutable >> > ? when I iterate over the Ports later >> > ? error: cannot capture variable of type `&~str`, which does not >> fulfill `Send`, in a bounded closure >> > ? cchan.send(fun(*s)) >> > I also tried a version with |&s| and cchan.send(fun(s)), which gave me >> different errors: >> > ? error: cannot move out of captured outer variable in a heap >> closure >> > ? cchan.send(fun(*s)) >> > ? error: cannot move out of dereference of & pointer >> > ? on the |&s| >> > ? error: cannot borrow immutable local variable as mutable >> > ? when I iterate over the Ports later >> > >> > I'm very new to Rust. What do I need to do to let the compiler know >> that I'm not going to use anything in the first vec anymore? That I just >> want the ~str pointers directly? >> > >> > (I put the |s| outside the {} because putting it inside seemed to >> confuse things -- in that case, rustc expected an identifier instead of the >> `let` that comes next, so I assumed that `do v.iter().map {|s| ...}` is a >> syntax error.) >> > >> > Thanks, >> > Leah >> > >> > >> > >> > >> > On Sat, Nov 2, 2013 at 3:23 PM, Scott Lawrence >> wrote: >> > I would think: >> > >> > let ports = do myvect.iter().map { |e| something(e) } >> > >> > >> > On Sat, 2 Nov 2013, Leah Hanson wrote: >> > >> > Hi, >> > >> > I have a ~[~str]. I have code that will turn a ~str into a Port. >> > >> > I want to end up with a [Port]. (or ~ or @ or whatever. I just >> want >> > to be able to iterate over the Ports later.) >> > >> > Since I'm not sure what looping construct to use, I tried with a >> for-each >> > loop. >> > >> > ~~~ >> > let ports = for s in myvect.iter() { >> > let (pport, cchan) = stream(); >> > do spawn { >> > cchan.send(fun(*s)) >> > } >> > pport >> > }; >> > ~~~ >> > >> > As you might, expect I got an error: >> > error: mismatched types: expected `()` but found `std::comm::Port` >> > (expected () but found struct std::comm::Port) >> > >> > From this, I take it that for loops must return `()`, rather than an >> actual >> > value. When I searched for a map function in the documentation, I only >> > found a Map type. >> > >> > How would you map one vector to a vector of a different element type? >> > >> > Thanks, >> > Leah >> > >> > >> > -- >> > Scott Lawrence >> > >> > _______________________________________________ >> > 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: From simon.sapin at exyr.org Sat Nov 2 14:21:42 2013 From: simon.sapin at exyr.org (Simon Sapin) Date: Sat, 02 Nov 2013 21:21:42 +0000 Subject: [rust-dev] How would you map one vector to a vector of a different element type? In-Reply-To: References: <1422576C-8467-413D-AB93-BB96924174CC@yahoo.com.au> Message-ID: <52756CE6.8070509@exyr.org> Le 02/11/2013 21:05, Leah Hanson a ?crit : > Thanks, Brendan. :) > > You?re trying to move the ~strs out of the vector. You?ll need to > use `move_iter`: > > Is this "moving" about moving memory around or about promising the > compiler that I won't use those elements of the vector again? ~str is an "owned" string that can only have one owner. If you move it (give away ownership) you can not use it anymore. The compiler verifies that. This is why move_iter() consumes a vector (takes ownership), while iter() only gives you references (& pointers) to the elements. This allows the memory to be freed when the owner disappears, without garbage collection or reference counting. > ~~~ > let ports = do myvect.move_iter().map |s| { > let (pport, cchan) = stream(); > do spawn { > cchan.send(fun(s)) > } > pport > }.to_owned_vec(); > > > There is still a problem because something (I guess the `do spawn > {...}`) is a "heap closure". > > * error: cannot move out of captured outer variable in a heap closure > o cchan.send(fun(s)) > > I think that this error message is complaining because I'm trying to > move s, the ~str that the `do spawn {...}` closes over, to a new task. > And I'm not allowed to move it because it is apparently a heap closure. > Is there some other kind of closure that does work here? Or some way to > make this not a closure? I?m not sure, but you may need to use spawn_with to move something into a task: do spawn_with(s) |s| { ... } -- Simon Sapin From astrieanna at gmail.com Sat Nov 2 15:45:36 2013 From: astrieanna at gmail.com (Leah Hanson) Date: Sat, 2 Nov 2013 18:45:36 -0400 Subject: [rust-dev] How would you map one vector to a vector of a different element type? In-Reply-To: <52756CE6.8070509@exyr.org> References: <1422576C-8467-413D-AB93-BB96924174CC@yahoo.com.au> <52756CE6.8070509@exyr.org> Message-ID: Thanks! :D It compiles now! (and works) The working code is here: https://github.com/astrieanna/rust-fun/blob/one_worker_per_element/pmap.rs Best, Leah On Sat, Nov 2, 2013 at 5:21 PM, Simon Sapin wrote: > Le 02/11/2013 21:05, Leah Hanson a ?crit : > > Thanks, Brendan. :) >> >> You?re trying to move the ~strs out of the vector. You?ll need to >> use `move_iter`: >> >> Is this "moving" about moving memory around or about promising the >> compiler that I won't use those elements of the vector again? >> > > ~str is an "owned" string that can only have one owner. If you move it > (give away ownership) you can not use it anymore. The compiler verifies > that. > > This is why move_iter() consumes a vector (takes ownership), while iter() > only gives you references (& pointers) to the elements. > > This allows the memory to be freed when the owner disappears, without > garbage collection or reference counting. > > > ~~~ >> let ports = do myvect.move_iter().map |s| { >> let (pport, cchan) = stream(); >> do spawn { >> cchan.send(fun(s)) >> } >> pport >> }.to_owned_vec(); >> >> >> There is still a problem because something (I guess the `do spawn >> {...}`) is a "heap closure". >> >> * error: cannot move out of captured outer variable in a heap closure >> o cchan.send(fun(s)) >> >> >> I think that this error message is complaining because I'm trying to >> move s, the ~str that the `do spawn {...}` closes over, to a new task. >> And I'm not allowed to move it because it is apparently a heap closure. >> Is there some other kind of closure that does work here? Or some way to >> make this not a closure? >> > > I?m not sure, but you may need to use spawn_with to move something into a > task: > > do spawn_with(s) |s| { ... } > > -- > Simon Sapin > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jon.mb at proinbox.com Sat Nov 2 17:34:59 2013 From: jon.mb at proinbox.com (John Mija) Date: Sun, 03 Nov 2013 00:34:59 +0000 Subject: [rust-dev] Checking error at opening file Message-ID: <52759A33.9060707@proinbox.com> How to check an error at opening a file but without closing its file descriptor? use std::path; use std::rt::io; use std::rt::io::file; let filename = "/some/path"; let f = file::open(&path::Path::new(filename), io::Open, io::Read); From loebel.marvin at gmail.com Sat Nov 2 19:09:59 2013 From: loebel.marvin at gmail.com (=?ISO-8859-1?Q?Marvin_L=F6bel?=) Date: Sun, 03 Nov 2013 03:09:59 +0100 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: <20131102153457.GE1305@Mr-Bennet> References: <5273F0DC.4040702@gmail.com> <20131102153457.GE1305@Mr-Bennet> Message-ID: <5275B077.10504@gmail.com> On 11/02/2013 04:34 PM, Niko Matsakis wrote: > I am generally in favor of this proposal. It seems to be a reasonable > way forward. It is unclear to me how many types would benefit from > this approach of having methods for each variant, but `Result` > certainly does. > > With respect to possible confusion between `is_ok()` and `ok()` -- I > think that the presence of a boolean return type should help with > that. (That is, if you write `if foo.ok() { ... }` the compiler will > catch it readily enough) That's my thinking too, we're not using a statically typed language for nothing after all. > Some of the methods on `Result`, however, can't be implemented in > terms of this approach. For example, `chain` and `chain_err` really > need to keep the `Result` return type. But I guess that's clear > enough. Right, `and` and `or` (which is what we call `chain` and `chain_err` these days) will still need to be implemented on `Result` directly, just like `map` and `map_err`. In fact, the only methods that would actually fall away on todays `Result` would be `expect`, `expect_err`, a lone `get_ref` and the iterator constructors. I'll send an mail containing a working patch in a follow up to this thread. > One specific comment on your message: > >> - There was talk about making `Result` use an `~Error` trait object >> instead of a generic type `E`, which could invalidate most of this >> email. However, this could also just mean that you usually will see >> `Result` in the wild, for which this proposal still >> applies. Additionally, even if the Pattern becomes useless for >> Result, the problem still exists for any other newtype variant >> enums, so I'd like to see it get used anyway. > It is not clear to me why moving to a `~Error` object would have > any effect on this proposal. `err()` would just return `Option<~Error>` > in that case, right? Well, that would still work, that much is true. However the `as_ref` and `as_mut_ref` adapters might pose some problems. Worst case we'll need to have `ok_ref`, `ok_mut`, `err_ref` and `err_mut` adapters instead, which would be unfortunate, but still better than duplicating all of `Option`s composable API across `Result`. Kimundi From loebel.marvin at gmail.com Sat Nov 2 20:00:06 2013 From: loebel.marvin at gmail.com (=?ISO-8859-1?Q?Marvin_L=F6bel?=) Date: Sun, 03 Nov 2013 04:00:06 +0100 Subject: [rust-dev] RFC about std::option and std::result API In-Reply-To: <5273F0DC.4040702@gmail.com> References: <5273F0DC.4040702@gmail.com> Message-ID: <5275BC36.9010203@gmail.com> I prepared a patch that renames everything as proposed with the exception of Option's unwrap -> get change here: https://github.com/Kimundi/rust/commit/752912f75f6334da87a476fffc2475a3dfa5639d I touches ~ 300 lines, most of them being the unwrap -> get and unwrap_err -> err_get fallout. In fact, only a few singular places actually needed to call a `ok()`, `err()` or `as_ref` adapter at all, most just unwrapped or mapped. I discovered another issue though: Right now we require a ToStr bound on Results error type E. Ignoring for a moment that ToStr is on the way out, the idea behind that bound is that the unwrapping functions could provide a useful error message in the common "unwrap an Err value" case. Changing Result to use composition through as_ref() and ok() complicates that goal: - The first problem is that ok(self) -> Option throws away the Error type, which means you'd be only ever be able to see the informative error message if you use the shorthand get() and err_get() methods, which leads to inconsistency. - The second, more interesting problem arises with as_ref. By turning Result into Result<&T, &E>, we changed the self type so that now an ToStr bound on &E is necessary. This could be solved by a generic ToStr impl of &T for all T: ToStr, however that could decrease usability of ToStr, as users might now get seemingly random "&" prefixes all over the place in their to_str() outputs. The good news is that those two issues might cancel each other out: If it gets decided that a composable, Option-API-leveraging interface is more important for Result than potentially more usable error messages in case of unwrapping an Err value, then we can just remove the ToStr bound and provide consistent, if generic, error messages. The patch above takes that approach for simplicity. Kimundi From alex at crichton.co Sat Nov 2 22:42:33 2013 From: alex at crichton.co (Alex Crichton) Date: Sat, 2 Nov 2013 22:42:33 -0700 Subject: [rust-dev] Checking error at opening file In-Reply-To: <52759A33.9060707@proinbox.com> References: <52759A33.9060707@proinbox.com> Message-ID: This api is a little in flux (hopefully #10179 will land soon), but I'm not quite sure what you mean about keeping the file descriptor open. If there was an error opening the file, then a file descriptor was never allocated and there's nothing to keep open. Regardless, once my pull request lands, your example would look something like: use std::rt::io; use std::rt::io::File; match io::result(|| File::open(&Path::new("/some/path")) { Ok(file) => { /* file was successfully opened, it existed */ } Err(e) => { /* file couldn't be opened, error contained in e */ } } On Sat, Nov 2, 2013 at 5:34 PM, John Mija wrote: > How to check an error at opening a file but without closing its file > descriptor? > > use std::path; > use std::rt::io; > use std::rt::io::file; > > let filename = "/some/path"; > let f = file::open(&path::Path::new(filename), io::Open, io::Read); > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From jon.mb at proinbox.com Sun Nov 3 02:19:51 2013 From: jon.mb at proinbox.com (John Mija) Date: Sun, 03 Nov 2013 10:19:51 +0000 Subject: [rust-dev] Checking error at opening file In-Reply-To: References: <52759A33.9060707@proinbox.com> Message-ID: <52762347.4060503@proinbox.com> Hi Alex, I had seen an example at http://static.rust-lang.org/doc/master/std/rt/io/file/fn.open.html which closes the file at the end of a block. I simply wants to open a file, checking if there is any error, for later to can read it line by line until the end of file. I was wrong using the term "closing its file descriptor". El 03/11/13 05:42, Alex Crichton escribi?: > This api is a little in flux (hopefully #10179 will land soon), but > I'm not quite sure what you mean about keeping the file descriptor > open. If there was an error opening the file, then a file descriptor > was never allocated and there's nothing to keep open. Regardless, once > my pull request lands, your example would look something like: > > use std::rt::io; > use std::rt::io::File; > > match io::result(|| File::open(&Path::new("/some/path")) { > Ok(file) => { /* file was successfully opened, it existed */ } > Err(e) => { /* file couldn't be opened, error contained in e */ } > } > > On Sat, Nov 2, 2013 at 5:34 PM, John Mija wrote: >> How to check an error at opening a file but without closing its file >> descriptor? >> >> use std::path; >> use std::rt::io; >> use std::rt::io::file; >> >> let filename = "/some/path"; >> let f = file::open(&path::Path::new(filename), io::Open, io::Read); >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > From lists at dhardy.name Sun Nov 3 04:28:59 2013 From: lists at dhardy.name (Diggory Hardy) Date: Sun, 03 Nov 2013 13:28:59 +0100 Subject: [rust-dev] Checking error at opening file In-Reply-To: <52762347.4060503@proinbox.com> References: <52759A33.9060707@proinbox.com> <52762347.4060503@proinbox.com> Message-ID: <1835411.AmDKot32ky@tph-l10036> Well, your program needs to handle the error somehow if there is one. Something like this could work (though syntax may be wrong): let file = match io::result(|| File::open(&Path::new("/some/path")) { Ok(f) => f /* i.e. file is set to f */ Err(e) => fail!("cannot open file") } Alternatively make your function return some "error value" instead of using the fail!(...) macro. On Sunday 03 November 2013 10:19:51 John Mija wrote: > Hi Alex, > > I had seen an example at > http://static.rust-lang.org/doc/master/std/rt/io/file/fn.open.html which > closes the file at the end of a block. > > I simply wants to open a file, checking if there is any error, for later > to can read it line by line until the end of file. I was wrong using the > term "closing its file descriptor". > > El 03/11/13 05:42, Alex Crichton escribi?: > > This api is a little in flux (hopefully #10179 will land soon), but > > I'm not quite sure what you mean about keeping the file descriptor > > open. If there was an error opening the file, then a file descriptor > > was never allocated and there's nothing to keep open. Regardless, once > > my pull request lands, your example would look something like: > > > > use std::rt::io; > > use std::rt::io::File; > > > > match io::result(|| File::open(&Path::new("/some/path")) { > > > > Ok(file) => { /* file was successfully opened, it existed */ } > > Err(e) => { /* file couldn't be opened, error contained in e */ } > > > > } > > > > On Sat, Nov 2, 2013 at 5:34 PM, John Mija wrote: > >> How to check an error at opening a file but without closing its file > >> descriptor? > >> > >> use std::path; > >> use std::rt::io; > >> use std::rt::io::file; > >> > >> let filename = "/some/path"; > >> let f = file::open(&path::Path::new(filename), io::Open, io::Read); > >> _______________________________________________ > >> 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 -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 490 bytes Desc: This is a digitally signed message part. URL: From hatahet at gmail.com Sun Nov 3 11:03:44 2013 From: hatahet at gmail.com (Ziad Hatahet) Date: Sun, 3 Nov 2013 11:03:44 -0800 Subject: [rust-dev] Checking error at opening file In-Reply-To: References: <52759A33.9060707@proinbox.com> Message-ID: Out of curiosity, why not make File::open() return a Result<> instead of Option<> like it does now? The current implementation already seems to be matching against the result of fs_open() and returning None if the result is Err(). So why the extra level of indirection and raising a condition in that case? -- Ziad On Sat, Nov 2, 2013 at 10:42 PM, Alex Crichton wrote: > This api is a little in flux (hopefully #10179 will land soon), but > I'm not quite sure what you mean about keeping the file descriptor > open. If there was an error opening the file, then a file descriptor > was never allocated and there's nothing to keep open. Regardless, once > my pull request lands, your example would look something like: > > use std::rt::io; > use std::rt::io::File; > > match io::result(|| File::open(&Path::new("/some/path")) { > Ok(file) => { /* file was successfully opened, it existed */ } > Err(e) => { /* file couldn't be opened, error contained in e */ } > } > > On Sat, Nov 2, 2013 at 5:34 PM, John Mija wrote: > > How to check an error at opening a file but without closing its file > > descriptor? > > > > use std::path; > > use std::rt::io; > > use std::rt::io::file; > > > > let filename = "/some/path"; > > let f = file::open(&path::Path::new(filename), io::Open, io::Read); > > _______________________________________________ > > 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: From alex at crichton.co Sun Nov 3 21:42:16 2013 From: alex at crichton.co (Alex Crichton) Date: Sun, 3 Nov 2013 21:42:16 -0800 Subject: [rust-dev] Checking error at opening file In-Reply-To: References: <52759A33.9060707@proinbox.com> Message-ID: > Out of curiosity, why not make File::open() return a Result<> instead of > Option<> like it does now? This is a relic of I/O using conditions. The idea here is that if you wanted to catch the condition, you can indeed catch it (and do something appropriate). If you don't catch it then the task fails and there's no need to return an Option anyway. The other idea here is that because the error is signaled by the condition, the return value of the function can be something that's "always successful". In this case the definition of success is returning something which is a Reader/Seek. The I/O library provides an implementation of Reader/Seek on Option, so in cases where we can't actually return a reader (because of the error), None is returned. The motivation behind this strategy is to reduce boilerplate code necessary for handling errors in I/O. Instead if checking for errors at each operation you can check for errors during a block of operations (or at least I believe that's the idea). All that being said, it's likely that conditions will be removed from the api so the return value will indeed be Result as one might expect. This is still a little in flux now (mostly on the error portion of the result), and as a consequence this means that almost any I/O operation will be Result. From oren at ben-kiki.org Sun Nov 3 22:11:29 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Mon, 4 Nov 2013 08:11:29 +0200 Subject: [rust-dev] Separating heaps from tasks Message-ID: I am toying with a non-trivial Rust project to get a feel for the language. There's a pattern I keep seeing in my code which isn't easy to express in Rust. I wonder what the "right thing to do" is here. The pattern is as follows. I have some container, which contains some components of different types. The container as a whole is send-able . The components form a complex graph (with cycles). What I'd like to do is something like this: - Declare a pool of objects of some types, which is held by the container. - Declare pointer-to-object whose scope is the container; that is, the lifetime of the pointer is the lifetime of the container. The pointer can be freely passed around, cloned, etc. but (for mutable objects), only one mutable access is allowed at a time. This calls for something between GC pointers and RC pointers. GC is out, because it isn't send-able. RC is out, because it doesn't allow for loops. So right now I use explicit pools and a semi-safe (that is, unsafe...) "smart pointer" type. And I don't support dropping objects until the whole container is done (which is OK in my specific app but isn't really a good solution). Ideally what I'd like to see is separating heaps from tasks. That is, suppose that GC pointers had a heap attribute (like borrowed pointers have a lifetime attribute). By default, each task has a heap, but it is also possible to define additional heaps (like we have the static lifetime and can also define additional lifetimes). So, the container could hold a heap and then many components with heap-scoped pointers. The whole thing is send-able and GC is done in the scope of each heap on its own (like today). There are implications on the type system (no mixing pointers between different heaps, unless the heaps are nested) - this seems very similar to the lifetimes type checking... Overall this seems very symmetrical with lifetimes. Basically, lifetimes == static (compile-time computable) free/malloc; heaps == dynamic (run-time computable) free/malloc. One interesting pattern allowed by this is ad-hoc actors (there are others of course). Currently, if one wants to write actor-style code, one ties in the GC pointers to one heap of one actor, which means one forces the parallelization policy to one task per actor. One could argue that the run-time should be good enough that any aggregation of actor threads to OS threads would be done optimally (which is a good goal); but in some apps, to get good performance one would like to control this. If we could separate heaps from tasks, we could spawn fewer tasks (roughly the number of OS threads) and use application code to decide which actor runs when and where (e.g., in combination with thread affinity to ensure better cache locality). At any rate - is this something that makes sense in the Rust view? If so, is there a chance of something like that being added (a completely separate question :-)? -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Sun Nov 3 22:13:48 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Sun, 03 Nov 2013 22:13:48 -0800 Subject: [rust-dev] Separating heaps from tasks In-Reply-To: References: Message-ID: <52773B1C.8020406@mozilla.com> On 11/3/13 10:11 PM, Oren Ben-Kiki wrote: > At any rate - is this something that makes sense in the Rust view? > If so, is there a chance of something like that being added (a > completely separate question :-)? Two questions: (1) In your proposal, do the cross-thread GC pointers have mutable contents? If so, how do you prevent data races? (2) Why were ARC and RWarc not sufficient? Patrick From danielmicay at gmail.com Sun Nov 3 22:18:32 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Mon, 4 Nov 2013 01:18:32 -0500 Subject: [rust-dev] Separating heaps from tasks In-Reply-To: References: Message-ID: On Mon, Nov 4, 2013 at 1:11 AM, Oren Ben-Kiki wrote: > I am toying with a non-trivial Rust project to get a feel for the > language. There's a pattern I keep seeing in my code which isn't easy to > express in Rust. I wonder what the "right thing to do" is here. > > The pattern is as follows. I have some container, which contains some > components of different types. The container as a whole is send-able . The > components form a complex graph (with cycles). > If there are keys, the path of least resistance is to use a map or a pair of maps. Reference counting can allow cyclic links in data structures as long as the ownership graph is acyclic, but Rust doesn't offer a type like this at the moment. -------------- next part -------------- An HTML attachment was scrubbed... URL: From oren at ben-kiki.org Sun Nov 3 22:19:40 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Mon, 4 Nov 2013 08:19:40 +0200 Subject: [rust-dev] Separating heaps from tasks In-Reply-To: <52773B1C.8020406@mozilla.com> References: <52773B1C.8020406@mozilla.com> Message-ID: On Mon, Nov 4, 2013 at 8:13 AM, Patrick Walton wrote: > On 11/3/13 10:11 PM, Oren Ben-Kiki wrote: > >> At any rate - is this something that makes sense in the Rust view? >> If so, is there a chance of something like that being added (a >> completely separate question :-)? >> > > Two questions: > > (1) In your proposal, do the cross-thread GC pointers have mutable > contents? If so, how do you prevent data races? > There are no cross-task data races because a heap can only be accessed by one task at a time. This is actually tricky. The container of the heap + components can be sent; separate components are not. I admit I'm not 100% sure how to address that. Preventing mutable aliasing requires an extra bit per pointer, but no atomic operations or reference counting. > (2) Why were ARC and RWarc not sufficient? > Because they don't allow cycles. -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Sun Nov 3 22:20:29 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Sun, 03 Nov 2013 22:20:29 -0800 Subject: [rust-dev] Separating heaps from tasks In-Reply-To: References: <52773B1C.8020406@mozilla.com> Message-ID: <52773CAD.4040805@mozilla.com> On 11/3/13 10:19 PM, Oren Ben-Kiki wrote: > Because they don't allow cycles. Aha. I personally think we should relax this restriction; it's pretty onerous. Patrick From oren at ben-kiki.org Sun Nov 3 22:23:47 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Mon, 4 Nov 2013 08:23:47 +0200 Subject: [rust-dev] Separating heaps from tasks In-Reply-To: References: Message-ID: Yes, using keys (or indices into a vector) is an option. There are two problems with this. It is pretty inefficient; one has to access the pool at any point, which means doubling the sizes of the pointers (at least), probably more; One needs a lot of unsafe code to allow mutating the pools; And there's the issue of keeping multiple pools (one per type)... So it gets complex fast, though perhaps a "sufficiently smart library" could still do a good job? On Mon, Nov 4, 2013 at 8:18 AM, Daniel Micay wrote: > On Mon, Nov 4, 2013 at 1:11 AM, Oren Ben-Kiki wrote: > >> I am toying with a non-trivial Rust project to get a feel for the >> language. There's a pattern I keep seeing in my code which isn't easy to >> express in Rust. I wonder what the "right thing to do" is here. >> >> The pattern is as follows. I have some container, which contains some >> components of different types. The container as a whole is send-able . The >> components form a complex graph (with cycles). >> > > If there are keys, the path of least resistance is to use a map or a pair > of maps. Reference counting can allow cyclic links in data structures as > long as the ownership graph is acyclic, but Rust doesn't offer a type like > this at the moment. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From oren at ben-kiki.org Sun Nov 3 22:29:32 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Mon, 4 Nov 2013 08:29:32 +0200 Subject: [rust-dev] Separating heaps from tasks In-Reply-To: <52773CAD.4040805@mozilla.com> References: <52773B1C.8020406@mozilla.com> <52773CAD.4040805@mozilla.com> Message-ID: Even if RC allowed cycles (I don't quite see how...) the whole thing wouldn't be send-able, unless one uses ARC. But ARC has even more performance penalties than RC... And doing cycle-supporting ARC across tasks seems like pushing it - you might as well admit you are doing global GC in the 1st place. On Mon, Nov 4, 2013 at 8:20 AM, Patrick Walton wrote: > On 11/3/13 10:19 PM, Oren Ben-Kiki wrote: > >> Because they don't allow cycles. >> > > Aha. I personally think we should relax this restriction; it's pretty > onerous. > > Patrick > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Sun Nov 3 22:32:18 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Sun, 03 Nov 2013 22:32:18 -0800 Subject: [rust-dev] Separating heaps from tasks In-Reply-To: References: <52773B1C.8020406@mozilla.com> <52773CAD.4040805@mozilla.com> Message-ID: <52773F72.3040209@mozilla.com> On 11/3/13 10:29 PM, Oren Ben-Kiki wrote: > Even if RC allowed cycles (I don't quite see how...) the whole thing > wouldn't be send-able, unless one uses ARC. But ARC has even more > performance penalties than RC... And doing cycle-supporting ARC across > tasks seems like pushing it - you might as well admit you are doing > global GC in the 1st place. I'm not sure I agree. I wasn't thinking that we would detect cycles with ARC, for one thing: we'd just let them leak. Not good, but more flexible. Unlike global GC, thread-safe reference counting has the nice property that you only pay for it when you use it. Thread-safe reference counting is used in a lot of C++ applications. Using it for everything is right out for performance-critical applications?it's poison in that concentration?but using it when you truly need it is totally fine IMHO. Patrick From danielmicay at gmail.com Sun Nov 3 22:32:51 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Mon, 4 Nov 2013 01:32:51 -0500 Subject: [rust-dev] Separating heaps from tasks In-Reply-To: References: <52773B1C.8020406@mozilla.com> <52773CAD.4040805@mozilla.com> Message-ID: On Mon, Nov 4, 2013 at 1:29 AM, Oren Ben-Kiki wrote: > Even if RC allowed cycles (I don't quite see how...) the whole thing > wouldn't be send-able, unless one uses ARC. But ARC has even more > performance penalties than RC... And doing cycle-supporting ARC across > tasks seems like pushing it - you might as well admit you are doing global > GC in the 1st place. > It can't support ownership cycles but it can certainly support cyclic links like `std::shared_ptr` + `std::weak_ptr` in C++. The performance penalty for supporting sends between tasks is atomic reference counting and the price for supporting weak pointers is an extra word per box. -------------- next part -------------- An HTML attachment was scrubbed... URL: From martindemello at gmail.com Sun Nov 3 23:10:38 2013 From: martindemello at gmail.com (Martin DeMello) Date: Sun, 3 Nov 2013 23:10:38 -0800 Subject: [rust-dev] Using libextra within libstd? Message-ID: I've been looking at https://github.com/mozilla/rust/issues/6085 which seems like it should be fairly simple to fix, however, the proposed solution involves EnumSet from libextra. Is it possible to use stuff from libextra within libstd? It seems to me that it would set up a circular dependency, though that could just be my misunderstanding the rust compilation model. If it is possible, how would I do it? If not, what would be the proper fix for issue #6085? martin From danielmicay at gmail.com Sun Nov 3 23:11:58 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Mon, 4 Nov 2013 02:11:58 -0500 Subject: [rust-dev] Using libextra within libstd? In-Reply-To: References: Message-ID: On Mon, Nov 4, 2013 at 2:10 AM, Martin DeMello wrote: > I've been looking at https://github.com/mozilla/rust/issues/6085 which > seems like it should be fairly simple to fix, however, the proposed > solution involves EnumSet from libextra. > > Is it possible to use stuff from libextra within libstd? It seems to > me that it would set up a circular dependency, though that could just > be my misunderstanding the rust compilation model. If it is possible, > how would I do it? If not, what would be the proper fix for issue > #6085? > > martin > No, it's not possible to use `libextra` within `libstd`. I think for now it might be best to define the flag type manually, and factor out the duplication with other flag types later. -------------- next part -------------- An HTML attachment was scrubbed... URL: From oren at ben-kiki.org Mon Nov 4 01:09:07 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Mon, 4 Nov 2013 11:09:07 +0200 Subject: [rust-dev] Separating heaps from tasks In-Reply-To: References: <52773B1C.8020406@mozilla.com> <52773CAD.4040805@mozilla.com> Message-ID: ARCs have their place, sure! But "letting it leak" isn't acceptable in my case. Instead, in my use case, "no deletes until the whole heap is released" makes way more sense (heaps are small, grow a bit, and get released). Since the lifetime of the object becomes == the lifetime of the heap, there's no issue with cycles. There's only an issue with multiple mutations, which like I said only needs a bit per pointer (and a non-atomic one at that as each heap is accessed by one thread - the only thing that gets sent between tasks is the whole heap!). So... different use cases, different solutions. ARC is a different trade-off. I guess the right thing to do would be to implement some "sufficiently smart" AppendOnlyHeap pointer, but this seems hard to do (same heap can hold objects of multiple types, etc.) so for now I have some AlmostSafeHeapPointer instead :-( Language support for heaps-separate-from-tasks would have solved it (and a bit more)... On Mon, Nov 4, 2013 at 8:32 AM, Daniel Micay wrote: > On Mon, Nov 4, 2013 at 1:29 AM, Oren Ben-Kiki wrote: > >> Even if RC allowed cycles (I don't quite see how...) the whole thing >> wouldn't be send-able, unless one uses ARC. But ARC has even more >> performance penalties than RC... And doing cycle-supporting ARC across >> tasks seems like pushing it - you might as well admit you are doing global >> GC in the 1st place. >> > > It can't support ownership cycles but it can certainly support cyclic > links like `std::shared_ptr` + `std::weak_ptr` in C++. The performance > penalty for supporting sends between tasks is atomic reference counting and > the price for supporting weak pointers is an extra word per box. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dbau.pp at gmail.com Mon Nov 4 01:59:10 2013 From: dbau.pp at gmail.com (Huon Wilson) Date: Mon, 04 Nov 2013 20:59:10 +1100 Subject: [rust-dev] Separating heaps from tasks In-Reply-To: References: <52773B1C.8020406@mozilla.com> <52773CAD.4040805@mozilla.com> Message-ID: <52776FEE.2020004@gmail.com> On 04/11/13 20:09, Oren Ben-Kiki wrote: > ARCs have their place, sure! But "letting it leak" isn't acceptable in > my case. > > Instead, in my use case, "no deletes until the whole heap is > released" makes way more sense (heaps are small, grow a bit, and get > released). Since the lifetime of the object becomes == the lifetime of > the heap, there's no issue with cycles. There's only an issue with > multiple mutations, which like I said only needs a bit per pointer > (and a non-atomic one at that as each heap is accessed by one thread - > the only thing that gets sent between tasks is the whole heap!). > > So... different use cases, different solutions. ARC is a different > trade-off. I guess the right thing to do would be to implement some > "sufficiently smart" AppendOnlyHeap pointer, but this seems hard to > do (same heap can hold objects of multiple types, etc.) so for now I > have some AlmostSafeHeapPointer instead :-( > > Language support for heaps-separate-from-tasks would have solved it > (and a bit more)... > Is this essentially an "arena allocator" where one can transfer the whole arena and all the objects allocated in it into another task? From robertknight at gmail.com Mon Nov 4 02:31:19 2013 From: robertknight at gmail.com (Robert Knight) Date: Mon, 4 Nov 2013 10:31:19 +0000 Subject: [rust-dev] Using libextra within libstd? In-Reply-To: References: Message-ID: > Is it possible to use stuff from libextra within libstd? > It seems to me that it would set up a circular dependency Even if it was possible technically, probably not a good idea from a maintenance perspective to have such dependencies. On 4 November 2013 07:10, Martin DeMello wrote: > I've been looking at https://github.com/mozilla/rust/issues/6085 which > seems like it should be fairly simple to fix, however, the proposed > solution involves EnumSet from libextra. > > Is it possible to use stuff from libextra within libstd? It seems to > me that it would set up a circular dependency, though that could just > be my misunderstanding the rust compilation model. If it is possible, > how would I do it? If not, what would be the proper fix for issue > #6085? > > martin > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From oren at ben-kiki.org Mon Nov 4 02:53:54 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Mon, 4 Nov 2013 12:53:54 +0200 Subject: [rust-dev] Separating heaps from tasks In-Reply-To: <52776FEE.2020004@gmail.com> References: <52773B1C.8020406@mozilla.com> <52773CAD.4040805@mozilla.com> <52776FEE.2020004@gmail.com> Message-ID: Essentially, yes. On Mon, Nov 4, 2013 at 11:59 AM, Huon Wilson wrote: > On 04/11/13 20:09, Oren Ben-Kiki wrote: > >> ARCs have their place, sure! But "letting it leak" isn't acceptable in my >> case. >> >> Instead, in my use case, "no deletes until the whole heap is released" >> makes way more sense (heaps are small, grow a bit, and get released). Since >> the lifetime of the object becomes == the lifetime of the heap, there's no >> issue with cycles. There's only an issue with multiple mutations, which >> like I said only needs a bit per pointer (and a non-atomic one at that as >> each heap is accessed by one thread - the only thing that gets sent between >> tasks is the whole heap!). >> >> So... different use cases, different solutions. ARC is a different >> trade-off. I guess the right thing to do would be to implement some >> "sufficiently smart" AppendOnlyHeap pointer, but this seems hard to do >> (same heap can hold objects of multiple types, etc.) so for now I have some >> AlmostSafeHeapPointer instead :-( >> >> Language support for heaps-separate-from-tasks would have solved it (and >> a bit more)... >> >> > Is this essentially an "arena allocator" where one can transfer the whole > arena and all the objects allocated in it into another task? > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From niko at alum.mit.edu Mon Nov 4 03:22:48 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Mon, 4 Nov 2013 06:22:48 -0500 Subject: [rust-dev] Separating heaps from tasks In-Reply-To: References: Message-ID: <20131104112248.GC6816@Mr-Bennet> This is not a complete answer to your question, but I have toyed with the idea of an (unsafely implemented but with safe interface) message allocation library that would partially address your use case. Unfortunately I think that implementing it would require higher-kinded types. The basic would be an interface where you have an opaque "message" that contains an arena and a root pointer (of some type `T`): struct Message> { priv arena: ~Arena, priv root: *mut T<'static> } You can create a message like so: Message::new(|arena| { let obj1 = arena.alloc(|| Leaf(...)); let obj2 = arena.alloc(|| Leaf(...)); arena.alloc(|| Root(obj1, obj2)) // return the root }); You could "open" an existing message and revise its contents: Message::edit(msg, |arena, root| { ... root // return new root }) These messages could be sent to other tasks, provided of course that they do not access managed data and so forth. The idea is to leverage the lifetime system to guarantee that pointers allocated from the arena do not escape. I haven't thought too hard about this, so there might be a hole, but I think it would work like so: impl:Isolate> Message { fn new(f: <'a> |&'a Arena| -> &'a mut T<'a> { let arena = ~Arena::new(); let root: *mut T<'static> = unsafe { transmute(f(&arena)) }; Message { arena: arena, root: root } } fn edit<'a>(m: &mut Message<'a>, f: <'b> |&'b Arena, &'b mut T<'b>| -> &'b mut T<'b>) { m.root = unsafe { transmute(f(&m.arena), transmute(m.root)) }; } } To address your use case, of course, we'd want to extend `arena` with the ability to track the types of the memory it has allocated and performance GC. Doing this while a message is being created or edited would be challenging and would require hooks from the runtime to obtain stack roots and so forth; interestingly, it'd be pretty trivial to run the GC at deterministic times or (say) at the end of an editing session. This might be enough for some uses cases. Niko [1]: http://smallcultfollowing.com/babysteps/blog/2013/06/11/data-parallelism-in-rust/ On Mon, Nov 04, 2013 at 08:11:29AM +0200, Oren Ben-Kiki wrote: > I am toying with a non-trivial Rust project to get a feel for the language. > There's a pattern I keep seeing in my code which isn't easy to express in > Rust. I wonder what the "right thing to do" is here. > > The pattern is as follows. I have some container, which contains some > components of different types. The container as a whole is send-able . The > components form a complex graph (with cycles). > > What I'd like to do is something like this: > - Declare a pool of objects of some types, which is held by the container. > - Declare pointer-to-object whose scope is the container; that is, the > lifetime of the pointer is the lifetime of the container. The pointer can > be freely passed around, cloned, etc. but (for mutable objects), only one > mutable access is allowed at a time. > > This calls for something between GC pointers and RC pointers. GC is out, > because it isn't send-able. RC is out, because it doesn't allow for loops. > So right now I use explicit pools and a semi-safe (that is, unsafe...) > "smart pointer" type. And I don't support dropping objects until the whole > container is done (which is OK in my specific app but isn't really a good > solution). > > Ideally what I'd like to see is separating heaps from tasks. That is, > suppose that GC pointers had a heap attribute (like borrowed pointers have > a lifetime attribute). By default, each task has a heap, but it is also > possible to define additional heaps (like we have the static lifetime and > can also define additional lifetimes). > > So, the container could hold a heap and then many components with > heap-scoped pointers. The whole thing is send-able and GC is done in the > scope of each heap on its own (like today). > > There are implications on the type system (no mixing pointers between > different heaps, unless the heaps are nested) - this seems very similar to > the lifetimes type checking... > > Overall this seems very symmetrical with lifetimes. Basically, lifetimes == > static (compile-time computable) free/malloc; heaps == dynamic (run-time > computable) free/malloc. > > One interesting pattern allowed by this is ad-hoc actors (there are others > of course). Currently, if one wants to write actor-style code, one ties in > the GC pointers to one heap of one actor, which means one forces the > parallelization policy to one task per actor. One could argue that the > run-time should be good enough that any aggregation of actor threads to OS > threads would be done optimally (which is a good goal); but in some apps, > to get good performance one would like to control this. If we could > separate heaps from tasks, we could spawn fewer tasks (roughly the number > of OS threads) and use application code to decide which actor runs when and > where (e.g., in combination with thread affinity to ensure better cache > locality). > > At any rate - is this something that makes sense in the Rust view? > If so, is there a chance of something like that being added (a completely > separate question :-)? > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From banderson at mozilla.com Mon Nov 4 10:55:02 2013 From: banderson at mozilla.com (Brian Anderson) Date: Mon, 04 Nov 2013 10:55:02 -0800 Subject: [rust-dev] Using libextra within libstd? In-Reply-To: References: Message-ID: <5277ED86.2060104@mozilla.com> On 11/03/2013 11:10 PM, Martin DeMello wrote: > I've been looking at https://github.com/mozilla/rust/issues/6085 which > seems like it should be fairly simple to fix, however, the proposed > solution involves EnumSet from libextra. > > Is it possible to use stuff from libextra within libstd? It seems to > me that it would set up a circular dependency, though that could just > be my misunderstanding the rust compilation model. If it is possible, > how would I do it? If not, what would be the proper fix for issue > #6085? > As others mentioned it's not generally possible, but just for curiosity's sake I'll point out that when running tests std *does* link to and use features from libextra. It's mind-bending and bad. When we decide that std absolutely can't live without features from extra, then those features get promoted to std. The bar is pretty high though. From gaetan at xeberon.net Mon Nov 4 11:00:43 2013 From: gaetan at xeberon.net (Gaetan) Date: Mon, 4 Nov 2013 20:00:43 +0100 Subject: [rust-dev] Using libextra within libstd? In-Reply-To: <5277ED86.2060104@mozilla.com> References: <5277ED86.2060104@mozilla.com> Message-ID: hello I'm new in the rust dev list, so sorry if the question has already been rised. But what is the reason to have 2 libraries std/extra? why not gathering all in a single "std" library? Thanks G. ----- Gaetan 2013/11/4 Brian Anderson > On 11/03/2013 11:10 PM, Martin DeMello wrote: > >> I've been looking at https://github.com/mozilla/rust/issues/6085 which >> seems like it should be fairly simple to fix, however, the proposed >> solution involves EnumSet from libextra. >> >> Is it possible to use stuff from libextra within libstd? It seems to >> me that it would set up a circular dependency, though that could just >> be my misunderstanding the rust compilation model. If it is possible, >> how would I do it? If not, what would be the proper fix for issue >> #6085? >> >> > As others mentioned it's not generally possible, but just for curiosity's > sake I'll point out that when running tests std *does* link to and use > features from libextra. It's mind-bending and bad. > > When we decide that std absolutely can't live without features from extra, > then those features get promoted to std. The bar is pretty high though. > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From banderson at mozilla.com Mon Nov 4 14:33:34 2013 From: banderson at mozilla.com (Brian Anderson) Date: Mon, 04 Nov 2013 14:33:34 -0800 Subject: [rust-dev] Using libextra within libstd? In-Reply-To: References: <5277ED86.2060104@mozilla.com> Message-ID: <527820BE.80101@mozilla.com> On 11/04/2013 11:00 AM, Gaetan wrote: > hello > > I'm new in the rust dev list, so sorry if the question has already > been rised. > > But what is the reason to have 2 libraries std/extra? why not > gathering all in a single "std" library? There are a few reasons for the split between std and extra. In general, we think the correct strategy for organizing Rust code is to use many small crates; one of the main reasons for this is to avoid large compilation times, but there are arguable modularity benefits as well. Personally I'd like to avoid Java's situation where there is one very large monolithic standard library that we have to live with in its entirety forever. The 'vision' currently is to have a rich ecosystem of officially supported packages in addition to the monolithic standard library. Under this scheme libextra will not exist at all, and will instead be broken up into a bunch of individual packages in their own repositories. Packages can be developed and stabilized and deprecated by the larger community on their own schedules, and those that fall out of use can disappear gracefully. The standard library though is monolithic because it has many complex interdependencies and wasn't developed with any intent to be more modular. In my opinion the definition of std is something like 'all the abstractions that depend on some interface to the compiler (this includes primitive types, the runtime, atomics), plus those that are so common that most moderate-sized software will need them (various data structures, algorithms and OS interfaces)'. I don't actually recall the original motivation for the split, but this is my current thinking. From martindemello at gmail.com Mon Nov 4 14:39:36 2013 From: martindemello at gmail.com (Martin DeMello) Date: Mon, 4 Nov 2013 14:39:36 -0800 Subject: [rust-dev] Using libextra within libstd? In-Reply-To: <5277ED86.2060104@mozilla.com> References: <5277ED86.2060104@mozilla.com> Message-ID: How does this work without getting into a dependency loop at build time? martin On Mon, Nov 4, 2013 at 10:55 AM, Brian Anderson wrote: > On 11/03/2013 11:10 PM, Martin DeMello wrote: >> >> I've been looking at https://github.com/mozilla/rust/issues/6085 which >> seems like it should be fairly simple to fix, however, the proposed >> solution involves EnumSet from libextra. >> >> Is it possible to use stuff from libextra within libstd? It seems to >> me that it would set up a circular dependency, though that could just >> be my misunderstanding the rust compilation model. If it is possible, >> how would I do it? If not, what would be the proper fix for issue >> #6085? >> > > As others mentioned it's not generally possible, but just for curiosity's > sake I'll point out that when running tests std *does* link to and use > features from libextra. It's mind-bending and bad. > > When we decide that std absolutely can't live without features from extra, > then those features get promoted to std. The bar is pretty high though. > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From gaetan at xeberon.net Mon Nov 4 15:09:42 2013 From: gaetan at xeberon.net (Gaetan) Date: Tue, 5 Nov 2013 00:09:42 +0100 Subject: [rust-dev] Using libextra within libstd? In-Reply-To: References: <5277ED86.2060104@mozilla.com> Message-ID: ok I understand, it will be like python which I really like the modularity. I'm beginning to play a little with std::os as my first rust programming, trying to add missing methods, etc, and I think this should quite strategic to move to libextra and then to be splitted appart, this would solve this cyclic dependency. What do you think about it? ----- Gaetan 2013/11/4 Martin DeMello > How does this work without getting into a dependency loop at build time? > > martin > > On Mon, Nov 4, 2013 at 10:55 AM, Brian Anderson > wrote: > > On 11/03/2013 11:10 PM, Martin DeMello wrote: > >> > >> I've been looking at https://github.com/mozilla/rust/issues/6085 which > >> seems like it should be fairly simple to fix, however, the proposed > >> solution involves EnumSet from libextra. > >> > >> Is it possible to use stuff from libextra within libstd? It seems to > >> me that it would set up a circular dependency, though that could just > >> be my misunderstanding the rust compilation model. If it is possible, > >> how would I do it? If not, what would be the proper fix for issue > >> #6085? > >> > > > > As others mentioned it's not generally possible, but just for curiosity's > > sake I'll point out that when running tests std *does* link to and use > > features from libextra. It's mind-bending and bad. > > > > When we decide that std absolutely can't live without features from > extra, > > then those features get promoted to std. The bar is pretty high though. > > > > _______________________________________________ > > 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: From banderson at mozilla.com Mon Nov 4 16:35:43 2013 From: banderson at mozilla.com (Brian Anderson) Date: Mon, 04 Nov 2013 16:35:43 -0800 Subject: [rust-dev] Using libextra within libstd? In-Reply-To: References: <5277ED86.2060104@mozilla.com> Message-ID: <52783D5F.9030200@mozilla.com> On 11/04/2013 02:39 PM, Martin DeMello wrote: > How does this work without getting into a dependency loop at build time? The std under test is not *actually* the standard library as seen by compiler and runtime; as far as the compiler is concerned it is just some library compiled with --test, that links to libextra and libstd (so when testing std there are two different copies of it in memory.. This has some complications since the standard library has some functionality (lang-items) that must not be redefined, so std has a few strategic 'cfg' attributes thrown in to avoid that. For the most part this set up works just fine, but occasionally can result in some very hard to understand errors, especially if you run tests of the runtime without first recompiling the standard library (resulting in unsafe interoperation of incompatible type definitions). > > martin > > On Mon, Nov 4, 2013 at 10:55 AM, Brian Anderson wrote: >> On 11/03/2013 11:10 PM, Martin DeMello wrote: >>> I've been looking at https://github.com/mozilla/rust/issues/6085 which >>> seems like it should be fairly simple to fix, however, the proposed >>> solution involves EnumSet from libextra. >>> >>> Is it possible to use stuff from libextra within libstd? It seems to >>> me that it would set up a circular dependency, though that could just >>> be my misunderstanding the rust compilation model. If it is possible, >>> how would I do it? If not, what would be the proper fix for issue >>> #6085? >>> >> As others mentioned it's not generally possible, but just for curiosity's >> sake I'll point out that when running tests std *does* link to and use >> features from libextra. It's mind-bending and bad. >> >> When we decide that std absolutely can't live without features from extra, >> then those features get promoted to std. The bar is pretty high though. >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev From banderson at mozilla.com Mon Nov 4 16:42:47 2013 From: banderson at mozilla.com (Brian Anderson) Date: Mon, 04 Nov 2013 16:42:47 -0800 Subject: [rust-dev] Using libextra within libstd? In-Reply-To: References: <5277ED86.2060104@mozilla.com> Message-ID: <52783F07.8090505@mozilla.com> On 11/04/2013 03:09 PM, Gaetan wrote: > ok I understand, it will be like python which I really like the > modularity. I'm beginning to play a little with std::os as my first > rust programming, trying to add missing methods, etc, and I think this > should quite strategic to move to libextra and then to be splitted > appart, this would solve this cyclic dependency. What do you think > about it? Things like 'mkdir' are pretty important and are increasingly tied to our I/O subsystem (it just moved into std::rt::io::fs), so I don't think it should move out of standard. Since this issue of how to represent OR-able flags is pretty common, the consensus seems to be to clean up EnumSet and move it to std. If you're interested in tackling it I opened an issue specifically about the move https://github.com/mozilla/rust/issues/10272. > > ----- > Gaetan > > > > 2013/11/4 Martin DeMello > > > How does this work without getting into a dependency loop at build > time? > > martin > > On Mon, Nov 4, 2013 at 10:55 AM, Brian Anderson > > wrote: > > On 11/03/2013 11:10 PM, Martin DeMello wrote: > >> > >> I've been looking at > https://github.com/mozilla/rust/issues/6085 which > >> seems like it should be fairly simple to fix, however, the proposed > >> solution involves EnumSet from libextra. > >> > >> Is it possible to use stuff from libextra within libstd? It > seems to > >> me that it would set up a circular dependency, though that > could just > >> be my misunderstanding the rust compilation model. If it is > possible, > >> how would I do it? If not, what would be the proper fix for issue > >> #6085? > >> > > > > As others mentioned it's not generally possible, but just for > curiosity's > > sake I'll point out that when running tests std *does* link to > and use > > features from libextra. It's mind-bending and bad. > > > > When we decide that std absolutely can't live without features > from extra, > > then those features get promoted to std. The bar is pretty high > though. > > > > _______________________________________________ > > 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: From martindemello at gmail.com Mon Nov 4 16:59:43 2013 From: martindemello at gmail.com (Martin DeMello) Date: Mon, 4 Nov 2013 16:59:43 -0800 Subject: [rust-dev] Using libextra within libstd? In-Reply-To: <52783F07.8090505@mozilla.com> References: <5277ED86.2060104@mozilla.com> <52783F07.8090505@mozilla.com> Message-ID: okay, i figure niko might want to do this himself, but i've marked my interest on the bug if he doesn't. martin On Mon, Nov 4, 2013 at 4:42 PM, Brian Anderson wrote: > On 11/04/2013 03:09 PM, Gaetan wrote: > > ok I understand, it will be like python which I really like the modularity. > I'm beginning to play a little with std::os as my first rust programming, > trying to add missing methods, etc, and I think this should quite strategic > to move to libextra and then to be splitted appart, this would solve this > cyclic dependency. What do you think about it? > > > Things like 'mkdir' are pretty important and are increasingly tied to our > I/O subsystem (it just moved into std::rt::io::fs), so I don't think it > should move out of standard. Since this issue of how to represent OR-able > flags is pretty common, the consensus seems to be to clean up EnumSet and > move it to std. If you're interested in tackling it I opened an issue > specifically about the move https://github.com/mozilla/rust/issues/10272. > > > > ----- > Gaetan > > > > 2013/11/4 Martin DeMello >> >> How does this work without getting into a dependency loop at build time? >> >> martin >> >> On Mon, Nov 4, 2013 at 10:55 AM, Brian Anderson >> wrote: >> > On 11/03/2013 11:10 PM, Martin DeMello wrote: >> >> >> >> I've been looking at https://github.com/mozilla/rust/issues/6085 which >> >> seems like it should be fairly simple to fix, however, the proposed >> >> solution involves EnumSet from libextra. >> >> >> >> Is it possible to use stuff from libextra within libstd? It seems to >> >> me that it would set up a circular dependency, though that could just >> >> be my misunderstanding the rust compilation model. If it is possible, >> >> how would I do it? If not, what would be the proper fix for issue >> >> #6085? >> >> >> > >> > As others mentioned it's not generally possible, but just for >> > curiosity's >> > sake I'll point out that when running tests std *does* link to and use >> > features from libextra. It's mind-bending and bad. >> > >> > When we decide that std absolutely can't live without features from >> > extra, >> > then those features get promoted to std. The bar is pretty high though. >> > >> > _______________________________________________ >> > 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 > > > From banderson at mozilla.com Mon Nov 4 17:03:42 2013 From: banderson at mozilla.com (Brian Anderson) Date: Mon, 04 Nov 2013 17:03:42 -0800 Subject: [rust-dev] Using libextra within libstd? In-Reply-To: References: <5277ED86.2060104@mozilla.com> <52783F07.8090505@mozilla.com> Message-ID: <527843EE.6090004@mozilla.com> On 11/04/2013 04:59 PM, Martin DeMello wrote: > okay, i figure niko might want to do this himself, but i've marked my > interest on the bug if he doesn't. > Ask niko for advice about the design, but he will be *happy* to let you do it, guaranteed. From banderson at mozilla.com Mon Nov 4 18:21:51 2013 From: banderson at mozilla.com (Brian Anderson) Date: Mon, 04 Nov 2013 18:21:51 -0800 Subject: [rust-dev] Abandoning segmented stacks in Rust Message-ID: <5278563F.2070507@mozilla.com> Greetings you delightful Rustic people, Sound the death knell for segmented stacks. The new runtime does not implement segmented stacks and it never will. This decision has been brewing for some time, and now I'd like to make it official and lay out the reasoning for posterity. To recap, segmented stacks are a strategy for growing stacks incrementally, starting from a single small stack segment, and appending further segments as needed in a linked list as the stack grows. This allows threads to be very compact so that many can be created concurrently. The previous Rust runtime did implement segmented stacks, and that experience makes us believe that the performance tradeoffs required are not compatible with Rust's goals as a high performance systems language. The performance problems associated with segmented stacks can be summerized as: switching stacks has a cost. Though that cost can be minimized through extensive tuning and micro-optimization (much of which we admittedly did not pursue), it will never be free, and we've concluded that the effort and complexity of continuing down that route is not justified. We've seen the problem manifest primarily in three areas: * "stack thrashing" - when out of stack a function call will force an allocation of a new segment, which is later freed upon return. This is expensive even when the new stack segmented is cached. The result is unpredictable and severe drops in performance whenever a stack boundary happens to fall inside a tight loop. ([Similar concerns][1] are pushing Go away from a segmented stack scheme as well - they call it the "hot split" problem). [1]: https://docs.google.com/document/d/1wAaf1rYoM4S4gtnPh0zOlGzWtrZFQ5suE8qr2sD8uWQ/pub * FFI - foreign code typically expects to have large stacks, so using the FFI often requires switching stacks. Avoiding this overhead would require an elaborate and inherently unsafe system of annotation (#8822), increasing a burden on the FFI interface. * LLVM libc optimizations and intrinsic fallbacks - LLVM will transform calls to some libc functions into intrinsics and some intrinsics into runtime function calls, for reasons of performance and platform compatibility. Obvious solutions to making these compatible with segmented stacks impose a high minimum stack requirement, partially defeating the point of a segmented stack. Instead of segmented stacks we're going to rely on the OS and MMU to help us map pages lazily. Although the details aren't clear yet, I expect that on 64-bit platforms the number of concurrent tasks will be comparable to using segmented stacks. On 32-bit platforms, with their limited address space, the situation will not be as good, but this is a calculated risk that we can live without the same amount of concurrency there. Regards, Brian From bill_myers at outlook.com Mon Nov 4 19:50:27 2013 From: bill_myers at outlook.com (Bill Myers) Date: Tue, 5 Nov 2013 03:50:27 +0000 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: <5278563F.2070507@mozilla.com> References: <5278563F.2070507@mozilla.com> Message-ID: The advantage of segmented stacks is that blocked tasks only take up as much memory as they actually need to store state, so that for instance a network server can use a task for each connection, and still only use, say, 64 bytes per connection if that's possible instead of the number of stack pages that got allocated for previous computation (assuming an "extreme" version that allocates a stack segment on every call). However, there is another approach that can replace segmented stacks for that purpose, namely having the compiler automatically transform blocking functions to instead return a future (with limited lifetime). This means that segmented allocation only happens for functions that indirectly perform I/O and only allocates the exact amount of memory needed to retain state that must persistent across the blocking I/O operation, while other functions execute normally using traditional stacks. The simplest example of this feature is async/await in C# 5, and Scala has a delimited continuation passing transformation that can be used to do the same thing. Has this been considered for Rust? -------------- next part -------------- An HTML attachment was scrubbed... URL: From thadguidry at gmail.com Mon Nov 4 20:13:26 2013 From: thadguidry at gmail.com (Thad Guidry) Date: Mon, 4 Nov 2013 22:13:26 -0600 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: <5278563F.2070507@mozilla.com> Message-ID: Bill, memory is cheap. On Mon, Nov 4, 2013 at 9:50 PM, Bill Myers wrote: > The advantage of segmented stacks is that blocked tasks only take up as > much memory as they actually need to store state, so that for instance a > network server can use a task for each connection, and still only use, say, > 64 bytes per connection if that's possible instead of the number of stack > pages that got allocated for previous computation (assuming an "extreme" > version that allocates a stack segment on every call). > > However, there is another approach that can replace segmented stacks for > that purpose, namely having the compiler automatically transform blocking > functions to instead return a future (with limited lifetime). > > This means that segmented allocation only happens for functions that > indirectly perform I/O and only allocates the exact amount of memory needed > to retain state that must persistent across the blocking I/O operation, > while other functions execute normally using traditional stacks. > > The simplest example of this feature is async/await in C# 5, and Scala has > a delimited continuation passing transformation that can be used to do the > same thing. > > Has this been considered for Rust? > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -- -Thad +ThadGuidry Thad on LinkedIn -------------- next part -------------- An HTML attachment was scrubbed... URL: From oren at ben-kiki.org Mon Nov 4 21:21:55 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Tue, 5 Nov 2013 07:21:55 +0200 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: <5278563F.2070507@mozilla.com> References: <5278563F.2070507@mozilla.com> Message-ID: Note that as memory becomes cheaper and larger there will be more pressure on 64-bit OS-es to switch to large pages; the number of pages needed to map several GBs of memory today is already getting out of hand, causing TLB misses to become a performance issue in some cases - imagine a system with 0.xTBs of memory and it becomes ludicrous. So playing tricks with MMU and lazy page loading may not work as well as it does with today's the small 4K page size. Of course, Rust is hardly the only platform that would be affected :-) and ideally, it would be possible to have more flexibility than today in choosing which page sizes are used where in the program's address space... but it remains to be seen how exactly this would play out. Just a point to keep in mind... On Tue, Nov 5, 2013 at 4:21 AM, Brian Anderson wrote: > Instead of segmented stacks we're going to rely on the OS and MMU to help > us map pages lazily. Although the details aren't clear yet, I expect that > on 64-bit platforms the number of concurrent tasks will be comparable to > using segmented stacks. On 32-bit platforms, with their limited address > space, the situation will not be as good, but this is a calculated risk > that we can live without the same amount of concurrency there. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From bob at redivi.com Mon Nov 4 23:17:35 2013 From: bob at redivi.com (Bob Ippolito) Date: Mon, 4 Nov 2013 23:17:35 -0800 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: <5278563F.2070507@mozilla.com> Message-ID: Having memory is cheap, accessing it isn't. On Monday, November 4, 2013, Thad Guidry wrote: > Bill, memory is cheap. > > > On Mon, Nov 4, 2013 at 9:50 PM, Bill Myers > > wrote: > >> The advantage of segmented stacks is that blocked tasks only take up as >> much memory as they actually need to store state, so that for instance a >> network server can use a task for each connection, and still only use, say, >> 64 bytes per connection if that's possible instead of the number of stack >> pages that got allocated for previous computation (assuming an "extreme" >> version that allocates a stack segment on every call). >> >> However, there is another approach that can replace segmented stacks for >> that purpose, namely having the compiler automatically transform blocking >> functions to instead return a future (with limited lifetime). >> >> This means that segmented allocation only happens for functions that >> indirectly perform I/O and only allocates the exact amount of memory needed >> to retain state that must persistent across the blocking I/O operation, >> while other functions execute normally using traditional stacks. >> >> The simplest example of this feature is async/await in C# 5, and Scala >> has a delimited continuation passing transformation that can be used to do >> the same thing. >> >> Has this been considered for Rust? >> >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> >> > > > -- > -Thad > +ThadGuidry > Thad on LinkedIn > -------------- next part -------------- An HTML attachment was scrubbed... URL: From denis.spir at gmail.com Tue Nov 5 02:44:01 2013 From: denis.spir at gmail.com (spir) Date: Tue, 05 Nov 2013 11:44:01 +0100 Subject: [rust-dev] the inter-play of struct type impl, traits, & type params Message-ID: <5278CBF1.8010900@gmail.com> Hello, New to Rust. Is there (already) a list for mutual help in the usage of Rust? If not, I guess it may be worth having one, distinct from the dev list, even if the language is a moving target, even for people who rather intend, at terms, to participate in the development. It is in fact even more needed due precisely to the constant change of the lang, to the fact it is mostly unknown, and to the state of the docs. In the meanwhile... see below. Also please pardon wrong ideas or statements: I am presently discovering the language. (Also, english is a foreign lang for me.) As an exercise in learning the language, I am trying various ways to implement sparse arrays (association list, trie, "modulo table" = hash table w/o hash), the aim being to determine the nr of entries from which it is worth switching to a more complicated version. But I'm far from there yet, stumbling on diverse issues right for the simplest bits of code. Below, I'm talking of the interrelation between struct type declaration & impl, type params, and traits. type Key = uint; struct PairList { ... } impl PairList { ... } impl PairList for Iterable { ... } === trait implementation === A first point which I find annoying is the splitting of impl for traits a struct explicitely implements. This means that each time we need to use a generic func for the *usage* of an *instance* of a type, we have to modify this type's *definition* with a new impl section for the corresponding trait(s) required by the generic feature. Or do I misunderstand? (This, even if the the trait is actually implemented, I mean the methods exist, or am I wrong again?) I find that exagerated. Why not just add a declaration of the trait at the top of the struct type def? struct PairList : Iterable { === impl itself === As a side note, I also do not understand the purpose of the impl section altogether. I would be happy with: * either the methods inside the struct def: struct PairList { fn push (&self, key:Key, val:Val) {...} } * or a simple form outside the struct def: fn PairList.push (&self, key:Key, val:Val) {...} It is stated somewhere that the impl section nicely separates the fields from the implementation, but this is a question of taste: one could trivially reply this section "invents" a strange notion of implementation (after all, data fields also are implementation, or rather also definition), and forces to tell apart things that logically fit together. Anyway, it's a question of perspective... I'd vote for the second form above, because it is a kind of intermediate choice. Another advantage is it gives a name to the method ("PairList.push"). === the meaning of impl for trait sections === Also, I'm not clear about whether "impl for trait" sections form a kind of namespace. Can there be methods with equal names in diverse such sections (and/or in in th impl section or section not related to traits)? If yes, then it would be in my view a bad idea. Instead, make a kind of standard naming scheme for trait methods. Else, what do such sections mean? === impl & type params === As shown above, for a struct type with type params, we have to repeat the said type params in the impl section's headline, and this in fact twice! (I had a hard time with that point.) These repetitions make no sense, in my view, since the type param belongs to the struct type anyway, esp the one after "impl"; but this one repetition precisely is where to declare traits on type params... see below. I could live with the repetition after the struct type name, as if the type param belonged to the name of the struct type: impl PairList { (but as said I would happily forget about impl sections altogether) === traits used === For programmer feedback (read: debug) I need to write out pair-lists (indeed). An issue is that the Val type is a parameter. Since any form of structured output itself requires a format (if only '?') and such formats are traits (! why?), I need to declare this trait ("fmt::Default") as belonging to Val --yes, the type param... But where? I had to search for a while before stepping on the right place: as written above right after "impl" itself. The logical place to make this declaration would be the concerned method, here 'write'. But the said method does not take any Val instance as input, just self: so that there is no place there to declare that Val implements fmt::Default. Or how are we to do it? === universal traits === A distinct but related issue is this trait fmt::Default is supposed universal. Could type params have those universal traits? so that we don't have to declare them. Or better, they are not traits. === everything is a trait === Apparently, in the latest dev of Rust, about everything becomes a trait. This gets crazy ;-). I guess it is wrong in that it over-complicates the language, and there is no limit. Moreover, these layers of complication *compose*, since traits formally are independant. But they are not, semantically, I mean in the proper sense of the term: what they *mean* (or are supposed to). There is certainly a way to use traits in an opposite manner: they represent functionalities of which we may know they are available when we use other features or types of this or that kind. Currently, traits act conversely, as a constant barrier to usage and expression. With traits as they are (used), it looks like everything is forbidden by default, and we have to discover and explicitely authorise any single bit of functionality. See also "over-abstraction" below. === std features, esp traits === I love it that a range of "prelude" features are available in standard. A tiny improvement would be that we don't even need to prefix everything with "std::". (In the code above, I had to declare "use std:fmt"). Instead, just as every prelude feature is available as if we had explicitely imported it, make every (sub)module of std pretend to be at the root of the library. Meaning, whenever the language does not find x::y, have it search std:x:y. This would be particularly appreciated for traits which, as it seems, we'll have to deal with *very* much. === over-abstraction === Traits look like, finally, de facto making ("inventing") sub-categories of types. There are already many such categories in principle, eg for vectors fix-size/var-size/dyn-size, mutable/immutable, fix-type/param-type, etc... Each new trait or range of related traits (eg how they are to be written or iterated) forms new sub-categories or panels of sub-categories. All of them in principle are "orthogonal" (in the sense of logically independant). Features like generics, type params, traits, should be an opportunity for otherwise hyper-rigid languages, because statically typed, and like Rust aiming at full safety, to regain some flexibility and ease of use, while retaining their safety and efficiency. I guess this is what makes so-called dyn languages easy to use. In such a language there is one type of sequential container, and 0 sub-category. The features required to use such a type are at most a dozen methods plus a handful of operators (python) or even less, in fact about nothing (lua). Lua may arguably be extreme, but in Python this is enough to cover 99.9% of use cases, other being trivially wri tten in a few lines of code in terms of existing features. Now, have a look at [http://static.rust-lang.org/doc/0.8/std/vec.html]: it is by me a webpage long of 50 screens (I use rather big fonts, right); I did not count the functions, but there may be more than 200 probably. And this is nearly a plain list, most funcs are undocumented or just with a short sentence. Actually, most of them seem redondant, there are tons of versions of the same features, depending on various variants. I guess much of this mess is due to a kind of over-engineering related in part to traits, or to their current usage in Rust. It seems the combination of traits, and their combinations with other sources of complication such as type params, add barriers to usage and expression. Instead of gaining flexibility and ease of use, we get the opposite as it seems. We should just declare traits once and for all in the headline ot type defs, this just for doc and to help the compiler, and then corresponding functionality be available, also composing with functionality provided by other traits, and automatically declining into subtypes due to genericity, etc...; this, without any other declaration for other types, type params, and more, even less for each method of the type or at each function using instances of the type. I guess there is a way for traits to be door-openers, not barricade-fabricators. Or am I dreaming? I love many things in Rust, but am afraid it ends up proving being to difficult to use or even learn. I'm pretty sure its core design, with some adjustments maybe, permits driving it toward an other, welcoming direction. I'm searching for a while already for a modern, flexible C with basic safety and reasonable performance, a language fun and exciting to program with despite the difficulty of lower-level coding, and think it could be Rust. In any case, thank you very much. Denis From qwertie256 at gmail.com Tue Nov 5 08:32:43 2013 From: qwertie256 at gmail.com (David Piepgrass) Date: Tue, 5 Nov 2013 09:32:43 -0700 Subject: [rust-dev] Abandoning segmented stacks in Rust Message-ID: Segmented stacks aren't the only solution though. If the concern is many tasks that block for a long time, I imagine a mechanism to bundle a bunch of small, dormant stacks into a single page so that the original pages could be released to the OS. If stacks were additionally relocatable (which requires similar machinery as precise moving GC, if I'm not mistaken) then the released pages could be re-used for other tasks or heaps, which would be especially helpful on 32-bit. To address the problem of running out of address space on 32-bit, small-stack tasks could request a single-page stack (plus a guard page), which is enlarged by relocation as needed. Combining these techniques, you might be able to have up to a million small tasks in a 32-bit process. From: Bill Myers > > The advantage of segmented stacks is that blocked tasks only take up as > much memory as they actually need to store state, so that for instance a > network server can use a task for each connection, and still only use, say, > 64 bytes per connection if that's possible instead of the number of stack > pages that got allocated for previous computation (assuming an "extreme" > version that allocates a stack segment on every call). > > However, there is another approach that can replace segmented stacks for > that purpose, namely having the compiler automatically transform blocking > functions to instead return a future (with limited lifetime). > > This means that segmented allocation only happens for functions that > indirectly perform I/O and only allocates the exact amount of memory needed > to retain state that must persistent across the blocking I/O operation, > while other functions execute normally using traditional stacks. > > The simplest example of this feature is async/await in C# 5, and Scala has > a delimited continuation passing transformation that can be used to do the > same thing. > > Has this been considered for Rust? > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From tiffany at stormbit.net Tue Nov 5 08:47:33 2013 From: tiffany at stormbit.net (Tiffany Bennett) Date: Tue, 5 Nov 2013 11:47:33 -0500 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: <5278563F.2070507@mozilla.com> Message-ID: If you really need such a small memory footprint for your tasks, I am of the opinion that it would be less error prone (whoops, accidentally used 64 bytes of stack than I should have, now I'm using twice as much memory!) to use an async event loop, like libevent, rather than a task model. It just doesn't seem like it's as worthwhile - if you really need to have that faux synchronous IO, you could use FRP. I'm sure a lot of people would disagree with me, given the general direction rust has been going with tasks (IO, task-local errors, etc.) -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Tue Nov 5 09:17:23 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Tue, 05 Nov 2013 09:17:23 -0800 Subject: [rust-dev] the inter-play of struct type impl, traits, & type params In-Reply-To: <5278CBF1.8010900@gmail.com> References: <5278CBF1.8010900@gmail.com> Message-ID: <52792823.40403@mozilla.com> On 11/5/13 2:44 AM, spir wrote: > Why not just add a declaration of the trait at the top of the struct > type def? > > struct PairList : Iterable { You can implement traits on types that aren't structs. > * either the methods inside the struct def: > > struct PairList { > fn push (&self, key:Key, val:Val) {...} > } That seems somewhat ad-hoc IMHO, because you can implement traits on types that aren't structs. > > * or a simple form outside the struct def: > > fn PairList.push (&self, key:Key, val:Val) {...} > > It is stated somewhere that the impl section nicely separates the fields > from the implementation, but this is a question of taste: one could > trivially reply this section "invents" a strange notion of > implementation (after all, data fields also are implementation, or > rather also definition), and forces to tell apart things that logically > fit together. Anyway, it's a question of perspective... I'd vote for the > second form above, because it is a kind of intermediate choice. Another > advantage is it gives a name to the method ("PairList.push"). We considered the second form, but rejected it, because if you had generic type parameters you'd have to repeat them over and over. > Also, I'm not clear about whether "impl for trait" sections form a kind > of namespace. Can there be methods with equal names in diverse such > sections (and/or in in th impl section or section not related to > traits)? If yes, then it would be in my view a bad idea. Instead, make a > kind of standard naming scheme for trait methods. > Else, what do such sections mean? I'm not sure what this means. > As shown above, for a struct type with type params, we have to repeat > the said type params in the impl section's headline, and this in fact > twice! (I had a hard time with that point.) These repetitions make no > sense, in my view, since the type param belongs to the struct type > anyway, esp the one after "impl"; but this one repetition precisely is > where to declare traits on type params... see below. I could live with > the repetition after the struct type name, as if the type param belonged > to the name of the struct type: > > impl PairList { > > (but as said I would happily forget about impl sections altogether) There's a big difference between: impl SomeTrait for Foo { ... } And: impl SomeTrait for Foo { ... } We want to be able to tell the difference between the two at parse time. > There is certainly a way to use traits in an opposite manner: they > represent functionalities of which we may know they are available when > we use other features or types of this or that kind. Currently, traits > act conversely, as a constant barrier to usage and expression. With > traits as they are (used), it looks like everything is forbidden by > default, and we have to discover and explicitely authorise any single > bit of functionality. Rust doesn't have C++-style ad-hoc templates; instead it requires that you use concepts in all circumstances. There are two reasons for this: (a) to fix the error message problems of C++ templates; (b) to allow functionality to be added to existing types and used in templates without the C++ *argument-dependent lookup*. Given that C++ is heavily moving toward concepts because the error message problems at least seem intractable without them, I'm personally pretty happy with the decision that we made. It requires more organization up front, but the user experience of the language becomes so much nicer. > I love it that a range of "prelude" features are available in standard. > A tiny improvement would be that we don't even need to prefix everything > with "std::". (In the code above, I had to declare "use std:fmt"). > Instead, just as every prelude feature is available as if we had > explicitely imported it, make every (sub)module of std pretend to be at > the root of the library. Meaning, whenever the language does not find > x::y, have it search std:x:y. > This would be particularly appreciated for traits which, as it seems, > we'll have to deal with *very* much. We used to do this, but we stopped. The reasons have to do with making imports tractable and the fact that we didn't want to wire "std" into the compiler more than it needs to be. > Now, have a look at [http://static.rust-lang.org/doc/0.8/std/vec.html]: > it is by me a webpage long of 50 screens (I use rather big fonts, > right); I did not count the functions, but there may be more than 200 > probably. And this is nearly a plain list, most funcs are undocumented > or just with a short sentence. Actually, most of them seem redondant, > there are tons of versions of the same features, depending on various > variants. The `vec` module does need to be cleaned up, agreed. > I guess much of this mess is due to a kind of over-engineering > related in part to traits, or to their current usage in Rust. It seems > the combination of traits, and their combinations with other sources of > complication such as type params, add barriers to usage and expression. I would caution against drawing too much of a conclusion from the `vec` module. Most of those traits exist just so that the standard library can add methods to the primitive vector type. Remember that in most other languages you can't add methods to primitive types at all. If vectors weren't a built-in type, then you wouldn't have to use traits to define all these methods. That would be ideal if we had enough time to fix it before 1.0, but regrettably I don't think it'll happen. (We may be able to sneak it in in 2.0 backwards compatibly, however.) Ultimately I think you want ad-hoc templates like C++/D/Nimrod. I don't see that happening, unfortunately: Rust is fairly firmly in the Haskell tradition of typeclasses for abstraction at this point. Patrick From pcwalton at mozilla.com Tue Nov 5 09:18:19 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Tue, 05 Nov 2013 09:18:19 -0800 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: Message-ID: <5279285B.2070706@mozilla.com> On 11/5/13 8:32 AM, David Piepgrass wrote: > Segmented stacks aren't the only solution though. > > If the concern is many tasks that block for a long time, I imagine a > mechanism to bundle a bunch of small, dormant stacks into a single page > so that the original pages could be released to the OS. > > If stacks were additionally relocatable (which requires similar > machinery as precise moving GC, if I'm not mistaken) This is correct. It's conceivable (although I can't make any promises) that if and when LLVM supports this, we could experiment with doing what Go does. Patrick From denis.spir at gmail.com Tue Nov 5 10:44:18 2013 From: denis.spir at gmail.com (spir) Date: Tue, 05 Nov 2013 19:44:18 +0100 Subject: [rust-dev] the inter-play of struct type impl, traits, & type params In-Reply-To: <52792823.40403@mozilla.com> References: <5278CBF1.8010900@gmail.com> <52792823.40403@mozilla.com> Message-ID: <52793C82.20001@gmail.com> On 11/05/2013 06:17 PM, Patrick Walton wrote: > On 11/5/13 2:44 AM, spir wrote: That you very much for this complete answer, Patrick. Things are clearer. Denis From hatahet at gmail.com Tue Nov 5 11:28:02 2013 From: hatahet at gmail.com (Ziad Hatahet) Date: Tue, 5 Nov 2013 11:28:02 -0800 Subject: [rust-dev] the inter-play of struct type impl, traits, & type params In-Reply-To: <52792823.40403@mozilla.com> References: <5278CBF1.8010900@gmail.com> <52792823.40403@mozilla.com> Message-ID: On Tue, Nov 5, 2013 at 9:17 AM, Patrick Walton wrote: > On 11/5/13 2:44 AM, spir wrote: > >> Why not just add a declaration of the trait at the top of the struct >> type def? >> >> struct PairList : Iterable { >> > > You can implement traits on types that aren't structs. Isn't another effect of this is the ability to "monkey-patch" structs to implement extra methods or traits? E.g. you can later in implement a to_str() method for a type, or implement certain traits, like Clone or Drop. -- Ziad -------------- next part -------------- An HTML attachment was scrubbed... URL: From steven099 at gmail.com Tue Nov 5 13:29:38 2013 From: steven099 at gmail.com (Steven Blenkinsop) Date: Tue, 5 Nov 2013 16:29:38 -0500 Subject: [rust-dev] the inter-play of struct type impl, traits, & type params In-Reply-To: References: <5278CBF1.8010900@gmail.com> <52792823.40403@mozilla.com> Message-ID: As long as "you" are the person who owns the type, yeah, but I suspect that's not what you mean. Coherence requires that you only implement traits for types if you own either the trait or the type (or both). You can't implement a 3rd party trait for a 3rd party type, since then there could be multiple such implementations for a given (trait, type) pair, and coherence would be broken. On Tue, Nov 5, 2013 at 2:28 PM, Ziad Hatahet wrote: > On Tue, Nov 5, 2013 at 9:17 AM, Patrick Walton wrote: > >> On 11/5/13 2:44 AM, spir wrote: >> >>> Why not just add a declaration of the trait at the top of the struct >>> type def? >>> >>> struct PairList : Iterable { >>> >> >> You can implement traits on types that aren't structs. > > > > Isn't another effect of this is the ability to "monkey-patch" structs to > implement extra methods or traits? E.g. you can later in implement a > to_str() method for a type, or implement certain traits, like Clone or Drop. > > > -- > Ziad > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From banderson at mozilla.com Tue Nov 5 13:40:58 2013 From: banderson at mozilla.com (Brian Anderson) Date: Tue, 05 Nov 2013 13:40:58 -0800 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: <5278563F.2070507@mozilla.com> Message-ID: <527965EA.1080604@mozilla.com> On 11/04/2013 07:50 PM, Bill Myers wrote: > The advantage of segmented stacks is that blocked tasks only take up > as much memory as they actually need to store state, so that for > instance a network server can use a task for each connection, and > still only use, say, 64 bytes per connection if that's possible > instead of the number of stack pages that got allocated for previous > computation (assuming an "extreme" version that allocates a stack > segment on every call). In practice there are a number of other limitations that would ever prevent Rust from reducing a stack segment to 64 bytes. Rust segmented stacks still needed a large 'red zone' for running various bits of code, the most problematic being the dynamic linker. On Linux the dynamic linker needs about 2k of space to resolve symbols, on Mac much more. There are ways to work around this by writing our own dynamic linker or disallowing it, but there are significant obstacles to making the stack as small as one might want. We had the Linux minimum stack down to ~3k (1k for Rust code + *2k* red zone). With mmapped stacks we are always free to unmap pages that aren't in use, saving space. > > However, there is another approach that can replace segmented stacks > for that purpose, namely having the compiler automatically transform > blocking functions to instead return a future (with limited lifetime). > > This means that segmented allocation only happens for functions that > indirectly perform I/O and only allocates the exact amount of memory > needed to retain state that must persistent across the blocking I/O > operation, while other functions execute normally using traditional > stacks. > > The simplest example of this feature is async/await in C# 5, and Scala > has a delimited continuation passing transformation that can be used > to do the same thing. > > Has this been considered for Rust? > Aren't these futures fullfilled by some kind of task abstraction that runs on a thread pool or something? Do these tasks not have their own stacks? I have thought about C#'s async/await feature but decided it was more or less equivalent to tasks. -------------- next part -------------- An HTML attachment was scrubbed... URL: From banderson at mozilla.com Tue Nov 5 13:42:36 2013 From: banderson at mozilla.com (Brian Anderson) Date: Tue, 05 Nov 2013 13:42:36 -0800 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: <5278563F.2070507@mozilla.com> Message-ID: <5279664C.6020908@mozilla.com> On 11/04/2013 09:21 PM, Oren Ben-Kiki wrote: > Note that as memory becomes cheaper and larger there will be more > pressure on 64-bit OS-es to switch to large pages; the number of pages > needed to map several GBs of memory today is already getting out of > hand, causing TLB misses to become a performance issue in some cases - > imagine a system with 0.xTBs of memory and it becomes ludicrous. > > So playing tricks with MMU and lazy page loading may not work as well > as it does with today's the small 4K page size. Of course, Rust is > hardly the only platform that would be affected :-) and ideally, it > would be possible to have more flexibility than today in choosing > which page sizes are used where in the program's address space... but > it remains to be seen how exactly this would play out. > > Just a point to keep in mind... > Thanks! That is an interesting point that I hadn't thought about. From haoyi.sg at gmail.com Tue Nov 5 14:32:34 2013 From: haoyi.sg at gmail.com (Haoyi Li) Date: Tue, 5 Nov 2013 14:32:34 -0800 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: <5279664C.6020908@mozilla.com> References: <5278563F.2070507@mozilla.com> <5279664C.6020908@mozilla.com> Message-ID: C# Async/Await is distinct from segmented stacks because they store the enclosed variables as heap objects rather than on the stack; that means it goes through the same malloc/garbage collector as any other heap objects you create. It's purely a compiler fiction to let you write code that 'looks' like it's stack allocating variables. On Tue, Nov 5, 2013 at 1:42 PM, Brian Anderson wrote: > On 11/04/2013 09:21 PM, Oren Ben-Kiki wrote: > >> Note that as memory becomes cheaper and larger there will be more >> pressure on 64-bit OS-es to switch to large pages; the number of pages >> needed to map several GBs of memory today is already getting out of hand, >> causing TLB misses to become a performance issue in some cases - imagine a >> system with 0.xTBs of memory and it becomes ludicrous. >> >> So playing tricks with MMU and lazy page loading may not work as well as >> it does with today's the small 4K page size. Of course, Rust is hardly the >> only platform that would be affected :-) and ideally, it would be possible >> to have more flexibility than today in choosing which page sizes are used >> where in the program's address space... but it remains to be seen how >> exactly this would play out. >> >> Just a point to keep in mind... >> >> > Thanks! That is an interesting point that I hadn't thought about. > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From corey at octayn.net Tue Nov 5 14:49:02 2013 From: corey at octayn.net (Corey Richardson) Date: Tue, 5 Nov 2013 17:49:02 -0500 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: <527965EA.1080604@mozilla.com> References: <5278563F.2070507@mozilla.com> <527965EA.1080604@mozilla.com> Message-ID: On Tue, Nov 5, 2013 at 4:40 PM, Brian Anderson wrote: > On 11/04/2013 07:50 PM, Bill Myers wrote: > > The advantage of segmented stacks is that blocked tasks only take up as much > memory as they actually need to store state, so that for instance a network > server can use a task for each connection, and still only use, say, 64 bytes > per connection if that's possible instead of the number of stack pages that > got allocated for previous computation (assuming an "extreme" version that > allocates a stack segment on every call). > > > In practice there are a number of other limitations that would ever prevent > Rust from reducing a stack segment to 64 bytes. Rust segmented stacks still > needed a large 'red zone' for running various bits of code, the most > problematic being the dynamic linker. Plus the sysv amd64 ABI requires a 128 byte red zone under the stack anyway. From hatahet at gmail.com Tue Nov 5 19:34:12 2013 From: hatahet at gmail.com (Ziad Hatahet) Date: Tue, 5 Nov 2013 19:34:12 -0800 Subject: [rust-dev] the inter-play of struct type impl, traits, & type params In-Reply-To: References: <5278CBF1.8010900@gmail.com> <52792823.40403@mozilla.com> Message-ID: The following seems to work: trait Double { fn double(&self) -> Self; } impl Double for int { fn double(&self) -> int { *self * 2 } } fn main() { let x = 2; println!("{}", x.double()); // prints "4" } -- Ziad On Tue, Nov 5, 2013 at 1:29 PM, Steven Blenkinsop wrote: > As long as "you" are the person who owns the type, yeah, but I suspect > that's not what you mean. Coherence requires that you only implement traits > for types if you own either the trait or the type (or both). You can't > implement a 3rd party trait for a 3rd party type, since then there could be > multiple such implementations for a given (trait, type) pair, and coherence > would be broken. > > > On Tue, Nov 5, 2013 at 2:28 PM, Ziad Hatahet wrote: > >> On Tue, Nov 5, 2013 at 9:17 AM, Patrick Walton wrote: >> >>> On 11/5/13 2:44 AM, spir wrote: >>> >>>> Why not just add a declaration of the trait at the top of the struct >>>> type def? >>>> >>>> struct PairList : Iterable { >>>> >>> >>> You can implement traits on types that aren't structs. >> >> >> >> Isn't another effect of this is the ability to "monkey-patch" structs to >> implement extra methods or traits? E.g. you can later in implement a >> to_str() method for a type, or implement certain traits, like Clone or Drop. >> >> >> -- >> Ziad >> >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steven099 at gmail.com Tue Nov 5 20:25:17 2013 From: steven099 at gmail.com (Steven Blenkinsop) Date: Tue, 5 Nov 2013 23:25:17 -0500 Subject: [rust-dev] the inter-play of struct type impl, traits, & type params In-Reply-To: References: <5278CBF1.8010900@gmail.com> <52792823.40403@mozilla.com> Message-ID: Here you own the trait "Double". Doesn't work if you were trying to implement a trait you hadn't just defined. The specific examples you mentioned were Clone and Drop, so that wouldn't work. On Tuesday, November 5, 2013, Ziad Hatahet wrote: > The following seems to work: > > trait Double { > fn double(&self) -> Self; > } > > impl Double for int { > fn double(&self) -> int { > *self * 2 > } > } > > fn main() { > let x = 2; > println!("{}", x.double()); // prints "4" > } > > > > -- > Ziad > > > On Tue, Nov 5, 2013 at 1:29 PM, Steven Blenkinsop > > wrote: > >> As long as "you" are the person who owns the type, yeah, but I suspect >> that's not what you mean. Coherence requires that you only implement traits >> for types if you own either the trait or the type (or both). You can't >> implement a 3rd party trait for a 3rd party type, since then there could be >> multiple such implementations for a given (trait, type) pair, and coherence >> would be broken. >> >> >> On Tue, Nov 5, 2013 at 2:28 PM, Ziad Hatahet >> > wrote: >> >>> On Tue, Nov 5, 2013 at 9:17 AM, Patrick Walton >>> > wrote: >>> >>>> On 11/5/13 2:44 AM, spir wrote: >>>> >>>>> Why not just add a declaration of the trait at the top of the struct >>>>> type def? >>>>> >>>>> struct PairList : Iterable { >>>>> >>>> >>>> You can implement traits on types that aren't structs. >>> >>> >>> >>> Isn't another effect of this is the ability to "monkey-patch" structs to >>> implement extra methods or traits? E.g. you can later in implement a >>> to_str() method for a type, or implement certain traits, like Clone or Drop. >>> >>> >>> -- >>> Ziad >>> >>> >>> _______________________________________________ >>> Rust-dev mailing list >>> Rust-dev at mozilla.org >> 'Rust-dev at mozilla.org');> >>> https://mail.mozilla.org/listinfo/rust-dev >>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From hatahet at gmail.com Tue Nov 5 20:53:45 2013 From: hatahet at gmail.com (Ziad Hatahet) Date: Tue, 5 Nov 2013 20:53:45 -0800 Subject: [rust-dev] the inter-play of struct type impl, traits, & type params In-Reply-To: References: <5278CBF1.8010900@gmail.com> <52792823.40403@mozilla.com> Message-ID: Gotcha. But it is still pretty flexible in that you are not bound to the impls that were originally defined on the type (e.g. like C++/Java where the list of interfaces implemented by a class are fixed). This relieves one form writing wrapper classes in order for certain structs to adhere to particular interfaces. -- Ziad On Tue, Nov 5, 2013 at 8:25 PM, Steven Blenkinsop wrote: > Here you own the trait "Double". Doesn't work if you were trying to > implement a trait you hadn't just defined. The specific examples you > mentioned were Clone and Drop, so that wouldn't work. > > > On Tuesday, November 5, 2013, Ziad Hatahet wrote: > >> The following seems to work: >> >> trait Double { >> fn double(&self) -> Self; >> } >> >> impl Double for int { >> fn double(&self) -> int { >> *self * 2 >> } >> } >> >> fn main() { >> let x = 2; >> println!("{}", x.double()); // prints "4" >> } >> >> >> >> -- >> Ziad >> >> >> On Tue, Nov 5, 2013 at 1:29 PM, Steven Blenkinsop wrote: >> >>> As long as "you" are the person who owns the type, yeah, but I suspect >>> that's not what you mean. Coherence requires that you only implement traits >>> for types if you own either the trait or the type (or both). You can't >>> implement a 3rd party trait for a 3rd party type, since then there could be >>> multiple such implementations for a given (trait, type) pair, and coherence >>> would be broken. >>> >>> >>> On Tue, Nov 5, 2013 at 2:28 PM, Ziad Hatahet wrote: >>> >>>> On Tue, Nov 5, 2013 at 9:17 AM, Patrick Walton wrote: >>>> >>>>> On 11/5/13 2:44 AM, spir wrote: >>>>> >>>>>> Why not just add a declaration of the trait at the top of the struct >>>>>> type def? >>>>>> >>>>>> struct PairList : Iterable { >>>>>> >>>>> >>>>> You can implement traits on types that aren't structs. >>>> >>>> >>>> >>>> Isn't another effect of this is the ability to "monkey-patch" structs >>>> to implement extra methods or traits? E.g. you can later in implement a >>>> to_str() method for a type, or implement certain traits, like Clone or Drop. >>>> >>>> >>>> -- >>>> Ziad >>>> >>>> >>>> _______________________________________________ >>>> Rust-dev mailing list >>>> Rust-dev at mozilla.org >>>> https://mail.mozilla.org/listinfo/rust-dev >>>> >>>> >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From denis.spir at gmail.com Tue Nov 5 23:46:14 2013 From: denis.spir at gmail.com (spir) Date: Wed, 06 Nov 2013 08:46:14 +0100 Subject: [rust-dev] struct def Message-ID: <5279F3C6.2090005@gmail.com> I can write this: struct Points {xs:~[uint], ys:~[uint]} fn main () { let mut ps = Points{xs:~[1u], ys:~[1u]}; ... } But I cannot write that: struct Points {xs:~[T], ys:~[T]} fn main () { let mut ps = Points{xs:~[1u], ys:~[1u]}; ... } In the second case, I get the error: sparse_array.rs:106:31: 106:32 error: expected one of `; }` but found `:` sparse_array.rs:106 let mut ps = Points{xs:~[1u], ys:~[1u]}; ^ Sorry to bother you with that, I find myself unable to find the right syntactic schema (and could not find any example in any doc online). I'm blocked, stupidly. spir at ospir:~$ rust -v rust 0.8 host: x86_64-unknown-linux-gnu Also, I have a general problem with writing struct instances with the type apart; meaning, without any type param, I get the same error: struct Points {xs:~[uint], ys:~[uint]} fn main () { let mut ps : Points = {xs:~[1], ys:~[1]}; ... } ==> parse_array.rs:106:28: 106:29 error: expected one of `; }` but found `:` sparse_array.rs:106 let mut ps : Points = {xs:~[1], ys:~[1]}; ^ More generally, I don't know why there are 2 syntactic schemas to define vars. I would be happy with the latter alone (despite the additional pair of spaces) since it is more coherent and more general in allowing temporalily uninitialised declarations. Denis From oren at ben-kiki.org Wed Nov 6 00:00:34 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Wed, 6 Nov 2013 10:00:34 +0200 Subject: [rust-dev] struct def In-Reply-To: <5279F3C6.2090005@gmail.com> References: <5279F3C6.2090005@gmail.com> Message-ID: I would think: let mut ps = *Points* {xs:~[1], ys:~[1]}; let mut ps : *Points* = *Points* {xs:~[1], ys:~[1]}; In Haskell-speak, there is a different between the "type" and the "constructor", even though by convention they are given the same name. On Wed, Nov 6, 2013 at 9:46 AM, spir wrote: > > I can write this: > struct Points {xs:~[uint], ys:~[uint]} > fn main () { > let mut ps = Points{xs:~[1u], ys:~[1u]}; > ... > } > > But I cannot write that: > struct Points {xs:~[T], ys:~[T]} > fn main () { > let mut ps = Points{xs:~[1u], ys:~[1u]}; > ... > } > > In the second case, I get the error: > sparse_array.rs:106:31: 106:32 error: expected one of `; }` but found `:` > sparse_array.rs:106 let mut ps = Points{xs:~[1u], ys:~[1u]}; > ^ > > Sorry to bother you with that, I find myself unable to find the right > syntactic schema (and could not find any example in any doc online). I'm > blocked, stupidly. > > spir at ospir:~$ rust -v > rust 0.8 > host: x86_64-unknown-linux-gnu > > > Also, I have a general problem with writing struct instances with the type > apart; meaning, without any type param, I get the same error: > struct Points {xs:~[uint], ys:~[uint]} > > fn main () { > let mut ps : Points = {xs:~[1], ys:~[1]}; > ... > } > ==> > parse_array.rs:106:28: 106:29 error: expected one of `; }` but found `:` > sparse_array.rs:106 let mut ps : Points = {xs:~[1], ys:~[1]}; > ^ > > More generally, I don't know why there are 2 syntactic schemas to define > vars. I would be happy with the latter alone (despite the additional pair > of spaces) since it is more coherent and more general in allowing > temporalily uninitialised declarations. > > Denis > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dbau.pp at gmail.com Wed Nov 6 00:10:10 2013 From: dbau.pp at gmail.com (Huon Wilson) Date: Wed, 06 Nov 2013 19:10:10 +1100 Subject: [rust-dev] struct def In-Reply-To: <5279F3C6.2090005@gmail.com> References: <5279F3C6.2090005@gmail.com> Message-ID: <5279F962.2050703@gmail.com> On 06/11/13 18:46, spir wrote: > > I can write this: > struct Points {xs:~[uint], ys:~[uint]} > fn main () { > let mut ps = Points{xs:~[1u], ys:~[1u]}; > ... > } > > But I cannot write that: > struct Points {xs:~[T], ys:~[T]} > fn main () { > let mut ps = Points{xs:~[1u], ys:~[1u]}; > ... > } > > In the second case, I get the error: > sparse_array.rs:106:31: 106:32 error: expected one of `; }` but found `:` > sparse_array.rs:106 let mut ps = Points{xs:~[1u], ys:~[1u]}; > ^ The correct syntax is `let mut ps = Points:: { xs: ~[1u], ys: ~[1u] };`, but this actually does nothing, it's totally ignored ( https://github.com/mozilla/rust/issues/9620 ). In general, type inference means that you can normally just write `let mut ps = Points { xs: ~[1u], ys: ~[1u] }` even with the generic declaration of `Points`. > > Sorry to bother you with that, I find myself unable to find the right > syntactic schema (and could not find any example in any doc online). > I'm blocked, stupidly. > > spir at ospir:~$ rust -v > rust 0.8 > host: x86_64-unknown-linux-gnu > > > Also, I have a general problem with writing struct instances with the > type apart; meaning, without any type param, I get the same error: > struct Points {xs:~[uint], ys:~[uint]} > > fn main () { > let mut ps : Points = {xs:~[1], ys:~[1]}; > ... > } > ==> > parse_array.rs:106:28: 106:29 error: expected one of `; }` but found `:` > sparse_array.rs:106 let mut ps : Points = {xs:~[1], ys:~[1]}; > ^ You need to write the struct name always, since { } is valid expression, e.g. `let x = { foo(); bar(); baz() };`. So, in this case, `let mut ps: Points = Points { xs: ~[1], ys: ~[1] };`. > > More generally, I don't know why there are 2 syntactic schemas to > define vars. I would be happy with the latter alone (despite the > additional pair of spaces) since it is more coherent and more general > in allowing temporalily uninitialised declarations. Which two schema are you referring to? `let x: Type = value;` vs. `let x = value;`? If so, they're actually the same, the first just has the optional type specified. (One can provide temporarily uninitialised declarations by just `let x;`, as long as the compiler has enough information to (a) know that the variable is assigned before every use, and (b) infer the type.) Huon From niko at alum.mit.edu Wed Nov 6 06:41:14 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Wed, 6 Nov 2013 09:41:14 -0500 Subject: [rust-dev] the inter-play of struct type impl, traits, & type params In-Reply-To: References: <5278CBF1.8010900@gmail.com> <52792823.40403@mozilla.com> Message-ID: <20131106144114.GB18529@Mr-Bennet> On Tue, Nov 05, 2013 at 08:53:45PM -0800, Ziad Hatahet wrote: > This relieves one form writing wrapper classes in order for certain > structs to adhere to particular interfaces. Partially, yes. Where this breaks down is if you have a type from one crate and an interface from another. We can't help you there, though you can often workaround this problem by wrapping the type in a struct that you created, and defining the interface on that struct type instead. Niko From oren at ben-kiki.org Wed Nov 6 10:38:13 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Wed, 6 Nov 2013 20:38:13 +0200 Subject: [rust-dev] The let keyword Message-ID: Coming from Haskell, I realize some of the background of using this syntax form. But looking at my code, I sometimes wish I could just write `x: Foo := foo();` instead of `let x: Foo = foo();`. All these `let`s in the code seem noisy. I suppose this was an explicit design decision - I wonder if anyone can say something about why one form was used over the other? -------------- next part -------------- An HTML attachment was scrubbed... URL: From catamorphism at gmail.com Wed Nov 6 10:39:52 2013 From: catamorphism at gmail.com (Tim Chevalier) Date: Wed, 6 Nov 2013 10:39:52 -0800 Subject: [rust-dev] The let keyword In-Reply-To: References: Message-ID: On Wed, Nov 6, 2013 at 10:38 AM, Oren Ben-Kiki wrote: > Coming from Haskell, I realize some of the background of using this syntax > form. But looking at my code, I sometimes wish I could just write `x: Foo := > foo();` instead of `let x: Foo = foo();`. All these `let`s in the code seem > noisy. I suppose this was an explicit design decision - I wonder if anyone > can say something about why one form was used over the other? Haskell doesn't have assignment, so in Rust the `let` keyword makes it easy to visually distinguish updates from declarations. It also makes some of the dataflow analyses in the compiler easier (for example, it's easier to do the analysis that tells you which variables, if any, are used before initialization if you know where all the declarations are). Cheers, Tim > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt "If you are silent about your pain, they'll kill you and say you enjoyed it." -- Zora Neale Hurston From pcwalton at mozilla.com Wed Nov 6 10:56:47 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Wed, 06 Nov 2013 10:56:47 -0800 Subject: [rust-dev] The let keyword In-Reply-To: References: Message-ID: <527A90EF.4070100@mozilla.com> On 11/6/13 10:38 AM, Oren Ben-Kiki wrote: > Coming from Haskell, I realize some of the background of using this > syntax form. But looking at my code, I sometimes wish I could just write > `x: Foo := foo();` instead of `let x: Foo = foo();`. All these `let`s in > the code seem noisy. I suppose this was an explicit design decision - I > wonder if anyone can say something about why one form was used over the > other? `let` tells the parser that there's a pattern coming up. Languages that do 'x := whatever' can never have destructuring without some sort of cover grammar hack. Patrick From oren at ben-kiki.org Wed Nov 6 10:58:40 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Wed, 6 Nov 2013 20:58:40 +0200 Subject: [rust-dev] The let keyword In-Reply-To: <527A90EF.4070100@mozilla.com> References: <527A90EF.4070100@mozilla.com> Message-ID: I didn't consider that; `pattern := expression` would require "infinite lookahead" in the parser, I guess. Good point. Thanks! On Wed, Nov 6, 2013 at 8:56 PM, Patrick Walton wrote: > `let` tells the parser that there's a pattern coming up. > > Languages that do 'x := whatever' can never have destructuring without > some sort of cover grammar hack. -------------- next part -------------- An HTML attachment was scrubbed... URL: From gaetan at xeberon.net Thu Nov 7 02:03:58 2013 From: gaetan at xeberon.net (Gaetan) Date: Thu, 7 Nov 2013 11:03:58 +0100 Subject: [rust-dev] About owned pointer Message-ID: Hello I really the concept of owned pointers, and I'm wondering if it could be the default. I mean, the more I use it, the more I tend to use it everywhere, and it seem any "average" user-code (ie, not the rust compiler itself) will have a lot of "~var" anywhere, "let i=~5", ..., more than the other variable initialization. Look at the unit tests for libstd or libextra. Why not having the default syntax be owned pointers, and the ~ syntax (or another one) be the syntax for creating variable on the heap? let i=5; // owned pointer let j=~5; // heap value Regards, ----- Gaetan -------------- next part -------------- An HTML attachment was scrubbed... URL: From robertknight at gmail.com Thu Nov 7 02:13:29 2013 From: robertknight at gmail.com (Robert Knight) Date: Thu, 7 Nov 2013 10:13:29 +0000 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: > Why not having the default syntax be owned pointers, and the ~ syntax (or another one) be the syntax for creating variable on the heap? ~ does allocate on the heap. Without ~ you allocate on the stack. Regards, Rob. On 7 November 2013 10:03, Gaetan wrote: > Hello > > I really the concept of owned pointers, and I'm wondering if it could be the > default. > > I mean, the more I use it, the more I tend to use it everywhere, and it seem > any "average" user-code (ie, not the rust compiler itself) will have a lot > of "~var" anywhere, "let i=~5", ..., more than the other variable > initialization. Look at the unit tests for libstd or libextra. > > Why not having the default syntax be owned pointers, and the ~ syntax (or > another one) be the syntax for creating variable on the heap? > > let i=5; // owned pointer > let j=~5; // heap value > > Regards, > ----- > Gaetan > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > From gaetan at xeberon.net Thu Nov 7 02:18:56 2013 From: gaetan at xeberon.net (Gaetan) Date: Thu, 7 Nov 2013 11:18:56 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: sorry for the confusion ----- Gaetan 2013/11/7 Robert Knight > > Why not having the default syntax be owned pointers, and the ~ syntax > (or another one) be the syntax for creating variable on the heap? > > ~ does allocate on the heap. Without ~ you allocate on the stack. > > Regards, > Rob. > > On 7 November 2013 10:03, Gaetan wrote: > > Hello > > > > I really the concept of owned pointers, and I'm wondering if it could be > the > > default. > > > > I mean, the more I use it, the more I tend to use it everywhere, and it > seem > > any "average" user-code (ie, not the rust compiler itself) will have a > lot > > of "~var" anywhere, "let i=~5", ..., more than the other variable > > initialization. Look at the unit tests for libstd or libextra. > > > > Why not having the default syntax be owned pointers, and the ~ syntax (or > > another one) be the syntax for creating variable on the heap? > > > > let i=5; // owned pointer > > let j=~5; // heap value > > > > Regards, > > ----- > > Gaetan > > > > > > _______________________________________________ > > Rust-dev mailing list > > Rust-dev at mozilla.org > > https://mail.mozilla.org/listinfo/rust-dev > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From loebel.marvin at gmail.com Thu Nov 7 02:24:38 2013 From: loebel.marvin at gmail.com (=?ISO-8859-1?Q?Marvin_L=F6bel?=) Date: Thu, 07 Nov 2013 11:24:38 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: <527B6A66.8010300@gmail.com> On 11/07/2013 11:03 AM, Gaetan wrote: > I mean, the more I use it, the more I tend to use it everywhere, and > it seem any "average" user-code (ie, not the rust compiler itself) > will have a lot of "~var" anywhere, "let i=~5", ..., more than the > other variable initialization. Look at the unit tests for libstd or > libextra. The unit tests are not necessary good code examples. In actual good rust code, you'd almost never need to use a heap allocated ~T if you can use a T on the stack. There is also no problem with that: A ~T behaves almost exactly like a T, the only exceptions being that ~T is always pointer sized, and that ~T always has a destructor, which means it always gets moved around instead of possibly being implicitly copied. From loebel.marvin at gmail.com Thu Nov 7 02:46:14 2013 From: loebel.marvin at gmail.com (=?ISO-8859-1?Q?Marvin_L=F6bel?=) Date: Thu, 7 Nov 2013 11:46:14 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: <527B6A66.8010300@gmail.com> References: <527B6A66.8010300@gmail.com> Message-ID: Don't worry, our pointers _are_ more confusing compared to many other languages after all. :) Am 07.11.2013 11:25 schrieb "Marvin L?bel" : > On 11/07/2013 11:03 AM, Gaetan wrote: > >> I mean, the more I use it, the more I tend to use it everywhere, and it >> seem any "average" user-code (ie, not the rust compiler itself) will have a >> lot of "~var" anywhere, "let i=~5", ..., more than the other variable >> initialization. Look at the unit tests for libstd or libextra. >> > The unit tests are not necessary good code examples. In actual good rust > code, you'd almost never need to use a heap allocated ~T if you can use a T > on the stack. > There is also no problem with that: A ~T behaves almost exactly like a T, > the only exceptions being that ~T is always pointer sized, and that ~T > always has a destructor, which means it always gets moved around instead of > possibly being implicitly copied. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Thu Nov 7 13:48:06 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Thu, 7 Nov 2013 16:48:06 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: On Thu, Nov 7, 2013 at 5:03 AM, Gaetan wrote: > Hello > > I really the concept of owned pointers, and I'm wondering if it could be > the default. > > I mean, the more I use it, the more I tend to use it everywhere, and it > seem any "average" user-code (ie, not the rust compiler itself) will have a > lot of "~var" anywhere, "let i=~5", ..., more than the other variable > initialization. Look at the unit tests for libstd or libextra. > > Why not having the default syntax be owned pointers, and the ~ syntax (or > another one) be the syntax for creating variable on the heap? > > let i=5; // owned pointer > let j=~5; // heap value > > Regards, > ----- > Gaetan > Owned boxes shouldn't be commonly used. There's close to no reason to use one for anything but a recursive data structure or in rare cases for an owned trait object. http://static.rust-lang.org/doc/master/tutorial.html#boxes It's important to note that ~[T] and ~str are not owned boxes. They're just sugar for dynamic arrays, and are common containers. -------------- next part -------------- An HTML attachment was scrubbed... URL: From com.liigo at gmail.com Thu Nov 7 15:32:02 2013 From: com.liigo at gmail.com (Liigo Zhuang) Date: Fri, 8 Nov 2013 07:32:02 +0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: > Owned boxes shouldn't be commonly used. There's close to no reason to use one for anything but a recursive data structure or in rare cases for an owned trait object. > > http://static.rust-lang.org/doc/master/tutorial.html#boxes > > It's important to note that ~[T] and ~str are not owned boxes. They're just sugar for dynamic arrays, and are common containers. > It's so confusing. If it's not owned box, why not remove ~? Make "str" default be dynamic should OK. -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Thu Nov 7 15:36:33 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Thu, 7 Nov 2013 18:36:33 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: On Thu, Nov 7, 2013 at 6:32 PM, Liigo Zhuang wrote: > > Owned boxes shouldn't be commonly used. There's close to no reason to > use one for anything but a recursive data structure or in rare cases for an > owned trait object. > > > > http://static.rust-lang.org/doc/master/tutorial.html#boxes > > > > It's important to note that ~[T] and ~str are not owned boxes. They're > just sugar for dynamic arrays, and are common containers. > > > It's so confusing. If it's not owned box, why not remove ~? Make "str" > default be dynamic should OK. > It wouldn't be okay for every string literal to result in a heap allocation. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfager at gmail.com Thu Nov 7 16:49:45 2013 From: jfager at gmail.com (Jason Fager) Date: Thu, 7 Nov 2013 19:49:45 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: Can you speak a little to the practical differences between owned boxes and ~[T]/~str? How does the difference affect how I should use each? On Thursday, November 7, 2013, Daniel Micay wrote: > On Thu, Nov 7, 2013 at 6:32 PM, Liigo Zhuang > > wrote: > >> > Owned boxes shouldn't be commonly used. There's close to no reason to >> use one for anything but a recursive data structure or in rare cases for an >> owned trait object. >> > >> > http://static.rust-lang.org/doc/master/tutorial.html#boxes >> > >> > It's important to note that ~[T] and ~str are not owned boxes. They're >> just sugar for dynamic arrays, and are common containers. >> > >> It's so confusing. If it's not owned box, why not remove ~? Make "str" >> default be dynamic should OK. >> > > It wouldn't be okay for every string literal to result in a heap > allocation. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Thu Nov 7 16:59:41 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Thu, 7 Nov 2013 19:59:41 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: On Thu, Nov 7, 2013 at 7:49 PM, Jason Fager wrote: > Can you speak a little to the practical differences between owned boxes > and ~[T]/~str? How does the difference affect how I should use each? I wrote the section on owned boxes in the tutorial currently in master, so I would suggest reading that. It's very rare for there to be a use case for an owned box outside of a recursive data structure or plugin system (traits as objects). The coverage in the tutorial of vectors/strings is not only lacking in depth but is also *incorrect*, so I understand why there's a lot of confusion about them. Vectors/strings are containers, and aren't connected to owned boxes any more than HashMap/TreeMap/TrieMap. I would prefer it if the syntactic sugar didn't exist and we just had generic container literals, because it seems to end up causing a lot of confusion. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfager at gmail.com Thu Nov 7 17:40:27 2013 From: jfager at gmail.com (Jason Fager) Date: Thu, 7 Nov 2013 20:40:27 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: Let me ask another way: what's wrong with thinking of ~ just as meaning "allocate to the heap and subject to move semantics"? When would that simplification bite me in the ass regarding owned boxes vs strs/vecs? I get that I should very rarely want that for things that aren't dynamic containers or recursive data structures. But beyond that, am I ever going to get myself in trouble not remembering the details of the difference between how ~T works vs ~[T]? On Thursday, November 7, 2013, Daniel Micay wrote: > On Thu, Nov 7, 2013 at 7:49 PM, Jason Fager wrote: > >> Can you speak a little to the practical differences between owned boxes >> and ~[T]/~str? How does the difference affect how I should use each? > > > I wrote the section on owned boxes in the tutorial currently in master, so > I would suggest reading that. It's very rare for there to be a use case for > an owned box outside of a recursive data structure or plugin system (traits > as objects). > > The coverage in the tutorial of vectors/strings is not only lacking in > depth but is also *incorrect*, so I understand why there's a lot of > confusion about them. > > Vectors/strings are containers, and aren't connected to owned boxes any > more than HashMap/TreeMap/TrieMap. I would prefer it if the syntactic sugar > didn't exist and we just had generic container literals, because it seems > to end up causing a lot of confusion. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Thu Nov 7 18:01:39 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Thu, 7 Nov 2013 21:01:39 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: On Thu, Nov 7, 2013 at 8:40 PM, Jason Fager wrote: > Let me ask another way: what's wrong with thinking of ~ just as meaning > "allocate to the heap and subject to move semantics"? When would that > simplification bite me in the ass regarding owned boxes vs strs/vecs? > > I get that I should very rarely want that for things that aren't dynamic > containers or recursive data structures. But beyond that, am I ever going > to get myself in trouble not remembering the details of the difference > between how ~T works vs ~[T]? The heap allocation is a means to an end rather than a useful property. There are lots of types in the standard library with destructors, including most of the containers. There's a deeper connection between TreeMap and an owned box than between owned vectors and owned boxes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From oren at ben-kiki.org Thu Nov 7 22:27:06 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Fri, 8 Nov 2013 08:27:06 +0200 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: <5278563F.2070507@mozilla.com> References: <5278563F.2070507@mozilla.com> Message-ID: Does ditching segmented stacks mean we can start getting a stack trace when a task `fail!`s? Or is this an unrelated issue? The lack of stack traces is extremely tedious when debugging failed assertions... -------------- next part -------------- An HTML attachment was scrubbed... URL: From corey at octayn.net Thu Nov 7 22:40:13 2013 From: corey at octayn.net (Corey Richardson) Date: Fri, 8 Nov 2013 01:40:13 -0500 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: <5278563F.2070507@mozilla.com> Message-ID: Entirely unrelated. Do note that we have stack traces *now*, as long as you're using gdb to get them :). Break on `rust_begin_unwind` or "catch throw". On Fri, Nov 8, 2013 at 1:27 AM, Oren Ben-Kiki wrote: > Does ditching segmented stacks mean we can start getting a stack trace when > a task `fail!`s? Or is this an unrelated issue? > > The lack of stack traces is extremely tedious when debugging failed > assertions... > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > From oren at ben-kiki.org Thu Nov 7 22:45:53 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Fri, 8 Nov 2013 08:45:53 +0200 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: <5278563F.2070507@mozilla.com> Message-ID: Good to know! The GDB stack traces leave something to be desired, though - e.g. the way it reports closures isn't really very useful (adding source file name and line number would be really good there). But it is certainly better than nothing. Thanks! On Fri, Nov 8, 2013 at 8:40 AM, Corey Richardson wrote: > Entirely unrelated. Do note that we have stack traces *now*, as long > as you're using gdb to get them :). Break on `rust_begin_unwind` or > "catch throw". > > On Fri, Nov 8, 2013 at 1:27 AM, Oren Ben-Kiki wrote: > > Does ditching segmented stacks mean we can start getting a stack trace > when > > a task `fail!`s? Or is this an unrelated issue? > > > > The lack of stack traces is extremely tedious when debugging failed > > assertions... > > > > _______________________________________________ > > Rust-dev mailing list > > Rust-dev at mozilla.org > > https://mail.mozilla.org/listinfo/rust-dev > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Thu Nov 7 22:48:14 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Fri, 8 Nov 2013 01:48:14 -0500 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: <5278563F.2070507@mozilla.com> Message-ID: On Fri, Nov 8, 2013 at 1:45 AM, Oren Ben-Kiki wrote: > Good to know! The GDB stack traces leave something to be desired, though - > e.g. the way it reports closures isn't really very useful (adding source > file name and line number would be really good there). But it is certainly > better than nothing. Thanks! > Rust only has boxed (type erased) closures so there's no source data to associate with them. They're a function pointer and some data to go along with it. -------------- next part -------------- An HTML attachment was scrubbed... URL: From oren at ben-kiki.org Thu Nov 7 22:52:56 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Fri, 8 Nov 2013 08:52:56 +0200 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: <5278563F.2070507@mozilla.com> Message-ID: How bad would it be to add another 64 bits to the "some data to go along with it" part? I'm assuming 32 bit for file name index in some table and 32 bit for the line number in the file should be enough :-) On Fri, Nov 8, 2013 at 8:48 AM, Daniel Micay wrote: > On Fri, Nov 8, 2013 at 1:45 AM, Oren Ben-Kiki wrote: > >> Good to know! The GDB stack traces leave something to be desired, though >> - e.g. the way it reports closures isn't really very useful (adding source >> file name and line number would be really good there). But it is certainly >> better than nothing. Thanks! >> > > Rust only has boxed (type erased) closures so there's no source data to > associate with them. They're a function pointer and some data to go along > with it. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Thu Nov 7 22:59:17 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Fri, 8 Nov 2013 01:59:17 -0500 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: <5278563F.2070507@mozilla.com> Message-ID: On Fri, Nov 8, 2013 at 1:52 AM, Oren Ben-Kiki wrote: > How bad would it be to add another 64 bits to the "some data to go along > with it" part? I'm assuming 32 bit for file name index in some table and 32 > bit for the line number in the file should be enough :-) > In debug builds, no problem at all. It would mean updating all code doing transmutes of closures and the code generation for them though. -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Thu Nov 7 23:00:58 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Fri, 8 Nov 2013 02:00:58 -0500 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: <5278563F.2070507@mozilla.com> Message-ID: On Fri, Nov 8, 2013 at 1:59 AM, Daniel Micay wrote: > On Fri, Nov 8, 2013 at 1:52 AM, Oren Ben-Kiki wrote: > >> How bad would it be to add another 64 bits to the "some data to go along >> with it" part? I'm assuming 32 bit for file name index in some table and 32 >> bit for the line number in the file should be enough :-) >> > > In debug builds, no problem at all. It would mean updating all code doing > transmutes of closures and the code generation for them though. > On second thought... it does seem like if the debug data can be associated with functions, it's available for function pointers to them. -------------- next part -------------- An HTML attachment was scrubbed... URL: From oren at ben-kiki.org Thu Nov 7 23:29:06 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Fri, 8 Nov 2013 09:29:06 +0200 Subject: [rust-dev] Abandoning segmented stacks in Rust In-Reply-To: References: <5278563F.2070507@mozilla.com> Message-ID: Added https://github.com/mozilla/rust/issues/10350 then :-) On Fri, Nov 8, 2013 at 9:00 AM, Daniel Micay wrote: > On Fri, Nov 8, 2013 at 1:59 AM, Daniel Micay wrote: > >> On Fri, Nov 8, 2013 at 1:52 AM, Oren Ben-Kiki wrote: >> >>> How bad would it be to add another 64 bits to the "some data to go along >>> with it" part? I'm assuming 32 bit for file name index in some table and 32 >>> bit for the line number in the file should be enough :-) >>> >> >> In debug builds, no problem at all. It would mean updating all code doing >> transmutes of closures and the code generation for them though. >> > > On second thought... it does seem like if the debug data can be associated > with functions, it's available for function pointers to them. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From philippe.delrieu at free.fr Thu Nov 7 23:50:58 2013 From: philippe.delrieu at free.fr (Philippe Delrieu) Date: Fri, 08 Nov 2013 08:50:58 +0100 Subject: [rust-dev] Access error for trait implemtation in multiple file Message-ID: <527C97E2.9020904@free.fr> Hello, rust addict. I have a problem with rustc. I have 3 files. The first one actions.rs contains a trait declaration : pub trait Action { // process the action on server side. fn process(&self) -> ~str; } The second contains a trait implementation testaction.rs: mod actions; pub struct TestAction { actiontype: uint } impl actions::Action for TestAction { fn process(&self) -> ~str { ~"" } } The third test the trait cast : mod actions; mod midi; let element : ~testaction::TestAction = ~testaction::TestAction{actiontype:1}; let actelm: ~actions::Action = element as ~actions::Action; //error here println("process element :" + actelm.process()); => generate error: failed to find an implementation of trait let actelm: ~testaction::actions::Action = element as ~testaction::actions::Action; //error here println("process element :" + actelm.process()); => generate error: trait `Action` is inaccessible If I put testaction content in the test file rustc compile. Any idea? Philippe Delrieu From gaetan at xeberon.net Fri Nov 8 00:43:37 2013 From: gaetan at xeberon.net (Gaetan) Date: Fri, 8 Nov 2013 09:43:37 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: I agree, I don't understand the syntax here. Look at the Url class: pub struct Url { scheme: ~str, user: Option, host: ~str, port: Option<~str>, path: ~str, query: Query, fragment: Option<~str> } pub type Query = ~[(~str, ~str)]; fn split_char_first(s: &str, c: char) -> (~str, ~str) { ... if index+mat == len { return (s.slice(0, index).to_owned(), ~""); } } Isn't simpler, and easier to read, if we write it pub struct Url { scheme: str, user: Option, host: str, port: Option, path: str, query: Query, fragment: Option } pub type Query = [(str, str)]; fn split_char_first(s: &str, c: char) -> (str, str) { ... if index+mat == len { return (s.slice(0, index).to_owned(), ""); } } KISS ! ----- Gaetan 2013/11/8 Jason Fager > Can you speak a little to the practical differences between owned boxes > and ~[T]/~str? How does the difference affect how I should use each? > > > On Thursday, November 7, 2013, Daniel Micay wrote: > >> On Thu, Nov 7, 2013 at 6:32 PM, Liigo Zhuang wrote: >> >>> > Owned boxes shouldn't be commonly used. There's close to no reason to >>> use one for anything but a recursive data structure or in rare cases for an >>> owned trait object. >>> > >>> > http://static.rust-lang.org/doc/master/tutorial.html#boxes >>> > >>> > It's important to note that ~[T] and ~str are not owned boxes. They're >>> just sugar for dynamic arrays, and are common containers. >>> > >>> It's so confusing. If it's not owned box, why not remove ~? Make "str" >>> default be dynamic should OK. >>> >> >> It wouldn't be okay for every string literal to result in a heap >> allocation. >> > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gaetan at xeberon.net Fri Nov 8 00:46:32 2013 From: gaetan at xeberon.net (Gaetan) Date: Fri, 8 Nov 2013 09:46:32 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: // An exchange heap (owned) stringlet exchange_crayons: ~str = ~"Black, BlizzardBlue, Blue"; can you clarify us? thx! ----- Gaetan 2013/11/8 Daniel Micay > On Thu, Nov 7, 2013 at 7:49 PM, Jason Fager wrote: > >> Can you speak a little to the practical differences between owned boxes >> and ~[T]/~str? How does the difference affect how I should use each? > > > I wrote the section on owned boxes in the tutorial currently in master, so > I would suggest reading that. It's very rare for there to be a use case for > an owned box outside of a recursive data structure or plugin system (traits > as objects). > > The coverage in the tutorial of vectors/strings is not only lacking in > depth but is also *incorrect*, so I understand why there's a lot of > confusion about them. > > Vectors/strings are containers, and aren't connected to owned boxes any > more than HashMap/TreeMap/TrieMap. I would prefer it if the syntactic sugar > didn't exist and we just had generic container literals, because it seems > to end up causing a lot of confusion. > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From philippe.delrieu at free.fr Fri Nov 8 00:49:00 2013 From: philippe.delrieu at free.fr (Philippe Delrieu) Date: Fri, 08 Nov 2013 09:49:00 +0100 Subject: [rust-dev] zmq and Rust task Message-ID: <527CA57C.1050604@free.fr> Hello, I don't know if it's the right place to ask but I didn't find any information on zmq side. I found a strange behaviour using zmq rust binding. I start a task that loop and after I start another task that bind a port and way to receive a message. The zmq recv call block the first task that run only when the second task is receiving a message. The only way I found is to use the ZMQ_NOBLOCK (1) flag but I found strange that a blocked task can block all other task. I test on linux (Ubuntu 1204) with the master trunk of Rust (cloned on 10/20/13) and the trunk of rust-zmq. My version of zmq is 3.2.4. Any idea? The code : extern mod extra; extern mod zmq; use std::rt::io::timer; #[main] fn main() { println("hello?"); do spawn || { loop { timer::sleep(500); println("coucou"); } } do spawn || { let context = zmq::Context::new(); let responder = context.socket(zmq::REP).unwrap(); assert!(responder.bind("tcp://*:5555").is_ok()); let mut msg = zmq::Message::new(); loop { responder.recv(&mut msg, 0); do msg.with_str |s| { println!("Received {}", s); } responder.send_str("World", 0); timer::sleep(100); } } timer::sleep(10000); } Philippe Delrieu From alex at crichton.co Fri Nov 8 00:53:18 2013 From: alex at crichton.co (Alex Crichton) Date: Fri, 8 Nov 2013 00:53:18 -0800 Subject: [rust-dev] Access error for trait implemtation in multiple file In-Reply-To: <527C97E2.9020904@free.fr> References: <527C97E2.9020904@free.fr> Message-ID: You should be careful to declare modules only once. It looks like you have two instances of "mod actions" in the module hierarchy, and both modules will be compiled as separate entities (although everything will have the same name). If you remove the `mod actions` inside of testaction.rs you should start making some more progress. You'll probably hit some name resolution issues, but just be sure to import the previous declaration of the `actions` module in the top level of the crate. On Thu, Nov 7, 2013 at 11:50 PM, Philippe Delrieu wrote: > Hello, rust addict. > > I have a problem with rustc. I have 3 files. > The first one actions.rs contains a trait declaration : > > pub trait Action { > // process the action on server side. > fn process(&self) -> ~str; > } > > The second contains a trait implementation testaction.rs: > mod actions; > > > pub struct TestAction { > actiontype: uint > } > > impl actions::Action for TestAction { > > fn process(&self) -> ~str { > ~"" > } > } > The third test the trait cast : > mod actions; > mod midi; > > let element : ~testaction::TestAction = > ~testaction::TestAction{actiontype:1}; > let actelm: ~actions::Action = element as ~actions::Action; > //error here > println("process element :" + actelm.process()); > => generate error: failed to find an implementation of trait > > let actelm: ~testaction::actions::Action = element as > ~testaction::actions::Action; //error here > println("process element :" + actelm.process()); > => generate error: trait `Action` is inaccessible > > If I put testaction content in the test file rustc compile. > > Any idea? > > Philippe Delrieu > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From danielmicay at gmail.com Fri Nov 8 00:53:41 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Fri, 8 Nov 2013 03:53:41 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: On Fri, Nov 8, 2013 at 3:43 AM, Gaetan wrote: > I agree, I don't understand the syntax here. > > Look at the Url class: > > > pub struct Url { > scheme: ~str, > user: Option, > host: ~str, > port: Option<~str>, > path: ~str, > query: Query, > fragment: Option<~str> > } > > pub type Query = ~[(~str, ~str)]; > > fn split_char_first(s: &str, c: char) -> (~str, ~str) { > ... > if index+mat == len { > return (s.slice(0, index).to_owned(), ~""); > } > } > > > Isn't simpler, and easier to read, if we write it > > > pub struct Url { > scheme: str, > user: Option, > host: str, > port: Option, > path: str, > query: Query, > fragment: Option > } > > pub type Query = [(str, str)]; > > fn split_char_first(s: &str, c: char) -> (str, str) { > ... > if index+mat == len { > return (s.slice(0, index).to_owned(), ""); > } > } > > > KISS ! > It couldn't be called `str`, because `&str` is a slice. -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Fri Nov 8 01:01:46 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Fri, 8 Nov 2013 04:01:46 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: On Fri, Nov 8, 2013 at 3:46 AM, Gaetan wrote: > // An exchange heap (owned) stringlet exchange_crayons: ~str = ~"Black, BlizzardBlue, Blue"; > > > can you clarify us? > > thx! > ----- > Gaetan > I suggest ignoring the string/vector section in the tutorial because it's misleading and in some places incorrect. I'll send in a pull request removing the incorrect information. -------------- next part -------------- An HTML attachment was scrubbed... URL: From gaetan at xeberon.net Fri Nov 8 01:05:38 2013 From: gaetan at xeberon.net (Gaetan) Date: Fri, 8 Nov 2013 10:05:38 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: I think a clear paragraph on these cases (~ and ~[]) will help a lot the understanding of this subtlety... ----- Gaetan 2013/11/8 Daniel Micay > On Fri, Nov 8, 2013 at 3:46 AM, Gaetan wrote: > >> >> // An exchange heap (owned) stringlet exchange_crayons: ~str = ~"Black, BlizzardBlue, Blue"; >> >> >> can you clarify us? >> >> thx! >> ----- >> Gaetan >> > > I suggest ignoring the string/vector section in the tutorial because it's > misleading and in some places incorrect. > > I'll send in a pull request removing the incorrect information. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Fri Nov 8 02:07:24 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Fri, 8 Nov 2013 05:07:24 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: On Fri, Nov 8, 2013 at 4:05 AM, Gaetan wrote: > I think a clear paragraph on these cases (~ and ~[]) will help a lot the > understanding of this subtlety... > > ----- > Gaetan > Here are the changes: https://github.com/mozilla/rust/pull/10354 -------------- next part -------------- An HTML attachment was scrubbed... URL: From niko at alum.mit.edu Fri Nov 8 03:24:24 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Fri, 8 Nov 2013 06:24:24 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: <20131108112424.GB23082@Mr-Bennet> On Thu, Nov 07, 2013 at 04:48:06PM -0500, Daniel Micay wrote: > Owned boxes shouldn't be commonly used. There's close to no reason to use > one for anything but a recursive data structure or in rare cases for an > owned trait object. I don't really agree with this statement. I agree that those are the two cases an owned pointer is mandatory, and that the choice between `T` and `~T` is a matter of optimization, and hence something that should be measured. However, I don't think it's *so* unusual that one might want pointer-sized values. Off the top of my head, here are some more scenarios where owned pointers certainly make sense: 1. Options, particularly those that are frequently none. `Option<~HashMap<...>>` is a single word in size. If it is `None`, that's just a NULL pointer. 2. Enum variants. The size of an enum is the size of its largest variant. If you have: enum Foo { Opt1(uint), Opt2(HashMap<...>), Opt3(uint, uint, uint), } You are potentially wasting a lot of space, unless `Opt1` is very rare. You'd be better off doing something like: enum Foo { Opt1(uint), Opt2(~HashMap<...>), Opt3(~Opt3) } struct Opt3 { uint, uint, uint } Niko From niko at alum.mit.edu Fri Nov 8 03:33:23 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Fri, 8 Nov 2013 06:33:23 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: <20131108113323.GC23082@Mr-Bennet> On Fri, Nov 08, 2013 at 07:32:02AM +0800, Liigo Zhuang wrote: > It's so confusing. If it's not owned box, why not remove ~? Make "str" > default be dynamic should OK. I am not sure why Daniel says that a `~str` or `~[]` is not an "owned box". I guess he's using the term in some specific way. I consider `~str` and `~[]` to be exactly the same as any other `~T` value in usage and semantics. They are allocated on the same heap, moved from place to place, and freed at the same time, etc. The difference between a type like `str` or `[T]` and other types is that `str` and `[T]` are actually a series of values: `u8` bytes and `T` values respectively. This entails a change in representation and is also the reason that one *must* use a pointer to refer to them, because the number of values is not known and hence the compiler can't calculate the size of the value. Note that we are to some extent evolving how we handle dynamically sized types like `str` and `[]`. Right now they are quite second class (you can't impl them etc) but that will change. Nonetheless, it will remain true that you can never have a *value* of type `str` or `[]`, but most always use a pointer (either `~[]` or `&[]`). Also note that a type like `~[T]` is in fact going to be represented not as a single pointer but rather three pointers, thanks to work by Daniel in fact. Niko From niko at alum.mit.edu Fri Nov 8 03:37:44 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Fri, 8 Nov 2013 06:37:44 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: <20131108113744.GD23082@Mr-Bennet> On Thu, Nov 07, 2013 at 08:40:27PM -0500, Jason Fager wrote: > Let me ask another way: what's wrong with thinking of ~ just as meaning > "allocate to the heap and subject to move semantics"? When would that > simplification bite me in the ass regarding owned boxes vs strs/vecs? I don't consider that to be a simplification, really. It sounds about right to me. Of course a `~` pointer is not the only way to have move semantics; any destructor will do. Niko From danielmicay at gmail.com Fri Nov 8 03:46:37 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Fri, 8 Nov 2013 06:46:37 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: <20131108112424.GB23082@Mr-Bennet> References: <20131108112424.GB23082@Mr-Bennet> Message-ID: On Fri, Nov 8, 2013 at 6:24 AM, Niko Matsakis wrote: > On Thu, Nov 07, 2013 at 04:48:06PM -0500, Daniel Micay wrote: > > Owned boxes shouldn't be commonly used. There's close to no reason to use > > one for anything but a recursive data structure or in rare cases for an > > owned trait object. > > I don't really agree with this statement. I agree that those are the > two cases an owned pointer is mandatory, and that the choice between > `T` and `~T` is a matter of optimization, and hence something that > should be measured. > > However, I don't think it's *so* unusual that one might want > pointer-sized values. Off the top of my head, here are some more > scenarios where owned pointers certainly make sense: > > 1. Options, particularly those that are frequently none. > `Option<~HashMap<...>>` is a single word in size. If it is > `None`, that's just a NULL pointer. > > 2. Enum variants. The size of an enum is the size of its largest > variant. If you have: > > enum Foo { > Opt1(uint), > Opt2(HashMap<...>), > Opt3(uint, uint, uint), > } > > You are potentially wasting a lot of space, unless `Opt1` is very > rare. You'd be better off doing something like: > > enum Foo { > Opt1(uint), > Opt2(~HashMap<...>), > Opt3(~Opt3) > } > > struct Opt3 { uint, uint, uint } > > > > > Niko > I don't think the need to do micro-optimizations like this is *common* though. It gets to the point where you're optimizing for the characteristics of a specific allocator because they use different size class buckets so trusting a profiler on one platform isn't enough. There's a very real cost to the indirection, extra pointers in the CPU cache, and all the landing pad stuff that ends up generated. I don't deny that indirection can be useful for optimization, but it's unintuitive and often not a portable improvement. In the Boxes section I wrote for the tutorial, it includes this: > In uncommon cases, the indirection can provide a performance gain or memory reduction by making values smaller. However, unboxed values should almost always be preferred. -------------- next part -------------- An HTML attachment was scrubbed... URL: From philippe.delrieu at free.fr Fri Nov 8 04:15:59 2013 From: philippe.delrieu at free.fr (Philippe Delrieu) Date: Fri, 08 Nov 2013 13:15:59 +0100 Subject: [rust-dev] Access error for trait implemtation in multiple file In-Reply-To: References: <527C97E2.9020904@free.fr> Message-ID: <527CD5FF.60304@free.fr> hanks for your fast answer. I've made some test and if I remove mod actions; in testaction.rs I have the error: unresolved name impl actions::Action for TestAction in testaction.rs If I remove the mod actions; and keep the mod testaction; in the test.rs I have unresolved name in the line let actelm: ~actions::Action = element as ~actions::Action; for actions::Action. I don't see what to do!! I didn't fully understand the module management but even if I made something wrong rustc in my opinion shouldn't load the same module twice and if a module is load once it should use it for all. It make me think about I#ifndef in C. Philippe Delrieu Le 08/11/2013 09:53, Alex Crichton a ?crit : > You should be careful to declare modules only once. It looks like you > have two instances of "mod actions" in the module hierarchy, and both > modules will be compiled as separate entities (although everything > will have the same name). > > If you remove the `mod actions` inside of testaction.rs you should > start making some more progress. You'll probably hit some name > resolution issues, but just be sure to import the previous declaration > of the `actions` module in the top level of the crate. > > On Thu, Nov 7, 2013 at 11:50 PM, Philippe Delrieu > wrote: >> Hello, rust addict. >> >> I have a problem with rustc. I have 3 files. >> The first one actions.rs contains a trait declaration : >> >> pub trait Action { >> // process the action on server side. >> fn process(&self) -> ~str; >> } >> >> The second contains a trait implementation testaction.rs: >> mod actions; >> >> >> pub struct TestAction { >> actiontype: uint >> } >> >> impl actions::Action for TestAction { >> >> fn process(&self) -> ~str { >> ~"" >> } >> } >> The third test the trait cast : >> mod actions; >> mod midi; >> >> let element : ~testaction::TestAction = >> ~testaction::TestAction{actiontype:1}; >> let actelm: ~actions::Action = element as ~actions::Action; >> //error here >> println("process element :" + actelm.process()); >> => generate error: failed to find an implementation of trait >> >> let actelm: ~testaction::actions::Action = element as >> ~testaction::actions::Action; //error here >> println("process element :" + actelm.process()); >> => generate error: trait `Action` is inaccessible >> >> If I put testaction content in the test file rustc compile. >> >> Any idea? >> >> Philippe Delrieu >> >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > From danielmicay at gmail.com Fri Nov 8 04:39:59 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Fri, 8 Nov 2013 07:39:59 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: <20131108113323.GC23082@Mr-Bennet> References: <20131108113323.GC23082@Mr-Bennet> Message-ID: On Fri, Nov 8, 2013 at 6:33 AM, Niko Matsakis wrote: > On Fri, Nov 08, 2013 at 07:32:02AM +0800, Liigo Zhuang wrote: > > It's so confusing. If it's not owned box, why not remove ~? Make "str" > > default be dynamic should OK. > > I am not sure why Daniel says that a `~str` or `~[]` is not an "owned > box". I guess he's using the term in some specific way. I consider > `~str` and `~[]` to be exactly the same as any other `~T` value in > usage and semantics. They are allocated on the same heap, moved from > place to place, and freed at the same time, etc. > > The difference between a type like `str` or `[T]` and other types is > that `str` and `[T]` are actually a series of values: `u8` bytes and > `T` values respectively. This entails a change in representation and > is also the reason that one *must* use a pointer to refer to them, > because the number of values is not known and hence the compiler can't > calculate the size of the value. > > Note that we are to some extent evolving how we handle dynamically > sized types like `str` and `[]`. Right now they are quite second class > (you can't impl them etc) but that will change. Nonetheless, it will > remain true that you can never have a *value* of type `str` or `[]`, > but most always use a pointer (either `~[]` or `&[]`). > > Also note that a type like `~[T]` is in fact going to be represented > not as a single pointer but rather three pointers, thanks to work by > Daniel in fact. > > > > Niko > By owned box I just mean a type you can pass to `fn foo(x: ~T) { }` rather than something that's owned and has a heap allocation. Most of the other containers (hashmap, treemap, trie, ringbuf, priority_queue) are also owned, sendable and have a destructor. In my opinion, it would be better to have stronger support for library containers and only have vector/string slices built-in to the language. Stronger support would entail generic container literals, overloading auto-slicing and a rooting API for the GC (when we get one). There are good reasons to write another vector type, such as allocator support, optimizing for small vectors or ABI compatibility with a foreign library's vector type to avoid copying between the API boundary. -------------- next part -------------- An HTML attachment was scrubbed... URL: From philippe.delrieu at free.fr Fri Nov 8 04:52:00 2013 From: philippe.delrieu at free.fr (Philippe Delrieu) Date: Fri, 08 Nov 2013 13:52:00 +0100 Subject: [rust-dev] zmq and Rust task Message-ID: <527CDE70.5090601@free.fr> I found the problem. Rust schedules task in the same thread. If I stop the thread (the recv call sleep I think), every task stop. So I read the doc and I see the spawn_sched method that start a new scheluder in a new thread. I replace the do spawn with do std::task::spawn_sched(std::task::SingleThreaded) and now it work. Philippe Delrieu From niko at alum.mit.edu Fri Nov 8 05:31:24 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Fri, 8 Nov 2013 08:31:24 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> Message-ID: <20131108133124.GB29803@Mr-Bennet> On Fri, Nov 08, 2013 at 07:39:59AM -0500, Daniel Micay wrote: > By owned box I just mean a type you can pass to `fn foo(x: ~T) { }` > rather than something that's owned and has a heap allocation. Once the DST work is done, you will be able to pass a ~[T] to a function like `fn foo(x: ~T) { }`. Niko From erick.tryzelaar at gmail.com Fri Nov 8 05:38:08 2013 From: erick.tryzelaar at gmail.com (Erick Tryzelaar) Date: Fri, 8 Nov 2013 08:38:08 -0500 Subject: [rust-dev] zmq and Rust task In-Reply-To: <527CDE70.5090601@free.fr> References: <527CDE70.5090601@free.fr> Message-ID: (I maintain the bindings and this mailing list is fine for now. Bug reports work too) Right now rust-zmq is a pretty straightforward binding of the zeromq library, and is not integrated with rust's scheduler. So it's not yet preventing the user from two tasks from deadlocking. The only safe way to deal with that is to spawn those tasks off in their own thread. The best thing would be for us to write our own zmq implementation in rust, but that'll take quite a while to write. Or perhaps there is some way we can feed the ZMQ_FD of a socket to libuv to protect against task deadlocking. On Friday, November 8, 2013, Philippe Delrieu wrote: > I found the problem. Rust schedules task in the same thread. If I stop the > thread (the recv call sleep I think), every task stop. > So I read the doc and I see the spawn_sched method that start a new > scheluder in a new thread. > > I replace the do spawn with do std::task::spawn_sched(std::task::SingleThreaded) > and now it work. > > Philippe Delrieu > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From niko at alum.mit.edu Fri Nov 8 06:52:22 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Fri, 8 Nov 2013 09:52:22 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108112424.GB23082@Mr-Bennet> Message-ID: <20131108145222.GD29803@Mr-Bennet> On Fri, Nov 08, 2013 at 06:46:37AM -0500, Daniel Micay wrote: > I don't think the need to do micro-optimizations like this is *common* > though. I honestly don't know how common or uncommon various scenarios are. All I was doing in my e-mail was highlighting scenarios where indirection is a good idea. I agree with you that, like anything else, it carries cost and should not be used universally. > It gets to the point where you're optimizing for the > characteristics of a specific allocator because they use different size > class buckets so trusting a profiler on one platform isn't enough. It can get to that point, but it can easily be the case that structures are just plain too big. As an example of *not* doing it right, consider `ast::Expr` -- this type is currently *124 bytes* big! This is for *every expression* in the compiler. (No wonder our memory use is high.) I feel pretty confident we could use more indirection in there even without having consulted the allocator bucket sizes. In any case, the bottom line is: there is no single answer, you will have to experiment. As a rule of thumb, I'd say that you should use indirection (`~`) when data is "optional" -- as in, Option or just one variant of many -- so as to reduce the size for the other case. But if the data is always present, you're *probably* better off avoiding the `~` pointer. But both rules have exceptions. Niko From lists at dhardy.name Fri Nov 8 07:47:24 2013 From: lists at dhardy.name (Diggory Hardy) Date: Fri, 08 Nov 2013 16:47:24 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: <20131108113323.GC23082@Mr-Bennet> References: <20131108113323.GC23082@Mr-Bennet> Message-ID: <8817533.0HqEL1HLOK@tph-l10036> On Friday 08 November 2013 06:33:23 Niko Matsakis wrote: > I am not sure why Daniel says that a `~str` or `~[]` is not an "owned > box". I guess he's using the term in some specific way. I consider > `~str` and `~[]` to be exactly the same as any other `~T` value in > usage and semantics. They are allocated on the same heap, moved from > place to place, and freed at the same time, etc. > > The difference between a type like `str` or `[T]` and other types is > that `str` and `[T]` are actually a series of values: `u8` bytes and > `T` values respectively. This entails a change in representation and > is also the reason that one *must* use a pointer to refer to them, > because the number of values is not known and hence the compiler can't > calculate the size of the value. > > Note that we are to some extent evolving how we handle dynamically > sized types like `str` and `[]`. Right now they are quite second class > (you can't impl them etc) but that will change. Nonetheless, it will > remain true that you can never have a *value* of type `str` or `[]`, > but most always use a pointer (either `~[]` or `&[]`). > > Also note that a type like `~[T]` is in fact going to be represented > not as a single pointer but rather three pointers, thanks to work by > Daniel in fact. What's wrong with sticking with convention here? E.g. C++'s `string` and `vector` are objects containing two or three pointers. D's arrays and `string` act the same way. Even C's dynamic arrays (`int x[]`) can be thought of the same way (if one avoids thinking of them as pointers). So why not consider `str` and `[T]` conglomerates of a fixed size containing the pointers (start, length and capacity or whatever) needed? Semantically it's the same while syntactically it's simpler. Slices will need new names of course, but I think the resulting decrease in confusion will be worth it. (D's developers tried to go the other way, with all arrays and slices being effectively copy-on-write slices, before realising that discrete array/slices types _were_ needed.) DH -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 490 bytes Desc: This is a digitally signed message part. URL: From gaetan at xeberon.net Fri Nov 8 07:50:48 2013 From: gaetan at xeberon.net (Gaetan) Date: Fri, 8 Nov 2013 16:50:48 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: <8817533.0HqEL1HLOK@tph-l10036> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> Message-ID: I agree ----- Gaetan 2013/11/8 Diggory Hardy > On Friday 08 November 2013 06:33:23 Niko Matsakis wrote: > > I am not sure why Daniel says that a `~str` or `~[]` is not an "owned > > box". I guess he's using the term in some specific way. I consider > > `~str` and `~[]` to be exactly the same as any other `~T` value in > > usage and semantics. They are allocated on the same heap, moved from > > place to place, and freed at the same time, etc. > > > > The difference between a type like `str` or `[T]` and other types is > > that `str` and `[T]` are actually a series of values: `u8` bytes and > > `T` values respectively. This entails a change in representation and > > is also the reason that one *must* use a pointer to refer to them, > > because the number of values is not known and hence the compiler can't > > calculate the size of the value. > > > > Note that we are to some extent evolving how we handle dynamically > > sized types like `str` and `[]`. Right now they are quite second class > > (you can't impl them etc) but that will change. Nonetheless, it will > > remain true that you can never have a *value* of type `str` or `[]`, > > but most always use a pointer (either `~[]` or `&[]`). > > > > Also note that a type like `~[T]` is in fact going to be represented > > not as a single pointer but rather three pointers, thanks to work by > > Daniel in fact. > > What's wrong with sticking with convention here? E.g. C++'s `string` and > `vector` are objects containing two or three pointers. D's arrays and > `string` act the same way. Even C's dynamic arrays (`int x[]`) can be > thought > of the same way (if one avoids thinking of them as pointers). > > So why not consider `str` and `[T]` conglomerates of a fixed size > containing > the pointers (start, length and capacity or whatever) needed? Semantically > it's the same while syntactically it's simpler. > > Slices will need new names of course, but I think the resulting decrease in > confusion will be worth it. (D's developers tried to go the other way, with > all arrays and slices being effectively copy-on-write slices, before > realising > that discrete array/slices types _were_ needed.) > > DH > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From igor at mir2.org Fri Nov 8 08:47:28 2013 From: igor at mir2.org (Igor Bukanov) Date: Fri, 8 Nov 2013 17:47:28 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: <8817533.0HqEL1HLOK@tph-l10036> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> Message-ID: > C++'s `string` and `vector` are objects containing two or three pointers. For that one pays performance penalty in C++ as string and vector instances are passed by references resulting in double indirection when accessing the elements. I suppose it could help to think about strings in Rust similar to variable-sized structs in C like: struct MyString { unsigned int bytelength; unsigned int data[]; }; As in Rust such struct cannot be instantiated and one typically uses malloc/alloca to allocate instances and then just pass around the resulting pointers. From denis.spir at gmail.com Fri Nov 8 09:26:49 2013 From: denis.spir at gmail.com (spir) Date: Fri, 08 Nov 2013 18:26:49 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> Message-ID: <527D1ED9.8000008@gmail.com> On 11/08/2013 05:47 PM, Igor Bukanov wrote: >> C++'s `string` and `vector` are objects containing two or three pointers. > > For that one pays performance penalty in C++ as string and vector > instances are passed by references resulting in double indirection > when accessing the elements. I suppose it could help to think about > strings in Rust similar to variable-sized structs in C like: > > struct MyString { > unsigned int bytelength; > unsigned int data[]; > }; > > As in Rust such struct cannot be instantiated and one typically uses > malloc/alloca to allocate instances and then just pass around the > resulting pointers. I like this version precisely for the reason it avoids double indirection. I use it whenever I need "weighted strings" in C (strings that know their weight, Pascal strings in fact) [1]. It works fine, is easy on the implementation side, just terribly annoying w/o syntactic support. Same for arrays, both fixed (but variable, in the sense of not predefined) and dynamic size. It's all fine in my view for a language like Rust, provided it remains an implementation choice. Meaning, whether the representation of say a static array is a {p, n} struct or such a variable-sized structs is transparent on the language side. What are the present implementations of strings and arrays in Rust? And what about fixed size (esp for strings)? Denis [1] Actually, I rather just use a pointer, with the size written before the first string byte or array item, like true Pascal strings, but the result is the same. From pcwalton at mozilla.com Fri Nov 8 09:29:37 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 09:29:37 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: <8817533.0HqEL1HLOK@tph-l10036> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> Message-ID: <527D1F81.4030503@mozilla.com> On 11/8/13 7:47 AM, Diggory Hardy wrote: > What's wrong with sticking with convention here? E.g. C++'s `string` and > `vector` are objects containing two or three pointers. D's arrays and > `string` act the same way. Even C's dynamic arrays (`int x[]`) can be thought > of the same way (if one avoids thinking of them as pointers). Because: * We need slices in the language. They're important for soundness. * We need dynamically sized types in the language in order to be sound around first-class trait objects. * Given that we need slices, and we need dynamically-sized types, we can avoid introducing more concepts in the language by treating slices as just a special case of a dynamically-sized type. That is, a slice is nothing more than *a pointer to a dynamically-sized type*. * The pointer sigil is notated `&`, and the dynamically-sized type is `[int]`. So the resulting notation is `&[int]`. You can see slices as just pointers with a length attached; i.e. a pointer to multiple contiguous values. In fact, Cyclone called them "fat pointers" instead of "slices". In Cyclone, you wrote a slice as `int *fat`. (Notice the similarity to `&[int]`.) Note that not all of this is implemented today, which is leading to some of the confusion in this thread. Felix Klock is currently working on it. Patrick From pcwalton at mozilla.com Fri Nov 8 09:35:00 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 09:35:00 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: <527D1ED9.8000008@gmail.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> Message-ID: <527D20C4.3060107@mozilla.com> On 11/8/13 9:26 AM, spir wrote: > What are the present implementations of strings and arrays in Rust? And > what about fixed size (esp for strings)? struct RustString { int size; int cap; char ptr[] }; typedef *RustString ~str; (If `~` were a valid identifier character in C, that is.) ;) But Daniel did some performance measurements and found that this had suboptimal performance characteristics when compared to: struct ~str { char *ptr; int size; int cap; } So we're changing to the latter. By the way, I agree with Daniel that in an ideal world none of this would be baked into the compiler (except syntactically), and I would like to take steps to move to that world post Rust 1.0. However, given that we have dynamically sized types and as a result we have to define `~str` to mean *something*, we have to build in some representation into the compiler. Patrick From ben.striegel at gmail.com Fri Nov 8 09:38:07 2013 From: ben.striegel at gmail.com (Benjamin Striegel) Date: Fri, 8 Nov 2013 12:38:07 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: <527D20C4.3060107@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> Message-ID: > I would like to take steps to move to that world post Rust 1.0. I'd be interested to read more about this, and the reasons why it must be deferred until after 1.0. Is it just "too much work to do right now", or does it require some broader ambitious feature (HKT, etc)? On Fri, Nov 8, 2013 at 12:35 PM, Patrick Walton wrote: > On 11/8/13 9:26 AM, spir wrote: > >> What are the present implementations of strings and arrays in Rust? And >> what about fixed size (esp for strings)? >> > > struct RustString { > int size; > int cap; > char ptr[] > }; > > typedef *RustString ~str; > > (If `~` were a valid identifier character in C, that is.) ;) > > But Daniel did some performance measurements and found that this had > suboptimal performance characteristics when compared to: > > struct ~str { > char *ptr; > int size; > int cap; > } > > So we're changing to the latter. > > By the way, I agree with Daniel that in an ideal world none of this would > be baked into the compiler (except syntactically), and I would like to take > steps to move to that world post Rust 1.0. However, given that we have > dynamically sized types and as a result we have to define `~str` to mean > *something*, we have to build in some representation into the compiler. > > Patrick > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Fri Nov 8 09:42:09 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 09:42:09 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> Message-ID: <527D2271.1010908@mozilla.com> On 11/8/13 9:38 AM, Benjamin Striegel wrote: > > I would like to take steps to move to that world post Rust 1.0. > > I'd be interested to read more about this, and the reasons why it must > be deferred until after 1.0. Is it just "too much work to do right now", > or does it require some broader ambitious feature (HKT, etc)? IIRC Niko mentioned that it requires higher kinded types. I hadn't thought too much about the precise definition of the smart pointer trait. But it's also too much work to do right now, and doesn't seem like it's going to get us into much trouble regarding backwards compatibility. Having one ultra-common smart pointer type built into the language seems rather harmless. After all, in C++ there is a default `operator new`, and having to say `new(Unique)` would be pretty annoying for the commonest type of pointer. Patrick From denis.spir at gmail.com Fri Nov 8 09:46:20 2013 From: denis.spir at gmail.com (spir) Date: Fri, 08 Nov 2013 18:46:20 +0100 Subject: [rust-dev] About owned pointer -- explicit specification In-Reply-To: References: Message-ID: <527D236C.4020409@gmail.com> On 11/08/2013 09:43 AM, Gaetan wrote: > I agree, I don't understand the syntax here. > > Look at the Url class: > > > pub struct Url { > scheme: ~str, > user: Option, > host: ~str, > port: Option<~str>, > path: ~str, > query: Query, > fragment: Option<~str> > } > > pub type Query = ~[(~str, ~str)]; > > fn split_char_first(s: &str, c: char) -> (~str, ~str) { > ... > if index+mat == len { > return (s.slice(0, index).to_owned(), ~""); > } > } > > > Isn't simpler, and easier to read, if we write it > > > pub struct Url { > scheme: str, > user: Option, > host: str, > port: Option, > path: str, > query: Query, > fragment: Option > } > > pub type Query = [(str, str)]; > > fn split_char_first(s: &str, c: char) -> (str, str) { > ... > if index+mat == len { > return (s.slice(0, index).to_owned(), ""); > } > } > > > KISS ! > > > ----- > Gaetan Sure! I'd strongly support that (exactly the changes you propose). But I thought the obligation to explicitely specify the pointer type was a side-effect of the variety of pointer "kinds" in Rust: If in Rust one is to able to choose which kind of pointer is used, then, well, we must write it down somewhere somehow, no? Some of the strings or arrays above (or more generally structured data), may be shared, referenced from other structured thingies, in which case we'd need a "non-owned" pointer (probably @). Or do I misunderstand? Somewhat related but distinct, I thought we could get rid of specifying the pointer type for function input: seems to be always &, no? Or &mut when changed inside the func, but the compiler can probably tell that; also, if the param is not changed, having &mut does not affect the semantics anyway... Or, if pointed function input is not always & / &mut, systematically, in current Rust code, could it be anyway, without exaggerated semantic constraint or efficiency loss? Still related but distinct, what other uses for & (and &mut) than function input? Denis From denis.spir at gmail.com Fri Nov 8 09:48:15 2013 From: denis.spir at gmail.com (spir) Date: Fri, 08 Nov 2013 18:48:15 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: References: Message-ID: <527D23DF.4000403@gmail.com> On 11/08/2013 09:53 AM, Daniel Micay wrote: > It couldn't be called `str`, because `&str` is a slice. Why couldn't str be slices? (eg somewhat like arrays are slices in D) Also, i don't understand literals in Rust currently. Same for static arrays. Denis From philippe.delrieu at free.fr Fri Nov 8 10:00:46 2013 From: philippe.delrieu at free.fr (Philippe Delrieu) Date: Fri, 08 Nov 2013 19:00:46 +0100 Subject: [rust-dev] zmq and Rust task In-Reply-To: References: <527CDE70.5090601@free.fr> Message-ID: <527D26CE.9020103@free.fr> Hi Erick, thanks for your reply? The spawn_sched work fine for me. You do a great job in the binding. Definitely it would be very good to have a zmq implementation in Rust but It's a lot of work and your binding seem good enough. I'll tell you if I found some problems. best Philippe Delrieu Le 08/11/2013 14:38, Erick Tryzelaar a ?crit : > (I maintain the bindings and this mailing list is fine for now. Bug > reports work too) > > Right now rust-zmq is a pretty straightforward binding of the zeromq > library, and is not integrated with rust's scheduler. So it's not yet > preventing the user from two tasks from deadlocking. The only safe way > to deal with that is to spawn those tasks off in their own thread. > > The best thing would be for us to write our own zmq implementation in > rust, but that'll take quite a while to write. Or perhaps there is > some way we can feed the ZMQ_FD of a socket to libuv to protect > against task deadlocking. > > On Friday, November 8, 2013, Philippe Delrieu wrote: > > I found the problem. Rust schedules task in the same thread. If I > stop the thread (the recv call sleep I think), every task stop. > So I read the doc and I see the spawn_sched method that start a > new scheluder in a new thread. > > I replace the do spawn with do > std::task::spawn_sched(std::task::SingleThreaded) and now it work. > > Philippe Delrieu > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pwalton at mozilla.com Fri Nov 8 10:20:07 2013 From: pwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 10:20:07 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: <527D23DF.4000403@gmail.com> References: <527D23DF.4000403@gmail.com> Message-ID: <9701bd2d-235a-4236-937c-85b8381382ad@email.android.com> Because then `str` would not be a dynamically sized type. Please read the blog posts on dynamically sized types. spir wrote: >On 11/08/2013 09:53 AM, Daniel Micay wrote: >> It couldn't be called `str`, because `&str` is a slice. > >Why couldn't str be slices? (eg somewhat like arrays are slices in D) >Also, i don't understand literals in Rust currently. Same for static >arrays. > >Denis >_______________________________________________ >Rust-dev mailing list >Rust-dev at mozilla.org >https://mail.mozilla.org/listinfo/rust-dev -- Sent from my Android phone with K-9 Mail. Please excuse my brevity. -------------- next part -------------- An HTML attachment was scrubbed... URL: From denis.spir at gmail.com Fri Nov 8 10:38:18 2013 From: denis.spir at gmail.com (spir) Date: Fri, 08 Nov 2013 19:38:18 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: <9701bd2d-235a-4236-937c-85b8381382ad@email.android.com> References: <527D23DF.4000403@gmail.com> <9701bd2d-235a-4236-937c-85b8381382ad@email.android.com> Message-ID: <527D2F9A.5060609@gmail.com> On 11/08/2013 07:20 PM, Patrick Walton wrote: > Because then `str` would not be a dynamically sized type. (I'm not convinced --yet-- strings *must* have dynamic size at all, as I never need this feature even if I do quite a lot of text processing. When generating runtime produced strings, I'd rather concat all bits at once at the very end, thus knowing the final size. No support for this is needed: one never writes into a growable string buffer, instead always concat all at once. But this may be another, distinct story. And there may be use cases I'm unaware of, even common ones.) > Please read the blog posts on dynamically sized types. All right, I'll do. PS: Except I cannot find them. Don't seem listed in the list of blog post at https://github.com/mozilla/rust/wiki/Docs Also not in the archives of your own blog at: http://pcwalton.github.io/blog/archives/ Denis > spir wrote: >> On 11/08/2013 09:53 AM, Daniel Micay wrote: >>> It couldn't be called `str`, because `&str` is a slice. >> >> Why couldn't str be slices? (eg somewhat like arrays are slices in D) >> Also, i don't understand literals in Rust currently. Same for static >> arrays. >> >> Denis >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > From igor at mir2.org Fri Nov 8 10:50:01 2013 From: igor at mir2.org (Igor Bukanov) Date: Fri, 8 Nov 2013 19:50:01 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: <527D20C4.3060107@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> Message-ID: On 8 November 2013 18:35, Patrick Walton wrote: > But Daniel did some performance measurements and found that this had > suboptimal performance characteristics when compared to: > > struct ~str { > char *ptr; > int size; > int cap; > } > > So we're changing to the latter. Does this mean that when ~str is passed as a parameter the compiler copies 3 words and that makes things faster? From loebel.marvin at gmail.com Fri Nov 8 10:56:39 2013 From: loebel.marvin at gmail.com (=?ISO-8859-1?Q?Marvin_L=F6bel?=) Date: Fri, 08 Nov 2013 19:56:39 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> Message-ID: <527D33E7.4040007@gmail.com> On 11/08/2013 07:50 PM, Igor Bukanov wrote: > On 8 November 2013 18:35, Patrick Walton wrote: >> But Daniel did some performance measurements and found that this had >> suboptimal performance characteristics when compared to: >> >> struct ~str { >> char *ptr; >> int size; >> int cap; >> } >> >> So we're changing to the latter. > Does this mean that when ~str is passed as a parameter the compiler > copies 3 words and that makes things faster? According to https://github.com/mozilla/rust/issues/8981, yes and yes apparently. :) You rarely pass around a ~[T] directly anyway, usually you work with slices to them, which right now consist of exactly two words. (Though that might change to three words too for unrelated consistency reasons) Other speed improvements come from the fact that empty vectors no longer allocate, and that you no longer need to dereference a pointer into heap memory to get the size of an vector. From oren at ben-kiki.org Fri Nov 8 11:33:42 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Fri, 8 Nov 2013 21:33:42 +0200 Subject: [rust-dev] About owned pointer In-Reply-To: <527D33E7.4040007@gmail.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> Message-ID: Now I'm confused; doesn't this mean str is fixed size, so the proposal to just use "str" for the 3-word struct and have ~str and &str just be the normal thing makes sense after all? On Fri, Nov 8, 2013 at 8:56 PM, Marvin L?bel wrote: > On 11/08/2013 07:50 PM, Igor Bukanov wrote: > >> On 8 November 2013 18:35, Patrick Walton wrote: >> >>> But Daniel did some performance measurements and found that this had >>> suboptimal performance characteristics when compared to: >>> >>> struct ~str { >>> char *ptr; >>> int size; >>> int cap; >>> } >>> >>> So we're changing to the latter. >>> >> Does this mean that when ~str is passed as a parameter the compiler >> copies 3 words and that makes things faster? >> > According to https://github.com/mozilla/rust/issues/8981, yes and yes > apparently. :) > > You rarely pass around a ~[T] directly anyway, usually you work with > slices to them, which right now consist of exactly two words. (Though that > might change to three words too for unrelated consistency reasons) > > Other speed improvements come from the fact that empty vectors no longer > allocate, and that you no longer need to dereference a pointer into heap > memory to get the size of an vector. > > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From alex at crichton.co Fri Nov 8 11:36:32 2013 From: alex at crichton.co (Alex Crichton) Date: Fri, 8 Nov 2013 11:36:32 -0800 Subject: [rust-dev] Access error for trait implemtation in multiple file In-Reply-To: <527CD5FF.60304@free.fr> References: <527C97E2.9020904@free.fr> <527CD5FF.60304@free.fr> Message-ID: I would recommend reading about Rust's module system at http://static.rust-lang.org/doc/master/tutorial.html#crates-and-the-module-system to get more familiar with how things work. You may also want to read about how import statements work at http://static.rust-lang.org/doc/master/rust.html#use-declarations to get an idea of how to bring these names into scope. In rust's module system, you don't really load modules per-se, but rather insert them at certain points in the namespace hierarchy. It's perfectly valid to insert the same module at multiple locations in the hierarchy, but I agree that this may not always have the expected behavior. This probably warrants a lint mode for this which is warn by default about inserting the same file into the module hierarchy twice, On Fri, Nov 8, 2013 at 4:15 AM, Philippe Delrieu wrote: > hanks for your fast answer. > I've made some test and if I remove mod actions; in testaction.rs I have the > error: unresolved name impl actions::Action for TestAction in testaction.rs > If I remove the mod actions; and keep the mod testaction; in the test.rs I > have unresolved name in the line let actelm: ~actions::Action = element as > ~actions::Action; for actions::Action. > > I don't see what to do!! > > I didn't fully understand the module management but even if I made something > wrong rustc in my opinion shouldn't load the same module twice and if a > module is load once it should use it for all. It make me think about > I#ifndef in C. > > Philippe Delrieu > > > Le 08/11/2013 09:53, Alex Crichton a ?crit : >> >> You should be careful to declare modules only once. It looks like you >> >> have two instances of "mod actions" in the module hierarchy, and both >> modules will be compiled as separate entities (although everything >> will have the same name). >> >> If you remove the `mod actions` inside of testaction.rs you should >> start making some more progress. You'll probably hit some name >> resolution issues, but just be sure to import the previous declaration >> of the `actions` module in the top level of the crate. >> >> On Thu, Nov 7, 2013 at 11:50 PM, Philippe Delrieu >> wrote: >>> >>> Hello, rust addict. >>> >>> I have a problem with rustc. I have 3 files. >>> The first one actions.rs contains a trait declaration : >>> >>> pub trait Action { >>> // process the action on server side. >>> fn process(&self) -> ~str; >>> } >>> >>> The second contains a trait implementation testaction.rs: >>> mod actions; >>> >>> >>> pub struct TestAction { >>> actiontype: uint >>> } >>> >>> impl actions::Action for TestAction { >>> >>> fn process(&self) -> ~str { >>> ~"" >>> } >>> } >>> The third test the trait cast : >>> mod actions; >>> mod midi; >>> >>> let element : ~testaction::TestAction = >>> ~testaction::TestAction{actiontype:1}; >>> let actelm: ~actions::Action = element as >>> ~actions::Action; >>> //error here >>> println("process element :" + actelm.process()); >>> => generate error: failed to find an implementation of trait >>> >>> let actelm: ~testaction::actions::Action = element as >>> ~testaction::actions::Action; //error here >>> println("process element :" + actelm.process()); >>> => generate error: trait `Action` is inaccessible >>> >>> If I put testaction content in the test file rustc compile. >>> >>> Any idea? >>> >>> Philippe Delrieu >>> >>> >>> _______________________________________________ >>> 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 From ben.striegel at gmail.com Fri Nov 8 12:39:44 2013 From: ben.striegel at gmail.com (Benjamin Striegel) Date: Fri, 8 Nov 2013 15:39:44 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: <527D2F9A.5060609@gmail.com> References: <527D23DF.4000403@gmail.com> <9701bd2d-235a-4236-937c-85b8381382ad@email.android.com> <527D2F9A.5060609@gmail.com> Message-ID: > Except I cannot find them. The dynamically-sized type posts are sort of scattered all over Niko's blog. You can start here: http://smallcultfollowing.com/babysteps/blog/2013/04/30/dynamically-sized-types/ for a general overview. On Fri, Nov 8, 2013 at 1:38 PM, spir wrote: > On 11/08/2013 07:20 PM, Patrick Walton wrote: > >> Because then `str` would not be a dynamically sized type. >> > > (I'm not convinced --yet-- strings *must* have dynamic size at all, as I > never need this feature even if I do quite a lot of text processing. When > generating runtime produced strings, I'd rather concat all bits at once at > the very end, thus knowing the final size. No support for this is needed: > one never writes into a growable string buffer, instead always concat all > at once. But this may be another, distinct story. And there may be use > cases I'm unaware of, even common ones.) > > > Please read the blog posts on dynamically sized types. >> > > All right, I'll do. > PS: Except I cannot find them. > Don't seem listed in the list of blog post at https://github.com/mozilla/ > rust/wiki/Docs > Also not in the archives of your own blog at: http://pcwalton.github.io/ > blog/archives/ > > Denis > > spir wrote: >> >>> On 11/08/2013 09:53 AM, Daniel Micay wrote: >>> >>>> It couldn't be called `str`, because `&str` is a slice. >>>> >>> >>> Why couldn't str be slices? (eg somewhat like arrays are slices in D) >>> Also, i don't understand literals in Rust currently. Same for static >>> arrays. >>> >>> Denis >>> _______________________________________________ >>> >>> 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: From philippe.delrieu at free.fr Fri Nov 8 12:50:48 2013 From: philippe.delrieu at free.fr (Philippe Delrieu) Date: Fri, 08 Nov 2013 21:50:48 +0100 Subject: [rust-dev] Access error for trait implemtation in multiple file In-Reply-To: References: <527C97E2.9020904@free.fr> <527CD5FF.60304@free.fr> Message-ID: <527D4EA8.40400@free.fr> I solve my problem by using absolute path every where. It's ok but I can't use the source file in another program with another root module. Philippe Delrieu I've read the tutorial Le 08/11/2013 20:36, Alex Crichton a ?crit : > I would recommend reading about Rust's module system at > http://static.rust-lang.org/doc/master/tutorial.html#crates-and-the-module-system > to get more familiar with how things work. > > You may also want to read about how import statements work at > http://static.rust-lang.org/doc/master/rust.html#use-declarations to > get an idea of how to bring these names into scope. > > In rust's module system, you don't really load modules per-se, but > rather insert them at certain points in the namespace hierarchy. It's > perfectly valid to insert the same module at multiple locations in the > hierarchy, but I agree that this may not always have the expected > behavior. This probably warrants a lint mode for this which is warn by > default about inserting the same file into the module hierarchy twice, > From pcwalton at mozilla.com Fri Nov 8 13:22:22 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 13:22:22 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> Message-ID: <527D560E.5030807@mozilla.com> On 11/8/13 11:33 AM, Oren Ben-Kiki wrote: > Now I'm confused; doesn't this mean str is fixed size, so the proposal > to just use "str" for the 3-word struct and have ~str and &str just be > the normal thing makes sense after all? No, `str` is not fixed-size. An *owned pointer* to a string is fixed-size (as all pointers are), but the string *itself* is dynamically sized. The size of pointers changes based on the kind of thing they point to. Patrick From oren at ben-kiki.org Fri Nov 8 14:00:12 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Sat, 9 Nov 2013 00:00:12 +0200 Subject: [rust-dev] About owned pointer In-Reply-To: <527D560E.5030807@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> Message-ID: So, the core question is whether we think of str as an object or as a pointer. Either we see it as an object (with fixed size, 3 words), which internally holds a nested pointer to a dynamically-sized region of characters; or we see it as a direct smart pointer to this array. The "physics" of str seem to be the former, but the abstraction presented to the programmer is the latter. Of course, there's also value in providing clean abstractions, but this is a leaky one. For example, it isn't very clean to have a concrete type T which allows ~T, &T, @T, *T but forbids having a simple T (unless one is talking about a trait, which str isn't). It is weird and causes all sort of edge cases when trying to write generic code. Also, str != ~[u8] (for good reason). The internal array is hidden anyway, so pretending to be a smart pointer to it doesn't make a lot of sense to me. Of course there's a very related issue of whether we see a vector as a smart pointer or as an object, so even if str was == ~[u8] it would probably still make sense to view it as an object :-) In general, in a system language, one wants the low-level abstractions (such as "str") to be close to the "physics", so people would be able to easily reason about the code behavior. This would also lend support to the proposal of seeing str as a struct and not as a pointer. On Fri, Nov 8, 2013 at 11:22 PM, Patrick Walton wrote: > On 11/8/13 11:33 AM, Oren Ben-Kiki wrote: > >> Now I'm confused; doesn't this mean str is fixed size, so the proposal >> to just use "str" for the 3-word struct and have ~str and &str just be >> the normal thing makes sense after all? >> > > No, `str` is not fixed-size. An *owned pointer* to a string is fixed-size > (as all pointers are), but the string *itself* is dynamically sized. > > The size of pointers changes based on the kind of thing they point to. > > Patrick > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Fri Nov 8 14:04:45 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 14:04:45 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> Message-ID: <527D5FFD.8070008@mozilla.com> On 11/8/13 2:00 PM, Oren Ben-Kiki wrote: > So, the core question is whether we think of str as an object or as a > pointer. Either we see it as an object (with fixed size, 3 words), which > internally holds a nested pointer to a dynamically-sized region of > characters; or we see it as a direct smart pointer to this array. > > The "physics" of str seem to be the former, but the abstraction > presented to the programmer is the latter. Of course, there's also value > in providing clean abstractions, but this is a leaky one. For example, > it isn't very clean to have a concrete type T which allows ~T, &T, @T, > *T but forbids having a simple T (unless one is talking about a trait, > which str isn't). It is weird and causes all sort of edge cases when > trying to write generic code. You're arguing that we shouldn't have dynamically sized types, but I ask what your solution to `~Trait` is then. Patrick From pcwalton at mozilla.com Fri Nov 8 14:06:58 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 14:06:58 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> Message-ID: <527D6082.7030507@mozilla.com> On 11/8/13 2:00 PM, Oren Ben-Kiki wrote: > Also, str != ~[u8] (for good reason). The internal array is hidden > anyway, so pretending to be a smart pointer to it doesn't make a lot of > sense to me. Of course there's a very related issue of whether we see a > vector as a smart pointer or as an object, so even if str was == ~[u8] > it would probably still make sense to view it as an object :-) No! Read the thread! You need `&str and `&'static str` for performance as well as `~str`. Patrick From oren at ben-kiki.org Fri Nov 8 14:08:34 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Sat, 9 Nov 2013 00:08:34 +0200 Subject: [rust-dev] About owned pointer In-Reply-To: <527D5FFD.8070008@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D5FFD.8070008@mozilla.com> Message-ID: I don't follow. ~Trait is a pointer, and therefore its size is fixed. There are checks in place to prevent using a trait as a type (there's a nice error message from the compiler saying "using trait as a type" :-)... So the Trait in ~Trait isn't a _type_, right? :-) On Sat, Nov 9, 2013 at 12:04 AM, Patrick Walton wrote: > On 11/8/13 2:00 PM, Oren Ben-Kiki wrote: > >> So, the core question is whether we think of str as an object or as a >> pointer. Either we see it as an object (with fixed size, 3 words), which >> internally holds a nested pointer to a dynamically-sized region of >> characters; or we see it as a direct smart pointer to this array. >> >> The "physics" of str seem to be the former, but the abstraction >> presented to the programmer is the latter. Of course, there's also value >> in providing clean abstractions, but this is a leaky one. For example, >> it isn't very clean to have a concrete type T which allows ~T, &T, @T, >> *T but forbids having a simple T (unless one is talking about a trait, >> which str isn't). It is weird and causes all sort of edge cases when >> trying to write generic code. >> > > You're arguing that we shouldn't have dynamically sized types, but I ask > what your solution to `~Trait` is then. > > Patrick > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Fri Nov 8 14:09:39 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 14:09:39 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D5FFD.8070008@mozilla.com> Message-ID: <527D6123.4040501@mozilla.com> On 11/8/13 2:08 PM, Oren Ben-Kiki wrote: > > I don't follow. ~Trait is a pointer, and therefore its size is fixed. > There are checks in place to prevent using a trait as a type (there's a > nice error message from the compiler saying "using trait as a type" > :-)... So the Trait in ~Trait isn't a _type_, right? :-) No, the `Trait` in `~Trait` is a type under the dynamically sized types proposal. It is a type, just a dynamically sized one. Patrick From oren at ben-kiki.org Fri Nov 8 14:10:22 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Sat, 9 Nov 2013 00:10:22 +0200 Subject: [rust-dev] About owned pointer In-Reply-To: <527D6082.7030507@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> Message-ID: Yes, the down side is another level of indirection. This could be optimized away for &'static str, but not for &str. Good point. On Sat, Nov 9, 2013 at 12:06 AM, Patrick Walton wrote: > On 11/8/13 2:00 PM, Oren Ben-Kiki wrote: > >> Also, str != ~[u8] (for good reason). The internal array is hidden >> anyway, so pretending to be a smart pointer to it doesn't make a lot of >> sense to me. Of course there's a very related issue of whether we see a >> vector as a smart pointer or as an object, so even if str was == ~[u8] >> it would probably still make sense to view it as an object :-) >> > > No! Read the thread! You need `&str and `&'static str` for performance as > well as `~str`. > > Patrick > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From oren at ben-kiki.org Fri Nov 8 14:12:17 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Sat, 9 Nov 2013 00:12:17 +0200 Subject: [rust-dev] About owned pointer In-Reply-To: <527D6123.4040501@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D5FFD.8070008@mozilla.com> <527D6123.4040501@mozilla.com> Message-ID: Is there a place where one can see new proposals (is it all in the issues list in github and/or here, or is there a 3rd place?) E.g. there's the whole lets-get-rid-of-@, and now is the 1st time I heard there's a "dynamically sized types" proposal... well, other than in passing in this thread, that is. On Sat, Nov 9, 2013 at 12:09 AM, Patrick Walton wrote: > On 11/8/13 2:08 PM, Oren Ben-Kiki wrote: > >> >> I don't follow. ~Trait is a pointer, and therefore its size is fixed. >> There are checks in place to prevent using a trait as a type (there's a >> nice error message from the compiler saying "using trait as a type" >> :-)... So the Trait in ~Trait isn't a _type_, right? :-) >> > > No, the `Trait` in `~Trait` is a type under the dynamically sized types > proposal. It is a type, just a dynamically sized one. > > Patrick > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From banderson at mozilla.com Fri Nov 8 14:19:30 2013 From: banderson at mozilla.com (Brian Anderson) Date: Fri, 08 Nov 2013 14:19:30 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: <527D6082.7030507@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> Message-ID: <527D6372.6060300@mozilla.com> On 11/08/2013 02:06 PM, Patrick Walton wrote: > On 11/8/13 2:00 PM, Oren Ben-Kiki wrote: >> Also, str != ~[u8] (for good reason). The internal array is hidden >> anyway, so pretending to be a smart pointer to it doesn't make a lot of >> sense to me. Of course there's a very related issue of whether we see a >> vector as a smart pointer or as an object, so even if str was == ~[u8] >> it would probably still make sense to view it as an object :-) > > No! Read the thread! You need `&str and `&'static str` for performance > as well as `~str`. This thread is has been running off the rails a bit. Let's all please take a step back. This subject is one of the most subtle areas of Rust's type system, is in flux, and a lot of our plans about it are scattered across various places and passed around through informal conversation. It's understandable that there's confusion and debate here. From pcwalton at mozilla.com Fri Nov 8 14:21:36 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 14:21:36 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> Message-ID: <527D63F0.1030004@mozilla.com> On 11/8/13 2:10 PM, Oren Ben-Kiki wrote: > Yes, the down side is another level of indirection. This could be > optimized away for &'static str, but not for &str. Good point. I apologize for snapping at you. This thread has become not particularly productive. I'm welcome to alternative suggestions, but I'd like to suggest that any proposal needs to accommodate: 1. A coherent story for smart pointers to existential types in which the size is not known (e.g. `~Trait`). 2. Accommodation for extending the language for custom smart pointers. 3. A story for vectors, including custom ones. 4. Garbage-collected vectors and strings. 5. Lifetime-bounded pointers to array slices. Array slices must not allow access outside the bounds of the slice, even if those elements are within the original array. 6. C-like levels of efficiency for vectors and arrays, without extra levels of indirection. 7. The ability to push onto a unique array if capacity is available without copying all the elements. 8. Constant strings stored in static memory, without life-before-main. 9. Memory safety. 10. Unicode safety for strings: ensuring that all strings have valid UTF-8 in them at all times. There are probably more, but that's my initial list. I know that many people don't like the fact that, syntactically, vectors and strings have a sigil in front of them, but please consider that there are many design constraints here. What works for another language may not work for Rust, because of these constraints. Note that I *am* open to other possibilities :) I don't mean to shut people down! But the design space here is very limited. Patrick From pcwalton at mozilla.com Fri Nov 8 14:27:44 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 14:27:44 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D5FFD.8070008@mozilla.com> <527D6123.4040501@mozilla.com> Message-ID: <527D6560.2050908@mozilla.com> On 11/8/13 2:12 PM, Oren Ben-Kiki wrote: > Is there a place where one can see new proposals (is it all in the > issues list in github and/or here, or is there a 3rd place?) > > E.g. there's the whole lets-get-rid-of-@, and now is the 1st time I > heard there's a "dynamically sized types" proposal... well, other than > in passing in this thread, that is. Here's the stuff we have on dynamically sized types (DSTs): https://github.com/mozilla/rust/issues/6308 http://smallcultfollowing.com/babysteps/blog/2013/04/30/dynamically-sized-types/ http://smallcultfollowing.com/babysteps/blog/2013/05/13/recurring-closures-and-dynamically-sized-types/ Notice that the representation changes discussed in Niko's initial blog post are out of date. We aren't planning to do them, since there doesn't seem to be a soundness problem with having smart pointers like like `~` having different representations depending on what they point to. Patrick From pcwalton at mozilla.com Fri Nov 8 14:32:16 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 14:32:16 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: <527D6372.6060300@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D6372.6060300@mozilla.com> Message-ID: <527D6670.7030205@mozilla.com> On 11/8/13 2:19 PM, Brian Anderson wrote: > This thread is has been running off the rails a bit. Let's all please > take a step back. This subject is one of the most subtle areas of Rust's > type system, is in flux, and a lot of our plans about it are scattered > across various places and passed around through informal conversation. > It's understandable that there's confusion and debate here. Agreed, and again, my apologies. Patrick From oren at ben-kiki.org Fri Nov 8 14:37:25 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Sat, 9 Nov 2013 00:37:25 +0200 Subject: [rust-dev] About owned pointer In-Reply-To: <527D6670.7030205@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D6372.6060300@mozilla.com> <527D6670.7030205@mozilla.com> Message-ID: No need to apologize. You are quite right, this is tricky and there's a good reason for the current design choices (perhaps there are better, but they are far from obvious). I wish I could put more time into deep thinking about this... which, of course, you can :-) On Sat, Nov 9, 2013 at 12:32 AM, Patrick Walton wrote: > On 11/8/13 2:19 PM, Brian Anderson wrote: > >> This thread is has been running off the rails a bit. Let's all please >> take a step back. This subject is one of the most subtle areas of Rust's >> type system, is in flux, and a lot of our plans about it are scattered >> across various places and passed around through informal conversation. >> It's understandable that there's confusion and debate here. >> > > Agreed, and again, my apologies. > > Patrick > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dbau.pp at gmail.com Fri Nov 8 14:43:45 2013 From: dbau.pp at gmail.com (Huon Wilson) Date: Sat, 09 Nov 2013 09:43:45 +1100 Subject: [rust-dev] About owned pointer In-Reply-To: <527D6560.2050908@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D5FFD.8070008@mozilla.com> <527D6123.4040501@mozilla.com> <527D6560.2050908@mozilla.com> Message-ID: <527D6921.3080806@gmail.com> On 09/11/13 09:27, Patrick Walton wrote: > On 11/8/13 2:12 PM, Oren Ben-Kiki wrote: >> Is there a place where one can see new proposals (is it all in the >> issues list in github and/or here, or is there a 3rd place?) >> >> E.g. there's the whole lets-get-rid-of-@, and now is the 1st time I >> heard there's a "dynamically sized types" proposal... well, other than >> in passing in this thread, that is. > > Here's the stuff we have on dynamically sized types (DSTs): > > https://github.com/mozilla/rust/issues/6308 > > http://smallcultfollowing.com/babysteps/blog/2013/04/30/dynamically-sized-types/ > > > http://smallcultfollowing.com/babysteps/blog/2013/05/13/recurring-closures-and-dynamically-sized-types/ > > > Notice that the representation changes discussed in Niko's initial > blog post are out of date. We aren't planning to do them, since there > doesn't seem to be a soundness problem with having smart pointers like > like `~` having different representations depending on what they point > to. This will make transmuting ~ to get a * (e.g., to allocate memory for storage in an Rc, with automatic clean-up by transmuting back to ~ on destruction) harder to get right, won't it? > > Patrick > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From pcwalton at mozilla.com Fri Nov 8 14:44:52 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 14:44:52 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: <527D6921.3080806@gmail.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D5FFD.8070008@mozilla.com> <527D6123.4040501@mozilla.com> <527D6560.2050908@mozilla.com> <527D6921.3080806@gmail.com> Message-ID: <527D6964.1080508@mozilla.com> On 11/8/13 2:43 PM, Huon Wilson wrote: > This will make transmuting ~ to get a * (e.g., to allocate memory for > storage in an Rc, with automatic clean-up by transmuting back to ~ on > destruction) harder to get right, won't it? You'll want a `Sized` bound, I think. Patrick From dbau.pp at gmail.com Fri Nov 8 14:46:38 2013 From: dbau.pp at gmail.com (Huon Wilson) Date: Sat, 09 Nov 2013 09:46:38 +1100 Subject: [rust-dev] About owned pointer In-Reply-To: <527D6964.1080508@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D5FFD.8070008@mozilla.com> <527D6123.4040501@mozilla.com> <527D6560.2050908@mozilla.com> <527D6921.3080806@gmail.com> <527D6964.1080508@mozilla.com> Message-ID: <527D69CE.1080301@gmail.com> On 09/11/13 09:44, Patrick Walton wrote: > On 11/8/13 2:43 PM, Huon Wilson wrote: >> This will make transmuting ~ to get a * (e.g., to allocate memory for >> storage in an Rc, with automatic clean-up by transmuting back to ~ on >> destruction) harder to get right, won't it? > > You'll want a `Sized` bound, I think. > > Patrick > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev Ah, of course. Presumably this means that `Rc` or `Rc` would require a separate code-path? Huon From pcwalton at mozilla.com Fri Nov 8 14:47:31 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 14:47:31 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: <527D69CE.1080301@gmail.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D5FFD.8070008@mozilla.com> <527D6123.4040501@mozilla.com> <527D6560.2050908@mozilla.com> <527D6921.3080806@gmail.com> <527D6964.1080508@mozilla.com> <527D69CE.1080301@gmail.com> Message-ID: <527D6A03.4010700@mozilla.com> On 11/8/13 2:46 PM, Huon Wilson wrote: > On 09/11/13 09:44, Patrick Walton wrote: >> On 11/8/13 2:43 PM, Huon Wilson wrote: >>> This will make transmuting ~ to get a * (e.g., to allocate memory for >>> storage in an Rc, with automatic clean-up by transmuting back to ~ on >>> destruction) harder to get right, won't it? >> >> You'll want a `Sized` bound, I think. >> >> Patrick >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > > Ah, of course. Presumably this means that `Rc` or `Rc` would > require a separate code-path? Right. They'll have to be separate. Maybe we'll need an `UnsizedTrait` or `UnsizedVector` trait as well... we'll have to see. Patrick From danielmicay at gmail.com Fri Nov 8 14:48:25 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Fri, 8 Nov 2013 17:48:25 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: <527D6921.3080806@gmail.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D5FFD.8070008@mozilla.com> <527D6123.4040501@mozilla.com> <527D6560.2050908@mozilla.com> <527D6921.3080806@gmail.com> Message-ID: On Fri, Nov 8, 2013 at 5:43 PM, Huon Wilson wrote: > > This will make transmuting ~ to get a * (e.g., to allocate memory for > storage in an Rc, with automatic clean-up by transmuting back to ~ on > destruction) harder to get right, won't it? > FWIW, the only reason to do that right now is to support the current managed pointer scheme. It could be replaced by a proper rooting API. Unique pointers don't support allocators, so any containers/pointers with allocator support already need to abandon managed pointer support. -------------- next part -------------- An HTML attachment was scrubbed... URL: From igor at mir2.org Fri Nov 8 15:06:51 2013 From: igor at mir2.org (Igor Bukanov) Date: Sat, 9 Nov 2013 00:06:51 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> Message-ID: On 8 November 2013 23:10, Oren Ben-Kiki wrote: > Yes, the down side is another level of indirection. This could be optimized > away for &'static str, but not for &str. Good point. The level of indirection comes from passing strings as &str, not just as a plain str. But this raises the question. For immutable values implementing &T parameter as T should not be observable from the safe code, right? If so why not to declare that &T as a parameter is not a pointer but rather a hint to use the fastest way to pass an instance of T to the function. Then one can use &str as a parameter without any performance impact due to indirection even if str itself is fixed-sized 3-word block pointing to the heap allocated data. From dbau.pp at gmail.com Fri Nov 8 15:08:38 2013 From: dbau.pp at gmail.com (Huon Wilson) Date: Sat, 09 Nov 2013 10:08:38 +1100 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> Message-ID: <527D6EF6.2080608@gmail.com> On 09/11/13 10:06, Igor Bukanov wrote: > On 8 November 2013 23:10, Oren Ben-Kiki wrote: >> Yes, the down side is another level of indirection. This could be optimized >> away for &'static str, but not for &str. Good point. > The level of indirection comes from passing strings as &str, not just > as a plain str. But this raises the question. For immutable values > implementing &T parameter as T should not be observable from the safe > code, right? If so why not to declare that &T as a parameter is not a > pointer but rather a hint to use the fastest way to pass an instance > of T to the function. Then one can use &str as a parameter without any > performance impact due to indirection even if str itself is > fixed-sized 3-word block pointing to the heap allocated data. > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev `&T` is pointer-sized but `T` isn't always. (I believe that LLVM will optimise references to pass-by-value in certain circumstances; presumably when functions are internal to a compilation unit.) Huon From pcwalton at mozilla.com Fri Nov 8 15:10:09 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 15:10:09 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> Message-ID: <527D6F51.5060507@mozilla.com> On 11/8/13 3:06 PM, Igor Bukanov wrote: > On 8 November 2013 23:10, Oren Ben-Kiki wrote: >> Yes, the down side is another level of indirection. This could be optimized >> away for &'static str, but not for &str. Good point. > > The level of indirection comes from passing strings as &str, not just > as a plain str. But this raises the question. For immutable values > implementing &T parameter as T should not be observable from the safe > code, right? If so why not to declare that &T as a parameter is not a > pointer but rather a hint to use the fastest way to pass an instance > of T to the function. Then one can use &str as a parameter without any > performance impact due to indirection even if str itself is > fixed-sized 3-word block pointing to the heap allocated data. For one, you can pass substrings as `&str`. Those can't be optimized away so easily. Patrick From danielmicay at gmail.com Fri Nov 8 15:11:45 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Fri, 8 Nov 2013 18:11:45 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> Message-ID: On Fri, Nov 8, 2013 at 6:06 PM, Igor Bukanov wrote: > On 8 November 2013 23:10, Oren Ben-Kiki wrote: > > Yes, the down side is another level of indirection. This could be > optimized > > away for &'static str, but not for &str. Good point. > > The level of indirection comes from passing strings as &str, not just > as a plain str. But this raises the question. For immutable values > implementing &T parameter as T should not be observable from the safe > code, right? If so why not to declare that &T as a parameter is not a > pointer but rather a hint to use the fastest way to pass an instance > of T to the function. Then one can use &str as a parameter without any > performance impact due to indirection even if str itself is > fixed-sized 3-word block pointing to the heap allocated data. > The only way you could avoid pointer indirection is by making the element length part of the type, like fixed-size vectors. For strings, there's not really a clearly meaningful element length (bytes? code points? graphemes?). An alternate vector/string doing small string optimization makes more sense to me. -------------- next part -------------- An HTML attachment was scrubbed... URL: From igor at mir2.org Fri Nov 8 15:13:09 2013 From: igor at mir2.org (Igor Bukanov) Date: Sat, 9 Nov 2013 00:13:09 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: <527D6EF6.2080608@gmail.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D6EF6.2080608@gmail.com> Message-ID: On 9 November 2013 00:08, Huon Wilson wrote: > `&T` is pointer-sized but `T` isn't always. If the size of &T is not known, then obviously such optimization is not applicable, The point is about &T where T is fixed-sized 1-4 word thing. > > (I believe that LLVM will optimise references to pass-by-value in certain > circumstances; presumably when functions are internal to a compilation > unit.) But what about declaring that such optimization is always valid and even require it on the level of ABI? From pcwalton at mozilla.com Fri Nov 8 15:15:05 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 15:15:05 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D6EF6.2080608@gmail.com> Message-ID: <527D7079.4080309@mozilla.com> On 11/8/13 3:13 PM, Igor Bukanov wrote: > On 9 November 2013 00:08, Huon Wilson wrote: >> `&T` is pointer-sized but `T` isn't always. > > If the size of &T is not known, then obviously such optimization is > not applicable, The point is about &T where T is fixed-sized 1-4 word > thing. > >> >> (I believe that LLVM will optimise references to pass-by-value in certain >> circumstances; presumably when functions are internal to a compilation >> unit.) > > But what about declaring that such optimization is always valid and > even require it on the level of ABI? I don't see how you can without defeating separate compilation. If I am a function: fn f(s: ~str) {} It is `f`'s responsibility to free `s` at the end. That can't be done if this optimization has been performed. Patrick From danielmicay at gmail.com Fri Nov 8 15:15:29 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Fri, 8 Nov 2013 18:15:29 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D6EF6.2080608@gmail.com> Message-ID: On Fri, Nov 8, 2013 at 6:13 PM, Igor Bukanov wrote: > On 9 November 2013 00:08, Huon Wilson wrote: > > `&T` is pointer-sized but `T` isn't always. > > If the size of &T is not known, then obviously such optimization is > not applicable, The point is about &T where T is fixed-sized 1-4 word > thing. > > > > > (I believe that LLVM will optimise references to pass-by-value in certain > > circumstances; presumably when functions are internal to a compilation > > unit.) > > But what about declaring that such optimization is always valid and > even require it on the level of ABI? If you're using dynamic linking, the call overhead makes the cost of having an extra pointer in the CPU cache irrelevant. -------------- next part -------------- An HTML attachment was scrubbed... URL: From wuyunlong at msn.com Fri Nov 8 15:31:18 2013 From: wuyunlong at msn.com (wuyunlong) Date: Sat, 9 Nov 2013 07:31:18 +0800 Subject: [rust-dev] Help: How to execute the owned method "produce_obj"? In-Reply-To: References: Message-ID: struct Pool{ produce_obj : ~fn()->T, elements : ~[T] } impl Pool{ fn new_obj(&mut self){ let obj = self. ... ;// Here ,how to execute method "produce_obj" ? self.elements.push(obj); } } -------------- next part -------------- An HTML attachment was scrubbed... URL: From oren at ben-kiki.org Fri Nov 8 15:33:23 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Sat, 9 Nov 2013 01:33:23 +0200 Subject: [rust-dev] Help: How to execute the owned method "produce_obj"? In-Reply-To: References: Message-ID: It wouldn't be self.something because it doesn't take a self argument. Try Pool::produce_obj::(...) ? Or add a self argument to it and then call it normally. On Sat, Nov 9, 2013 at 1:31 AM, wuyunlong wrote: > struct Pool{ > produce_obj : ~fn()->T, > elements : ~[T] > } > > impl Pool{ > > fn new_obj(&mut self){ > let obj = self. ... ;*// Here ,how to execute method > "produce_obj" ?* > self.elements.push(obj); > } > } > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From igor at mir2.org Fri Nov 8 15:38:17 2013 From: igor at mir2.org (Igor Bukanov) Date: Sat, 9 Nov 2013 00:38:17 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: <527D7079.4080309@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D6EF6.2080608@gmail.com> <527D7079.4080309@mozilla.com> Message-ID: On 9 November 2013 00:15, Patrick Walton wrote: > I don't see how you can without defeating separate compilation. If I am a > function: > > fn f(s: ~str) {} > > It is `f`'s responsibility to free `s` at the end. That can't be done if > this optimization has been performed. This is about only optimizing fn f(t: &T) cases. Suppose one has a custom 3-word struct with a destructor. Then with the current setup one cannot hope that &T as a parameter would be just as efficient as 3-word ~str as the compiler uses an extra indirection. So the idea is to say to the programmer: do not worry about this and always use &T as a parameter type - the compiler will optimize it using the best mode using internally pass-by-value if necessary. With such optimization in place there would be no difference between ~str and struct MyStruct {s: ~str} as both ~str and &MyStruct as a parameter generates exactly the same code. From micah at micahchalmer.net Fri Nov 8 15:44:35 2013 From: micah at micahchalmer.net (Micah Chalmer) Date: Fri, 08 Nov 2013 18:44:35 -0500 Subject: [rust-dev] Help: How to execute the owned method "produce_obj"? In-Reply-To: References: Message-ID: <27ea4d97-b71c-4394-a3c6-084a18dd5696@email.android.com> This should work: let obj = (self.produce_obj)(); -------- Original Message -------- From: Oren Ben-Kiki Sent: Fri Nov 08 18:33:23 EST 2013 To: wuyunlong Cc: "rust-dev at mozilla.org" Subject: Re: [rust-dev] Help: How to execute the owned method "produce_obj"? It wouldn't be self.something because it doesn't take a self argument. Try Pool::produce_obj::(...) ? Or add a self argument to it and then call it normally. On Sat, Nov 9, 2013 at 1:31 AM, wuyunlong wrote: > struct Pool{ > produce_obj : ~fn()->T, > elements : ~[T] > } > > impl Pool{ > > fn new_obj(&mut self){ > let obj = self. ... ;*// Here ,how to execute method > "produce_obj" ?* > self.elements.push(obj); > } > } > > > _______________________________________________ > 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: From oren at ben-kiki.org Fri Nov 8 16:59:53 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Sat, 9 Nov 2013 02:59:53 +0200 Subject: [rust-dev] State of private Message-ID: I find that in several cases I would like to have sibling modules access private members, that is, allow "foo::bar::Bar" access the private members of "foo::baz::Baz", but disallow any code in "qux::*" from accessing these members. Currently in these cases I am forced to expose as public stuff that really should be private, or merge too much code into one module. In a word, is this even possible, or is planned to be possible? I know there have been some hot debates on visibility and accessibility and modules and crates, and I don't want to re-open it :-) I just want to know what the state of affairs is. -------------- next part -------------- An HTML attachment was scrubbed... URL: From slabode at aim.com Fri Nov 8 17:57:46 2013 From: slabode at aim.com (SiegeLord) Date: Fri, 8 Nov 2013 20:57:46 -0500 (EST) Subject: [rust-dev] State of private In-Reply-To: References: Message-ID: <8D0AB0638784B86-CE8-22D7D@webmail-vm013.sysops.aol.com> > I find that in several cases I would like to have sibling modules > access private members, that is, allow "foo::bar::Bar" access the > private members of "foo::baz::Baz", but disallow any code in > "qux::*" from accessing these members. The solution to prevent qux::* from accessing privates of bar and baz is to introduce a private barrier module, and manually re-export a subset of the internal API across that barrier. It'll look sort of like this: pub mod foo { pub use self::barrier::bar::pub_bar; pub use self::barrier::baz::pub_baz; mod barrier { pub mod bar { pub fn priv_bar() {} pub fn pub_bar() { ::foo::barrier::baz::priv_baz(); } } pub mod baz { pub fn priv_baz() {} pub fn pub_baz() { ::foo::barrier::bar::priv_bar(); } } } } pub mod qux { pub fn test() { // Can't do it, as barrier is private // ::foo::barrier::bar::priv_bar; ::foo::pub_bar(); ::foo::pub_baz(); } } -SL From catamorphism at gmail.com Fri Nov 8 18:54:33 2013 From: catamorphism at gmail.com (Tim Chevalier) Date: Fri, 8 Nov 2013 18:54:33 -0800 Subject: [rust-dev] Changing roles Message-ID: Hi, Rustic individuals -- I'm going to be changing roles from paid contributor to Rust, to volunteer. My last day working at Mozilla will be a week from now, November 15. While I still intend to contribute to Rust, after the 15th I will no longer be the owner of rustpkg. I have been talking with other core team members about identifying a new owner for rustpkg so that work on it will progress, and I'm confident that we will have an arrangement in place by the time I leave. If there are rustpkg bugs you would like me to try to fix in my remaining week, please @-mention me (catamorphism) in a comment on the relevant github issue. https://etherpad.mozilla.org/Rustpkg-priorities shows my idea of the priorities. For those interested in participating in OPW, don't worry, almost nothing is changing -- I'll still be the mentor for Rust. However, Larissa Shapiro (see https://wiki.mozilla.org/GNOME_Outreach_December2013 ) will be the coordinator and will answer any general questions about applying to work on a Mozilla project through OPW. It's been truly an honor to get to work on a project like Rust as my full-time job, due in no small part to Rust's large and vibrant community of volunteers. It would already be motivating to know that my work enables the range of interesting projects that people are using Rust for. It adds another level of excitement to know that many of those people are working on Rust, and writing applications in Rust, for sheer pleasure, with no immediate external reward. I'll still be on the mailing list and IRC channel, so this isn't goodbye. If you're interested in what I'm up to next, I'll probably be keeping track of it on my blog ( http://tim.dreamwidth.org/ ). Cheers, Tim -- Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt "If you are silent about your pain, they'll kill you and say you enjoyed it." -- Zora Neale Hurston From alex at crichton.co Fri Nov 8 19:31:23 2013 From: alex at crichton.co (Alex Crichton) Date: Fri, 8 Nov 2013 19:31:23 -0800 Subject: [rust-dev] State of private In-Reply-To: References: Message-ID: > I just want to know what the state of affairs is. The current state of affairs in terms of visibility and privacy in the languages is "defined and implemented with possible bugs." What's documented in the manual/tutorial is what is intended and currently implemented in the compiler, and if there is a deviation from those semantics then that's a bug which needs to be fixed. That being said, nothing is truly set in stone until we're backwards compatible (in theory), but there's a fairly large consensus that the current set of privacy/visibility rules are what we indeed want. I would certainly be willing to talk about other concrete proposals! It gets more difficult to change what we have as time goes by, but if a new idea is lightyears better than what we currently have, it's worth knowing about at least. From banderson at mozilla.com Fri Nov 8 20:41:59 2013 From: banderson at mozilla.com (Brian Anderson) Date: Fri, 08 Nov 2013 20:41:59 -0800 Subject: [rust-dev] Changing roles In-Reply-To: References: Message-ID: <527DBD17.4090100@mozilla.com> On 11/08/2013 06:54 PM, Tim Chevalier wrote: > Hi, Rustic individuals -- > > I'm going to be changing roles from paid contributor to Rust, to > volunteer. My last day working at Mozilla will be a week from now, > November 15. > It's been a great experience working with you, Tim. You are are an amazing asset to the Rust community, and a good friend. I'll see you around. Regards, Brian From kevin at sb.org Fri Nov 8 21:36:15 2013 From: kevin at sb.org (Kevin Ballard) Date: Fri, 8 Nov 2013 21:36:15 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: <527D63F0.1030004@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D63F0.1030004@mozilla.com> Message-ID: On Nov 8, 2013, at 2:21 PM, Patrick Walton wrote: > I know that many people don't like the fact that, syntactically, vectors and strings have a sigil in front of them, but please consider that there are many design constraints here. What works for another language may not work for Rust, because of these constraints. Personally, I find it great that they have a sigil in front of them. It reminds me that they're stored in the heap. -Kevin From danielmicay at gmail.com Fri Nov 8 21:38:40 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Sat, 9 Nov 2013 00:38:40 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D63F0.1030004@mozilla.com> Message-ID: On Sat, Nov 9, 2013 at 12:36 AM, Kevin Ballard wrote: > On Nov 8, 2013, at 2:21 PM, Patrick Walton wrote: > > > I know that many people don't like the fact that, syntactically, vectors > and strings have a sigil in front of them, but please consider that there > are many design constraints here. What works for another language may not > work for Rust, because of these constraints. > > Personally, I find it great that they have a sigil in front of them. It > reminds me that they're stored in the heap. > > -Kevin Since library containers, smart pointers and other types don't have them, I don't think it's helpful in that regard. -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevin at sb.org Fri Nov 8 21:43:47 2013 From: kevin at sb.org (Kevin Ballard) Date: Fri, 8 Nov 2013 21:43:47 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D63F0.1030004@mozilla.com> Message-ID: <559DC61A-0CD3-4B74-9A6F-3B8C3A5E734E@sb.org> On Nov 8, 2013, at 9:38 PM, Daniel Micay wrote: > On Sat, Nov 9, 2013 at 12:36 AM, Kevin Ballard wrote: > On Nov 8, 2013, at 2:21 PM, Patrick Walton wrote: > > > I know that many people don't like the fact that, syntactically, vectors and strings have a sigil in front of them, but please consider that there are many design constraints here. What works for another language may not work for Rust, because of these constraints. > > Personally, I find it great that they have a sigil in front of them. It reminds me that they're stored in the heap. > > -Kevin > > Since library containers, smart pointers and other types don't have them, I don't think it's helpful in that regard. Well no, you can't assume that the absence of a sigil means the absence of heap storage. But for types that are possibly not stored on the heap, such as str (which can be &'static str) and [T] (which can be a fixed-size stack-allocated vector), the ~ is a useful distinction. -Kevin -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Fri Nov 8 22:14:44 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 22:14:44 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> Message-ID: <527DD2D4.8010109@mozilla.com> On 11/8/13 3:11 PM, Daniel Micay wrote: > The only way you could avoid pointer indirection is by making the > element length part of the type, like fixed-size vectors. For strings, > there's not really a clearly meaningful element length (bytes? code > points? graphemes?). > > An alternate vector/string doing small string optimization makes more > sense to me. I think it's worth thinking about how to allow for custom vector/string implementations in this scenario. There are a couple of directions I can see us going: 1. Keep `~[T]` as today and implement overloadable literal syntax for `SmallString`/`SmallVector`. Or: 2. Implement things like `SmallString`/`SmallVector` as custom smart pointers that know how to store elements of a vector inline. These kind of custom smart pointers would be hard-wired to particular kinds of DSTs. So, for example, we could imagine: let x: SmallVector<[int]> = new(SmallVector) [ 1, 2, 3, 4 ]; Option (2) is intriguing to me, because it allows us to possibly get away with not having literal syntax and taking advantage of DSTs to get us the benefits of custom vector/string representations. But it seems too good to be true :) There may be something I'm missing... Patrick From oren at ben-kiki.org Fri Nov 8 22:43:16 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Fri, 8 Nov 2013 22:43:16 -0800 Subject: [rust-dev] State of private In-Reply-To: References: Message-ID: Many thanks for the replies. My problem is actually in accessing private methods/members of a struct defined in a different, but "very closely related" module. It seems @ nikomatsakis is saying in the final text comment of https://github.com/mozilla/rust/issues/8215 that it is not possible to specify methods/members that are only accessible from within a small set of modules; they are either completely public, or private to a single module. Looking at the same thread, I see nobody asked about a possibility of keeping the existing rules, but also adding a "friend" keyword at the module level; that is, if a module foo says "friend mod bar", then the module bar can access any private stuff in the module foo. I'm not very enamored of the friend keyword in C++, but it seems to me that having it only in module level greatly simplifies things. Also, in a Rust context, it seems it would cut down on much of the boilerplate code needed by barrier modules (which is not to say that re-exporting isn't a very useful feature as of itself). I don't want to re-open old discussions - is this something that was considered and rejected before? -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Fri Nov 8 22:44:41 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 22:44:41 -0800 Subject: [rust-dev] State of private In-Reply-To: References: Message-ID: <527DD9D9.6030306@mozilla.com> On 11/8/13 10:43 PM, Oren Ben-Kiki wrote: > Looking at the same thread, I see nobody asked about a possibility of > keeping the existing rules, but also adding a "friend" keyword at the > module level; that is, if a module foo says "friend mod bar", then the > module bar can access any private stuff in the module foo. I'm not very > enamored of the friend keyword in C++, but it seems to me that having it > only in module level greatly simplifies things. Also, in a Rust context, > it seems it would cut down on much of the boilerplate code needed by > barrier modules (which is not to say that re-exporting isn't a very > useful feature as of itself). > > I don't want to re-open old discussions - is this something that was > considered and rejected before? Nobody has proposed it AFAIK. I personally think it's not likely to be a Rust 1.0 feature, but I wouldn't necessarily be opposed in general. Patrick From danielmicay at gmail.com Fri Nov 8 22:49:52 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Sat, 9 Nov 2013 01:49:52 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: <559DC61A-0CD3-4B74-9A6F-3B8C3A5E734E@sb.org> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D63F0.1030004@mozilla.com> <559DC61A-0CD3-4B74-9A6F-3B8C3A5E734E@sb.org> Message-ID: On Sat, Nov 9, 2013 at 12:43 AM, Kevin Ballard wrote: > > Well no, you can't assume that the absence of a sigil means the absence of > heap storage. But for types that are possibly *not* stored on the heap, > such as str (which can be &'static str) and [T] (which can be a fixed-size > stack-allocated vector), the ~ is a useful distinction. > > -Kevin > Slices are just a view into some block of memory and are truly a low-level building block without any incentive for reimplementation. Rust's built-in vector/string types lack allocator support, so alternate implementations will end up being created. There's also a need for small vectors/strings, and perhaps reference-counted slices. LLVM is a good example of a modern, performance-concious C++ project. Here are the approximate counts for the various vector types: ArrayRef: 1276 (fixed-size vectors aren't used through a C++11-style template, the number is probably 10k or 20k) std::vector: 3078 SmallVector: 5076 std::string: 3648 StringRef: 4596 SmallString: 493 C++11 also supports reference counted slices of memory via `std::shared_ptr`, but I'm unsure if LLVM uses a similar type. This would be the following set of types: * &[T] * [T, ..N] * Vec * SmallVec * &str * Str * SmallStr * RcSlice * RcMutSlice With support for allocators like the C++ standard library, it's messier since Rust lacks default type parameters: * &[T] * [T, ..N] * Vec * SmallVec * &str * Str * SmallStr * RcSlice * RcMutSlice This is what I plan on implementing for rust-core, regardless of whether I convince anyone it's a good idea for the standard library. -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Fri Nov 8 22:52:46 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 22:52:46 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D63F0.1030004@mozilla.com> <559DC61A-0CD3-4B74-9A6F-3B8C3A5E734E@sb.org> Message-ID: <527DDBBE.3090502@mozilla.com> On 11/8/13 10:49 PM, Daniel Micay wrote: > This is what I plan on implementing for rust-core, regardless of whether > I convince anyone it's a good idea for the standard library. I do think the Rust standard library should support allocators and small vector optimization, for what it's worth. Patrick From corey at octayn.net Fri Nov 8 22:55:40 2013 From: corey at octayn.net (Corey Richardson) Date: Sat, 9 Nov 2013 01:55:40 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: <527DDBBE.3090502@mozilla.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D63F0.1030004@mozilla.com> <559DC61A-0CD3-4B74-9A6F-3B8C3A5E734E@sb.org> <527DDBBE.3090502@mozilla.com> Message-ID: On Sat, Nov 9, 2013 at 1:52 AM, Patrick Walton wrote: > On 11/8/13 10:49 PM, Daniel Micay wrote: >> >> This is what I plan on implementing for rust-core, regardless of whether >> I convince anyone it's a good idea for the standard library. > > > I do think the Rust standard library should support allocators and small > vector optimization, for what it's worth. > Would you add default type parameters to the language or just use a separate type for allocator-aware containers? (The third option, have them *all* be allocator aware, makes for horrendous UI) From pcwalton at mozilla.com Fri Nov 8 22:58:21 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Fri, 08 Nov 2013 22:58:21 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D63F0.1030004@mozilla.com> <559DC61A-0CD3-4B74-9A6F-3B8C3A5E734E@sb.org> <527DDBBE.3090502@mozilla.com> Message-ID: <527DDD0D.1040306@mozilla.com> On 11/8/13 10:55 PM, Corey Richardson wrote: > Would you add default type parameters to the language or just use a > separate type for allocator-aware containers? (The third option, have > them *all* be allocator aware, makes for horrendous UI) Probably using a separate type, but I wouldn't rule out the first option. Mostly I just wanted to make it clear that allocators and small vector optimization *are* on the table for the Rust standard library. For one thing, these are important optimizations for Web browser engines, and I don't want to leave that performance on the table when we've come so far with the lifetime/borrowing system. Patrick From oren at ben-kiki.org Fri Nov 8 22:59:46 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Fri, 8 Nov 2013 22:59:46 -0800 Subject: [rust-dev] State of private In-Reply-To: <527DD9D9.6030306@mozilla.com> References: <527DD9D9.6030306@mozilla.com> Message-ID: I added https://github.com/mozilla/rust/issues/10383 in the hope that enough people would find it useful and it would end up in 1.0 after all :-) In the meanwhile, I'll have to re-think my design to see if I can package all the private members in a separate structure, or something like that. Thanks, Oren Ben-Kiki On Fri, Nov 8, 2013 at 10:44 PM, Patrick Walton wrote: > On 11/8/13 10:43 PM, Oren Ben-Kiki wrote: > >> Looking at the same thread, I see nobody asked about a possibility of >> keeping the existing rules, but also adding a "friend" keyword at the >> module level... >> > > Nobody has proposed it AFAIK. I personally think it's not likely to be a > Rust 1.0 feature, but I wouldn't necessarily be opposed in general. > > Patrick -------------- next part -------------- An HTML attachment was scrubbed... URL: From corey at octayn.net Sat Nov 9 04:21:00 2013 From: corey at octayn.net (Corey Richardson) Date: Sat, 9 Nov 2013 07:21:00 -0500 Subject: [rust-dev] These Weeks in Rust Message-ID: Welcome to a mega-*This Week in Rust*. I was swamped this past week with schoolwork, so TWiR was put off. This week's combines the past two weeks of progress. These past two weeks were fairly exciting in terms of language and library progress. The next few weeks should be even more exciting. # What's cooking on master? There were 108 PRs merged these past two weeks. ## Breaking Changes - The very long-awaited [enum discriminant size patch](https://github.com/mozilla/rust/pull/9613) has landed. This will affect FFI. Size of enum discriminant is now configurable via the `repr` attribute, and will by default shrink to the smallest needed. - The extension traits for `Reader` and `Writer` have [been transformed into default methods on their respective trait](https://github.com/mozilla/rust/pull/10079). - Non-string literals are now [disallowed](https://github.com/mozilla/rust/pull/10166) in attributes. - Type parameters are now [forbidden](https://github.com/mozilla/rust/pull/10189) on inner statics (statics inside functions). - The interface to flush stdout [has changed](https://github.com/mozilla/rust/pull/10218). It was previously unsound by allowing aliased `&mut`. - `Result`'s API has changed [quite a bit](https://github.com/mozilla/rust/pull/10119), to be more consistent with `Option`, and hopefully simpler. - Linker arguments [no longer](https://github.com/mozilla/rust/pull/10199) propagate across crates. This means that if you link to a crate, its linker arguments won't be automatically added when your crate is linked. - The memory intrinsics [have been simplified](https://github.com/mozilla/rust/pull/10251). A single intrinsic for `memcpy`/`memmove`/`memset` is now exposed, rather than one per platform. - `#[link(name = "...")]` is now [taken into account](https://github.com/mozilla/rust/pull/10260) by rustc when creating build artifacts. - `std::rt::io::file` [has been fleshed out and tweaked](https://github.com/mozilla/rust/pull/10179). In particular, it has been renamed to `std::rt::io::fs`, many previously-free functions are now associated functions on `std::rt::io::File`, and `FileInfo` has been renamed to `FileStat`. ## Other Changes - Calling variadic functions with the C FFI [is now implemented](https://github.com/mozilla/rust/pull/10064). This is a pretty sweet change. The only thing missing in our C FFI now is unions. - We [now have](https://github.com/mozilla/rust/pull/10243) octal numeric literals, for all your esoteric numeric needs! - An `Any` type [has been added](https://github.com/mozilla/rust/pull/9967), and it is now possible to retrieve the object a task failed with. Previously tasks could only fail with a string, now they can fail with anything. - A `concat!` syntax extension [has been added](https://github.com/mozilla/rust/pull/9740) for compile-time string concatenation. - Timers are [now also ports](https://github.com/mozilla/rust/pull/10083), and the creator of a timer can cancel it. - `proc` is [now sugar](https://github.com/mozilla/rust/pull/10132) for `~once fn`. - The section in the tutorial on vectors and strings [has been rewritten](https://github.com/mozilla/rust/pull/10354) for correctness with modern Rust. - A bunch of C++ has been removed and rewritten. [Thread creation](https://github.com/mozilla/rust/pull/10290), [memory regions](https://github.com/mozilla/rust/pull/10094) (used for debugging and `@`-boxes, from what I can tell), and an [unused `array_list`](https://github.com/mozilla/rust/pull/10163/files). - Bounds check failures are [now marked as a cold path](https://github.com/mozilla/rust/pull/10113), and a `cold` [function attribute](https://github.com/mozilla/rust/pull/10127) has been added. - The build system [can cross-compile to iOS now](https://github.com/mozilla/rust/pull/10203), even though Rust doesn't actually run on that platform (yet!). - `std::rand` [now implements the Gamma distribution](https://github.com/mozilla/rust/pull/10223). - Cross-crate destructor inlining [now works](https://github.com/mozilla/rust/pull/10242). - A `type_id` intrinsic [has been added](https://github.com/mozilla/rust/pull/10182). - Everything in the runtime that uses `libuv` has been [split into its own crate](https://github.com/mozilla/rust/pull/10058). This means that the runtime really is pluggable: you can implement your own event loop and so forth. ## New Contributors Welcome to our new contributors! - Brian - Carol Willing - Dirkjan Bussink - Guillaume Pinot - Gyorgy Andrasek - Joshua Yanovski - Mat Carberry - Noufal Ibrahim - Robert Irelan - Tomas Sedovic - niftynif - sh8281.kim At .85 new contributors a day, we'll soon dwarf every other language in the "awesome volunteer" category. # Weekly Meetings Last week's [meeting](https://github.com/mozilla/rust/wiki/Meeting-weekly-2013-10-29) discussed segmented stacks (spoiler: [they're not coming back](https://mail.mozilla.org/pipermail/rust-dev/2013-November/006314.html) ) and placement new (we want it, how do we want it?). This week's [meeting](https://github.com/mozilla/rust/wiki/Meeting-weekly-2013-11-05) discussed the future of libextra, more stack things, octal literals, vector representation, and temporary ("rvalue") lifetimes. # Announcements etc - **Reminder from ~~the Ministry of Truth~~ ChrisMorgan**: Rust is awesome. - Rust Sk?ne, [has an event page now](http://www.foocafe.org/event/a-friendly-introduction-to-rust). It will be December 3 at 17:30 in Foo Cafe. - [Integermingled Parameter Lists](http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/), and [take 2](http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/). - [speculate](https://github.com/haxney/speculate) - a parallel speculative execution library. - [mcchat](https://github.com/luqmana/mcchat) - a pure-Rust Minecraft chat client. From illissius at gmail.com Sat Nov 9 05:50:16 2013 From: illissius at gmail.com (=?ISO-8859-1?Q?G=E1bor_Lehel?=) Date: Sat, 9 Nov 2013 14:50:16 +0100 Subject: [rust-dev] State of private In-Reply-To: References: Message-ID: On Sat, Nov 9, 2013 at 7:43 AM, Oren Ben-Kiki wrote: > Many thanks for the replies. > > My problem is actually in accessing private methods/members of a struct > defined in a different, but "very closely related" module. It seems @ > nikomatsakis is saying in the final > text comment of https://github.com/mozilla/rust/issues/8215 that it is > not possible to specify methods/members that are only accessible from > within a small set of modules; they are either completely public, or > private to a single module. > FWIW, I think this might also be partially addressed by my earlier proposal to remove methods as a distinct concept, and just allow using dot-syntax with any function? (I have a draft of a follow-up to that thread that's been sitting there for two weeks... sigh.) It wouldn't help with struct members though, which is interesting. Maybe the import syntax could be extended to accomodate that? E.g. mod a { pub struct Point { x: int, y: int } } mod b { use a::Point; } // currently exists, import all fields mod c { use a::Point { * }; } // also import all fields mod d { use a::Point { }; } // import no fields mod e { use a::Point { x }; } // import only x, not y Then you could play similar games with struct fields as with items. -- Your ship was destroyed in a monadic eruption. -------------- next part -------------- An HTML attachment was scrubbed... URL: From denis.spir at gmail.com Sat Nov 9 05:53:00 2013 From: denis.spir at gmail.com (spir) Date: Sat, 09 Nov 2013 14:53:00 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: <559DC61A-0CD3-4B74-9A6F-3B8C3A5E734E@sb.org> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D63F0.1030004@mozilla.com> <559DC61A-0CD3-4B74-9A6F-3B8C3A5E734E@sb.org> Message-ID: <527E3E3C.3040108@gmail.com> On 11/09/2013 06:43 AM, Kevin Ballard wrote:> On Nov 8, 2013, at 9:38 PM, Daniel Micay wrote: > >> On Sat, Nov 9, 2013 at 12:36 AM, Kevin Ballard wrote: >> On Nov 8, 2013, at 2:21 PM, Patrick Walton wrote: >> >>> I know that many people don't like the fact that, syntactically, vectors and strings have a sigil in front of them, but please consider that there are many design constraints here. What works for another language may not work for Rust, because of these constraints. >> >> Personally, I find it great that they have a sigil in front of them. It reminds me that they're stored in the heap. >> >> -Kevin >> >> Since library containers, smart pointers and other types don't have them, I don't think it's helpful in that regard. > > Well no, you can't assume that the absence of a sigil means the absence of heap storage. But for types that are possibly not stored on the heap, such as str (which can be &'static str) and [T] (which can be a fixed-size stack-allocated vector), the ~ is a useful distinction. > > -Kevin Can we, then, even consider the opposite: having a sigil for static data (mainly literal strings stored in static mem, I'd say) or generally non-heap data (thus including eg static arrays stored on stack)? The advantage is that this restores coherence between all heap of heap data. I'd use '$'! (what else can this sign be good for, anyway? ;-) [But where should the sigil go? In front of the data literal, as in let stst = $"Hello, world!"; let nums = $[1,2,3]; or in front of the type, or of the id itself?] Also, is it at all possible, in the long term maybe, to consider letting the compiler choose where to store, in cases where a possible pointer is meaningless, that is it does not express a true reference (shared object, that a.x is also b.y), instead is used for technical or efficiency reasons (that memory is not elastic!, for avoiding copy, etc...)? Denis From oren at ben-kiki.org Sat Nov 9 05:55:13 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Sat, 9 Nov 2013 05:55:13 -0800 Subject: [rust-dev] State of private In-Reply-To: References: Message-ID: Well... you could consider each member as if it was implemented by accessor method, and control these "methods" even if it was an actual member; of course, also provide a the same syntax for accessing actual members and method-defined-members... but I think this is too far from the current Rust direction. A friend keyword, on the other hand, should be pretty simple to implement and is a rather minor tweak to the existing system. On Sat, Nov 9, 2013 at 5:50 AM, G?bor Lehel wrote: > > On Sat, Nov 9, 2013 at 7:43 AM, Oren Ben-Kiki wrote: > >> Many thanks for the replies. >> >> My problem is actually in accessing private methods/members of a struct >> defined in a different, but "very closely related" module. It seems @ >> nikomatsakis is saying in the final >> text comment of https://github.com/mozilla/rust/issues/8215 that it is >> not possible to specify methods/members that are only accessible from >> within a small set of modules; they are either completely public, or >> private to a single module. >> > > FWIW, I think this might also be partially addressed by my earlier > proposal to remove methods as a distinct concept, and just allow using > dot-syntax with any function? (I have a draft of a follow-up to that thread > that's been sitting there for two weeks... sigh.) > > It wouldn't help with struct members though, which is interesting. Maybe > the import syntax could be extended to accomodate that? > > E.g. > > mod a { pub struct Point { x: int, y: int } } > > mod b { use a::Point; } // currently exists, import all fields > > mod c { use a::Point { * }; } // also import all fields > > mod d { use a::Point { }; } // import no fields > > mod e { use a::Point { x }; } // import only x, not y > > Then you could play similar games with struct fields as with items. > > -- > Your ship was destroyed in a monadic eruption. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From simon80 at gmail.com Sat Nov 9 11:13:50 2013 From: simon80 at gmail.com (Simon Ruggier) Date: Sat, 9 Nov 2013 14:13:50 -0500 Subject: [rust-dev] Faster communication between tasks In-Reply-To: References: <52700CB8.8010706@mozilla.com> Message-ID: Hi all, I've tentatively come up with a design that would allow the sender to reallocate the buffer as necessary, with very little added performance cost. The sending side would bear the cost of reallocation, and there would be an extra test that receivers would have to make every time they process an item (no extra atomic operations needed). However, it may be a few weeks or more before I have a working implementation to demonstrate, so I figured it might be worthwhile to mention now that I'll be working on this. Also, I think it would be interesting to investigate doing something like the Linux kernel's deadlock detection[1], but generalized to apply to bounded queues, and implemented as a static check. I know little about this, but even so, I can see how it would be an enormous amount of work. On the other hand, I would have thought the same thing about the memory safety rules that Rust enforces. I'm hopeful that this will eventually be possible as well. [1] https://www.kernel.org/doc/Documentation/lockdep-design.txt On Wed, Oct 30, 2013 at 12:55 AM, Simon Ruggier wrote: > On Tue, Oct 29, 2013 at 3:30 PM, Brian Anderson wrote: > >> On 10/28/2013 10:02 PM, Simon Ruggier wrote: >> >> Greetings fellow Rustians! >> >> First of all, thanks for working on such a great language. I really like >> the clean syntax, increased safety, separation of data from function >> definitions, and freedom from having to declare duplicate method prototypes >> in header files. >> >> I've been working on an alternate way to communicate between tasks in >> Rust, following the same approach as the LMAX Disruptor.[1] I'm hoping to >> eventually offer a superset of the functionality in the pipes API, and >> replace them as the default communication mechanism between tasks. Just as >> with concurrency in general, my main motivation in implementing this is to >> improve performance. For more information about the disruptor approach, >> there's a lot of information linked from their home page, in a variety of >> formats. >> >> >> This is really exciting work. Thanks for pursuing it. I've been >> interested in exploring something like Disruptor in Rust. The current >> channel types in Rust are indeed slow, and fixing them is the topic of >> https://github.com/mozilla/rust/issues/8568. >> > > I'll start paying attention to that. The Morrison & Afek 2013 paper looks > like something I should read. > > >> >> >> This is my first major contribution of new functionality to an >> open-source project, so I didn't want to discuss it in advance until I had >> a working system to demonstrate. I currently have a very basic proof of >> concept that achieves almost two orders of magnitude better performance >> than the pipes API. On my hardware[2], I currently see throughput of about >> 27 million items per second when synchronizing with a double-checked wait >> condition protocol between sender and receivers, 80+ million items with no >> blocking (i.e. busy waiting), and anywhere from 240,000 to 600,000 when >> using pipes. The LMAX Disruptor library gets up to 110 million items per >> second on the same hardware (using busy waiting and yielding), so there's >> definitely still room for significant improvement. >> >> >> Those are awesome results! >> > > Thanks! When I first brought it up, it was getting about 14 million with > the busy waiting. Minimizing the number of atomic operations (even with > relaxed memory ordering) makes a big difference in performance. The 2/3 > drop in performance with the blocking wait strategy comes from merely doing > a read-modify-write operation on every send (it currently uses atomic swap, > I haven't experimented with others yet). To be fair, the only result I can > take credit for is the blocking algorithm. The other ideas are straight > from the original disruptor. > > >> I've put the code up on GitHub (I'm using rustc from master).[3] >> Currently, single and multi-stage pipelines of receivers are supported, >> while many features are missing, like multiple concurrent senders, multiple >> concurrent receivers, or mutation of the items as they pass through the >> pipeline. However, given what I have so far, now is probably the right time >> to start soliciting feedback and advice. I'm looking for review, >> suggestions/constructive criticism, and guidance about contributing this to >> the Rust codebase. >> >> >> I'm not deeply familiar with Disruptor, but I believe that it uses >> bounded queues. My general feeling thus far is that, as the general 'go-to' >> channel type, people should not be using bounded queues that block the >> sender when full because of the potential for unexpected deadlocks. I could >> be convinced otherwise though if it's just not possible to have reasonably >> fast unbounded channels. Note that I don't think it's critical for the >> general-purpose channel to be as fast as possible - it's more important to >> be convenient. >> > > Yes, it does. I'm divided on this, because unbounded queues can also lead > to memory exhaustion and added latency, but I suspect that for many use > cases, you're right. For performance critical code, I think there's > probably no argument: if a queue is too large, it starts causing latency > problems (like with bufferbloat). A queue that accepts an unlimited number > of items is like an API that doesn't let the caller know about errors. The > caller needs to know that there's a large queue, and adjust its behaviour. > Because of this, I doubt any performance-critical application would find it > truly optimal to use unbounded queues. My opinion on this is strongly > influenced by this post: > > http://mechanical-sympathy.blogspot.co.uk/2012/05/apply-back-pressure-when-overloaded.html > > For general usage, though, I need to do more research. Any application > where latency is relevant really should be designed to deal with > back-pressure from queues, but there may be some batch job style use cases > where, as you say, it isn't worth the extra effort. On the other hand, it's > relevant to think about how deadlocks occur, and decide whether or not it's > reasonable for developers to expect to be able to do those things. I'll > look into this and see what I come up with. > > If there were some general way to mitigate the deadlock issue within the > runtime, it would also solve this problem. > > As a last resort, I suspect that I could probably figure out a way to have > the sender resize the buffer when it fills, copy the elements over, and > then switch the consumers over to the larger buffer. I don't know if I > could do it without affecting the fast path on the receiver side. > > Please keep working on this. I'm excited to see your results. >> > > I appreciate the encouragement :) > > >> >> Thanks, >> Simon >> >> [1] http://lmax-exchange.github.io/disruptor/ >> [2] A 2.66GHz Intel P8800 CPU running in a Thinkpad T500 on Linux x86_64 >> [3] https://github.com/sruggier/rust-disruptor >> >> >> _______________________________________________ >> Rust-dev mailing listRust-dev at mozilla.orghttps://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: From niko at alum.mit.edu Sat Nov 9 11:31:40 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Sat, 9 Nov 2013 14:31:40 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: <527D69CE.1080301@gmail.com> References: <527D560E.5030807@mozilla.com> <527D5FFD.8070008@mozilla.com> <527D6123.4040501@mozilla.com> <527D6560.2050908@mozilla.com> <527D6921.3080806@gmail.com> <527D6964.1080508@mozilla.com> <527D69CE.1080301@gmail.com> Message-ID: <20131109193140.GB18720@Mr-Bennet> On Sat, Nov 09, 2013 at 09:46:38AM +1100, Huon Wilson wrote: > Ah, of course. Presumably this means that `Rc` or `Rc` > would require a separate code-path? I've been thinking about this somewhat. I'm not sure if this is true. And in fact while both `Trait` and `str` are "dynamically sized types", they are not comparable and must be considered separately. 1. The type `Trait` is in fact not a type at all, it's shorthand for a type that the compiler "forgot" (jargon: an "existential type"). That is, every Every instance of `Rc` in fact began its life as a `Rc` for some known `T`, and the user "cast away" (pun intended) the `T` to make an object: Rc as Rc At runtime, this kind of cast (which, as an aside, I hope will no longer have to be explicit soon, it's quite tedious) pairs up the `Rc` with a vtable. So in fact `Rc` requires no "participation" on the part of `Rc`, but we will have to figure out some niggly details like how the compiler decides what type parameters can be changed from `T` to `Trait` and so forth. 2. True dynamically sized types like `[T]` and `str` are different, because they require fat pointers in place of thin ones. Until recently I was thinking we'd just (for now anyway) prohibit `Rc` and `Gc` etc from being instantiated with a DST. However, I was thinking recently that since `Rc` and `Gc` would build on `*T`, perhaps we can just define `*[T]` and `*str` to be the same sort of fat pointers, and things will work out rather nicely once everything is monomorphized. I have to think this over, but it's a promising idea. There are some complications for `Gc<[T]>`; when one traverses a pointer to this garbage-collected box, one must be sure to carry along the length information about the vector. But this doesn't seem unsolveable. Niko From niko at alum.mit.edu Sat Nov 9 11:36:17 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Sat, 9 Nov 2013 14:36:17 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: <527D6921.3080806@gmail.com> References: <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D5FFD.8070008@mozilla.com> <527D6123.4040501@mozilla.com> <527D6560.2050908@mozilla.com> <527D6921.3080806@gmail.com> Message-ID: <20131109193617.GC18720@Mr-Bennet> On Sat, Nov 09, 2013 at 09:43:45AM +1100, Huon Wilson wrote: > This will make transmuting ~ to get a * (e.g., to allocate memory for > storage in an Rc, with automatic clean-up by transmuting back to ~ on > destruction) harder to get right, won't it? See my other e-mail about choosing a representation for `*T`. I am currently thinking that the representation of `~T`, `&T`, and `*T` should be the same for all `T`. I think this addresses a number of issues and opens up new capabilities, though it does mean an unused "capacity" word for `&[T]` and `*[T]`. See issue #10295. Anyway, I am not sure if I am making sense -- I'd say this calls for a long-winded blog post. Or more likely 2 or 3. I spent some time yesterday working out some of the details for supporting custom allocators as well as higher-kinded types, so I've got a lot to write about... Niko From denis.spir at gmail.com Sat Nov 9 13:04:40 2013 From: denis.spir at gmail.com (spir) Date: Sat, 09 Nov 2013 22:04:40 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: <20131109193617.GC18720@Mr-Bennet> References: <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D5FFD.8070008@mozilla.com> <527D6123.4040501@mozilla.com> <527D6560.2050908@mozilla.com> <527D6921.3080806@gmail.com> <20131109193617.GC18720@Mr-Bennet> Message-ID: <527EA368.6070008@gmail.com> On 11/09/2013 08:36 PM, Niko Matsakis wrote: > See my other e-mail about choosing a representation for `*T`. I am > currently thinking that the representation of `~T`, `&T`, and `*T` > should be the same for all `T`. I think this addresses a number of > issues and opens up new capabilities, though it does mean an unused > "capacity" word for `&[T]` and `*[T]`. See issue #10295. Well, you may need it in fact. When I did implement slices for a trial (more or inspired by and copying D), I used this free word as a flag (with value 0) saying that extension is not allowed: one cannot push items into or concatenate a slice. Otherwise, arrays and slices are the same kind of thing; and in my case, there was a single type, as in D, arrays just are "original" slices, slices are arrays, except one cannot extend them. The remaining issue is, as in D again, the case of an array, of which slices exist, that later gets extended: in the general case (where extension requires realloc elsewhere), this invalids slices. Reason why I ended up concluding slices should only exist for fix-size thingies; anyway it's the case in practice afaik, since slices are extensively used (and a huge efficiency gain) on strings mainly. The D design, as I see it, thus brings a low level of safety; but their goal, on this point, is not to reach a level as high as Rust aims, I guess. Would be happy to read your thoughts on such topics. Denis From danielmicay at gmail.com Sat Nov 9 14:21:00 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Sat, 9 Nov 2013 17:21:00 -0500 Subject: [rust-dev] About owned pointer In-Reply-To: <527E3E3C.3040108@gmail.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D63F0.1030004@mozilla.com> <559DC61A-0CD3-4B74-9A6F-3B8C3A5E734E@sb.org> <527E3E3C.3040108@gmail.com> Message-ID: On Sat, Nov 9, 2013 at 8:53 AM, spir wrote: > > Can we, then, even consider the opposite: having a sigil for static data > (mainly literal strings stored in static mem, I'd say) or generally > non-heap data (thus including eg static arrays stored on stack)? The > advantage is that this restores coherence between all heap of heap data. > I'd use '$'! (what else can this sign be good for, anyway? ;-) > > [But where should the sigil go? In front of the data literal, as in > let stst = $"Hello, world!"; > let nums = $[1,2,3]; > or in front of the type, or of the id itself?] > > Also, is it at all possible, in the long term maybe, to consider letting > the compiler choose where to store, in cases where a possible pointer is > meaningless, that is it does not express a true reference (shared object, > that a.x is also b.y), instead is used for technical or efficiency reasons > (that memory is not elastic!, for avoiding copy, etc...)? > > Denis All variables in Rust are stack-allocated values. A unique pointer is a pointer stored on the stack, and may be defined as a library type. -------------- next part -------------- An HTML attachment was scrubbed... URL: From matthieu.monrocq at gmail.com Sun Nov 10 04:59:52 2013 From: matthieu.monrocq at gmail.com (Matthieu Monrocq) Date: Sun, 10 Nov 2013 13:59:52 +0100 Subject: [rust-dev] Faster communication between tasks In-Reply-To: References: <52700CB8.8010706@mozilla.com> Message-ID: On Sat, Nov 9, 2013 at 8:13 PM, Simon Ruggier wrote: > Hi all, I've tentatively come up with a design that would allow the sender > to reallocate the buffer as necessary, with very little added performance > cost. The sending side would bear the cost of reallocation, and there would > be an extra test that receivers would have to make every time they process > an item (no extra atomic operations needed). However, it may be a few weeks > or more before I have a working implementation to demonstrate, so I figured > it might be worthwhile to mention now that I'll be working on this. > > Also, I think it would be interesting to investigate doing something like > the Linux kernel's deadlock detection[1], but generalized to apply to > bounded queues, and implemented as a static check. I know little about > this, but even so, I can see how it would be an enormous amount of work. On > the other hand, I would have thought the same thing about the memory safety > rules that Rust enforces. I'm hopeful that this will eventually be possible > as well. > > [1] https://www.kernel.org/doc/Documentation/lockdep-design.txt > > A static proof seems extremely difficult; it would be a significant addition to the type system, affecting the closure types (did they, or not, embedded a channel/port at creation ?). In addition, I am unsure of how transfer of closures through channels would pan out. On the other hand, dynamic detection (such as done on @ pointers for mutability), seems possible. -- Matthieu > On Wed, Oct 30, 2013 at 12:55 AM, Simon Ruggier wrote: > >> On Tue, Oct 29, 2013 at 3:30 PM, Brian Anderson wrote: >> >>> On 10/28/2013 10:02 PM, Simon Ruggier wrote: >>> >>> Greetings fellow Rustians! >>> >>> First of all, thanks for working on such a great language. I really like >>> the clean syntax, increased safety, separation of data from function >>> definitions, and freedom from having to declare duplicate method prototypes >>> in header files. >>> >>> I've been working on an alternate way to communicate between tasks in >>> Rust, following the same approach as the LMAX Disruptor.[1] I'm hoping to >>> eventually offer a superset of the functionality in the pipes API, and >>> replace them as the default communication mechanism between tasks. Just as >>> with concurrency in general, my main motivation in implementing this is to >>> improve performance. For more information about the disruptor approach, >>> there's a lot of information linked from their home page, in a variety of >>> formats. >>> >>> >>> This is really exciting work. Thanks for pursuing it. I've been >>> interested in exploring something like Disruptor in Rust. The current >>> channel types in Rust are indeed slow, and fixing them is the topic of >>> https://github.com/mozilla/rust/issues/8568. >>> >> >> I'll start paying attention to that. The Morrison & Afek 2013 paper looks >> like something I should read. >> >> >>> >>> >>> This is my first major contribution of new functionality to an >>> open-source project, so I didn't want to discuss it in advance until I had >>> a working system to demonstrate. I currently have a very basic proof of >>> concept that achieves almost two orders of magnitude better performance >>> than the pipes API. On my hardware[2], I currently see throughput of about >>> 27 million items per second when synchronizing with a double-checked wait >>> condition protocol between sender and receivers, 80+ million items with no >>> blocking (i.e. busy waiting), and anywhere from 240,000 to 600,000 when >>> using pipes. The LMAX Disruptor library gets up to 110 million items per >>> second on the same hardware (using busy waiting and yielding), so there's >>> definitely still room for significant improvement. >>> >>> >>> Those are awesome results! >>> >> >> Thanks! When I first brought it up, it was getting about 14 million with >> the busy waiting. Minimizing the number of atomic operations (even with >> relaxed memory ordering) makes a big difference in performance. The 2/3 >> drop in performance with the blocking wait strategy comes from merely doing >> a read-modify-write operation on every send (it currently uses atomic swap, >> I haven't experimented with others yet). To be fair, the only result I can >> take credit for is the blocking algorithm. The other ideas are straight >> from the original disruptor. >> >> >>> I've put the code up on GitHub (I'm using rustc from master).[3] >>> Currently, single and multi-stage pipelines of receivers are supported, >>> while many features are missing, like multiple concurrent senders, multiple >>> concurrent receivers, or mutation of the items as they pass through the >>> pipeline. However, given what I have so far, now is probably the right time >>> to start soliciting feedback and advice. I'm looking for review, >>> suggestions/constructive criticism, and guidance about contributing this to >>> the Rust codebase. >>> >>> >>> I'm not deeply familiar with Disruptor, but I believe that it uses >>> bounded queues. My general feeling thus far is that, as the general 'go-to' >>> channel type, people should not be using bounded queues that block the >>> sender when full because of the potential for unexpected deadlocks. I could >>> be convinced otherwise though if it's just not possible to have reasonably >>> fast unbounded channels. Note that I don't think it's critical for the >>> general-purpose channel to be as fast as possible - it's more important to >>> be convenient. >>> >> >> Yes, it does. I'm divided on this, because unbounded queues can also lead >> to memory exhaustion and added latency, but I suspect that for many use >> cases, you're right. For performance critical code, I think there's >> probably no argument: if a queue is too large, it starts causing latency >> problems (like with bufferbloat). A queue that accepts an unlimited number >> of items is like an API that doesn't let the caller know about errors. The >> caller needs to know that there's a large queue, and adjust its behaviour. >> Because of this, I doubt any performance-critical application would find it >> truly optimal to use unbounded queues. My opinion on this is strongly >> influenced by this post: >> >> http://mechanical-sympathy.blogspot.co.uk/2012/05/apply-back-pressure-when-overloaded.html >> >> For general usage, though, I need to do more research. Any application >> where latency is relevant really should be designed to deal with >> back-pressure from queues, but there may be some batch job style use cases >> where, as you say, it isn't worth the extra effort. On the other hand, it's >> relevant to think about how deadlocks occur, and decide whether or not it's >> reasonable for developers to expect to be able to do those things. I'll >> look into this and see what I come up with. >> >> If there were some general way to mitigate the deadlock issue within the >> runtime, it would also solve this problem. >> >> As a last resort, I suspect that I could probably figure out a way to >> have the sender resize the buffer when it fills, copy the elements over, >> and then switch the consumers over to the larger buffer. I don't know if I >> could do it without affecting the fast path on the receiver side. >> >> Please keep working on this. I'm excited to see your results. >>> >> >> I appreciate the encouragement :) >> >> >>> >>> Thanks, >>> Simon >>> >>> [1] http://lmax-exchange.github.io/disruptor/ >>> [2] A 2.66GHz Intel P8800 CPU running in a Thinkpad T500 on Linux x86_64 >>> [3] https://github.com/sruggier/rust-disruptor >>> >>> >>> _______________________________________________ >>> Rust-dev mailing listRust-dev at mozilla.orghttps://mail.mozilla.org/listinfo/rust-dev >>> >>> >>> >>> _______________________________________________ >>> 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: From lists at dhardy.name Mon Nov 11 02:02:33 2013 From: lists at dhardy.name (Diggory Hardy) Date: Mon, 11 Nov 2013 11:02:33 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: <527D1F81.4030503@mozilla.com> References: <8817533.0HqEL1HLOK@tph-l10036> <527D1F81.4030503@mozilla.com> Message-ID: <1387267.xlRjlI7P1N@tph-l10036> Thanks for the clarification. The current design actually makes sense to me after re-reading about dynamically sized types. On Friday 08 November 2013 09:29:37 Patrick Walton wrote: > On 11/8/13 7:47 AM, Diggory Hardy wrote: > > What's wrong with sticking with convention here? E.g. C++'s `string` and > > `vector` are objects containing two or three pointers. D's arrays and > > `string` act the same way. Even C's dynamic arrays (`int x[]`) can be > > thought of the same way (if one avoids thinking of them as pointers). > > Because: > > * We need slices in the language. They're important for soundness. > > * We need dynamically sized types in the language in order to be sound > around first-class trait objects. > > * Given that we need slices, and we need dynamically-sized types, we can > avoid introducing more concepts in the language by treating slices as > just a special case of a dynamically-sized type. That is, a slice is > nothing more than *a pointer to a dynamically-sized type*. > > * The pointer sigil is notated `&`, and the dynamically-sized type is > `[int]`. So the resulting notation is `&[int]`. > > You can see slices as just pointers with a length attached; i.e. a > pointer to multiple contiguous values. In fact, Cyclone called them "fat > pointers" instead of "slices". In Cyclone, you wrote a slice as `int > *fat`. (Notice the similarity to `&[int]`.) > > Note that not all of this is implemented today, which is leading to some > of the confusion in this thread. Felix Klock is currently working on it. > > Patrick > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 490 bytes Desc: This is a digitally signed message part. URL: From denis.spir at gmail.com Mon Nov 11 03:55:50 2013 From: denis.spir at gmail.com (spir) Date: Mon, 11 Nov 2013 12:55:50 +0100 Subject: [rust-dev] formats 'Standard' {} and 'Poly' {:?} Message-ID: <5280C5C6.40003@gmail.com> Hello, Well, I wonder if we could exchange those formats. Here is how they work: fn main () { struct P {i:uint, j:uint}; let (b, u, i, x, c, s, a, p) = (false, 1u, -1, -1.11, 'c', "abc", [1,2,3], P{i:1,j:2}); let z : Option = None; // Poly println!("{:?} {:?} {:?} {:?} {:?} {:?} {:?} {:?} {:?}", b, u, i, x, c, s, a, p, z); // ==> false 1u -1 -1.11 'c' "abc" [1, 2, 3] main::P{i: 1u, j: 2u} // Standard println!("{} {} {} {} {} {}", b, u, i, x, c, s); // ==> false 1 -1 -1.11 c abc } The format 'Poly" {:?}: * works for all types, including app defined, does not require trait definition or declaration * just does the right thing, telling the programmer all what is needed in an exact and complete manner (except "main::" is too much maybe) The format 'Standard' {}: * requires definition of trait 'Standard' for complex types (arrays, structs, enums), as well as its declaration for type variables * is ambiguous about chars and strings, as well integers (signed?) In other words, 'poly' gives us back the notation of data, as we (would) have noted them in code. Also, its tells us the type, if implicitely, except for the exact size of a number. This information is what we need in the general case for all kinds of feedback in program testing, diagnosis, debugging... The standard notation of data is not always the best possible form, but it always does the job and we are used to it. I guess we'll constantly use it for our own feedback. For this reason, I'd like to exchange the notations of these formats: have Poly be {} so that we are less annoyed at typing it. And call with a meaningful name, such as Notation, Literal or... Standard. I have no idea what the other format (the one currently noted {} and called Standard) is good for. I'd say it can be used as part of user output, but we already have good type-specific formats for that. Maybe this format is a polyvalent form of those specialised formats, so that we don't need to choose: then call *this one* "poly"... Also, noting this one {:?} would make sense. Denis From corey at octayn.net Mon Nov 11 03:58:39 2013 From: corey at octayn.net (Corey Richardson) Date: Mon, 11 Nov 2013 06:58:39 -0500 Subject: [rust-dev] formats 'Standard' {} and 'Poly' {:?} In-Reply-To: <5280C5C6.40003@gmail.com> References: <5280C5C6.40003@gmail.com> Message-ID: Poly uses reflection, is fairly slow, and is intended only for debugging. `{}` is used for lots of things. It's used quite novelly for HTML formatting in rustdoc. On Mon, Nov 11, 2013 at 6:55 AM, spir wrote: > Hello, > > Well, I wonder if we could exchange those formats. Here is how they work: > > fn main () { > struct P {i:uint, j:uint}; > let (b, u, i, x, c, s, a, p) = > (false, 1u, -1, -1.11, 'c', "abc", [1,2,3], P{i:1,j:2}); > let z : Option = None; > > // Poly > println!("{:?} {:?} {:?} {:?} {:?} {:?} {:?} {:?} {:?}", > b, u, i, x, c, s, a, p, z); > // ==> false 1u -1 -1.11 'c' "abc" [1, 2, 3] main::P{i: 1u, j: 2u} > > // Standard > println!("{} {} {} {} {} {}", > b, u, i, x, c, s); > // ==> false 1 -1 -1.11 c abc > } > > The format 'Poly" {:?}: > * works for all types, including app defined, does not require trait > definition or declaration > * just does the right thing, telling the programmer all what is needed > in an exact and complete manner (except "main::" is too much maybe) > > The format 'Standard' {}: > * requires definition of trait 'Standard' for complex types (arrays, > structs, enums), as well as its declaration for type variables > * is ambiguous about chars and strings, as well integers (signed?) > > In other words, 'poly' gives us back the notation of data, as we (would) > have noted them in code. Also, its tells us the type, if implicitely, except > for the exact size of a number. This information is what we need in the > general case for all kinds of feedback in program testing, diagnosis, > debugging... The standard notation of data is not always the best possible > form, but it always does the job and we are used to it. I guess we'll > constantly use it for our own feedback. > > For this reason, I'd like to exchange the notations of these formats: have > Poly be {} so that we are less annoyed at typing it. And call with a > meaningful name, such as Notation, Literal or... Standard. > > I have no idea what the other format (the one currently noted {} and called > Standard) is good for. I'd say it can be used as part of user output, but we > already have good type-specific formats for that. Maybe this format is a > polyvalent form of those specialised formats, so that we don't need to > choose: then call *this one* "poly"... Also, noting this one {:?} would make > sense. > > Denis > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From danielmicay at gmail.com Mon Nov 11 04:18:05 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Mon, 11 Nov 2013 07:18:05 -0500 Subject: [rust-dev] formats 'Standard' {} and 'Poly' {:?} In-Reply-To: <5280C5C6.40003@gmail.com> References: <5280C5C6.40003@gmail.com> Message-ID: On Mon, Nov 11, 2013 at 6:55 AM, spir wrote: > Hello, > > Well, I wonder if we could exchange those formats. Here is how they work: > > fn main () { > struct P {i:uint, j:uint}; > let (b, u, i, x, c, s, a, p) = > (false, 1u, -1, -1.11, 'c', "abc", [1,2,3], P{i:1,j:2}); > let z : Option = None; > > // Poly > println!("{:?} {:?} {:?} {:?} {:?} {:?} {:?} {:?} {:?}", > b, u, i, x, c, s, a, p, z); > // ==> false 1u -1 -1.11 'c' "abc" [1, 2, 3] main::P{i: 1u, j: 2u} > > // Standard > println!("{} {} {} {} {} {}", > b, u, i, x, c, s); > // ==> false 1 -1 -1.11 c abc > } > > The format 'Poly" {:?}: > * works for all types, including app defined, does not require trait > definition or declaration > * just does the right thing, telling the programmer all what is needed > in an exact and complete manner (except "main::" is too much maybe) > > The format 'Standard' {}: > * requires definition of trait 'Standard' for complex types (arrays, > structs, enums), as well as its declaration for type variables > * is ambiguous about chars and strings, as well integers (signed?) > > In other words, 'poly' gives us back the notation of data, as we (would) > have noted them in code. Also, its tells us the type, if implicitely, > except for the exact size of a number. This information is what we need in > the general case for all kinds of feedback in program testing, diagnosis, > debugging... The standard notation of data is not always the best possible > form, but it always does the job and we are used to it. I guess we'll > constantly use it for our own feedback. > > For this reason, I'd like to exchange the notations of these formats: have > Poly be {} so that we are less annoyed at typing it. And call with a > meaningful name, such as Notation, Literal or... Standard. > > I have no idea what the other format (the one currently noted {} and > called Standard) is good for. I'd say it can be used as part of user > output, but we already have good type-specific formats for that. Maybe this > format is a polyvalent form of those specialised formats, so that we don't > need to choose: then call *this one* "poly"... Also, noting this one {:?} > would make sense. > > Denis > The reflection-based `{:?}` doesn't follow the privacy rules, so it will never be a format with a stable output. The low-level implementation details of a type aren't a sensible format for any application to be using. I don't think `std::reflect` and `std::repr` should even be available outside of debug builds because they're a huge backwards incompatibility hazard and prevent Rust from exposing a stable ABI for a reasonable subset of the standard library. I think the following is a great example: ``` use std::hashmap::HashMap; fn main() { let mut xs = HashMap::new(); xs.insert(5, 5); println!("{:?}", xs); } ``` The output is not even usable for debugging, unless what you're debugging is the hash table implementation: ``` std::hashmap::HashMap{k0: 16592526953366606085u64, k1: 12349690536349946653u64, resize_at: 24u, size: 1u, buckets: ~[None, None, None, None, None, None, None, None, Some(std::hashmap::Bucket{hash: 10818539429618494536u, key: 5, value: 5}), None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]} ``` Any type containing a hash table or a tree is going to have totally unusable output too. It quickly becomes unusable for anything that's not a thin wrapper around primitive types. -------------- next part -------------- An HTML attachment was scrubbed... URL: From denis.spir at gmail.com Mon Nov 11 04:44:04 2013 From: denis.spir at gmail.com (spir) Date: Mon, 11 Nov 2013 13:44:04 +0100 Subject: [rust-dev] returning an item from a collection Message-ID: <5280D114.8010907@gmail.com> Hello, I am searching for the easy or standard way to return an item from a collection. Here is a fictional example showing the issue: struct Coll { items : ~[Item] } impl Coll { fn first (&self) -> Item { // this line is for comments below: let it = self.items[0]; // error return it; } } fn main () { let coll = Coll{items:~[1,2,3]}; println!("first : {:?}", coll.first()); } ==> _.rs:12:18: 12:30 error: cannot move out of dereference of & pointer _.rs:12 let it = self.items[0]; I could not find any clue in docs. Have tried several approaches, finally succeeded with the following: impl Coll { fn first (&self) -> Item { let it = self.items[0].clone(); return it; } } I find that surprising. A few questions: * What does the error *mean* ? * Is this solution the right way? * What alternatives exist, if any? * What is the difference between copy and clone? * Why does clone work and not simple copy? About the latter 2 questions, well, for me, y = x just copies x into y [1]; and clone is just a synonym of copy. Where am I wrong? That we copy should remove any pointer safety question, shouldn't it? (This consideration was my lead to find a solution.) Again, where am I wrong? The doc of the module 'clone' reads: << The Clone trait for types that cannot be "implicitly copied" In Rust, some simple types are "implicitly copyable" and when you assign them or pass them as arguments, the receiver will get a copy, leaving the original value in place. These types do not require allocation to copy and do not have finalizers (i.e. they do not contain owned boxes or implement Drop), so the compiler considers them cheap and safe to copy. For other types copies must be made explicitly, by convention implementing the Clone trait and calling the clone method. >> This is all good and makes sense for me. But then, in the first code example above, the compiler does not know anything about the "copy-ability" of Val specimens. How does it then interpret the line: let it = self.items[0]; The only way to make sense of that is to copy, isn't it? What else? Then, the language should require Val to declare the trait Clone, shouldn't it? And there should not be a need for an explicit copy via the clone method in my view... Again, what other sense but copying does the compiler assign to a simple assignment "y=x" ? Finally, is it so that for generic collections, item types must always be declared the Clone trait, else we just cannot read them? Same for generic struct fields? (If I add a field of type Item in Coll, I also cannot read it out without error.) Denis [1] shallow copy: the pointer, if x is a pointer, the "fa?ade" struct is x is such an thing, etc... From oren at ben-kiki.org Mon Nov 11 05:10:03 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Mon, 11 Nov 2013 15:10:03 +0200 Subject: [rust-dev] formats 'Standard' {} and 'Poly' {:?} In-Reply-To: References: <5280C5C6.40003@gmail.com> Message-ID: I thought the trait for `{}` was called `Default`. At any rate, I also don't understand why we need both `{}` and `{:s}`, `{:i}`, etc. There's some reason for `{:x}` (change the output base to hexadecimal), but that's about it. -------------- next part -------------- An HTML attachment was scrubbed... URL: From denis.spir at gmail.com Mon Nov 11 05:17:01 2013 From: denis.spir at gmail.com (spir) Date: Mon, 11 Nov 2013 14:17:01 +0100 Subject: [rust-dev] formats 'Standard' {} and 'Poly' {:?} In-Reply-To: References: <5280C5C6.40003@gmail.com> Message-ID: <5280D8CD.3040008@gmail.com> On 11/11/2013 01:18 PM, Daniel Micay wrote: > The reflection-based `{:?}` doesn't follow the privacy rules, so it will > never be a format with a stable output. The low-level implementation > details of a type aren't a sensible format for any application to be using. Provided it goes on doing the right thing, meaning ~ reproducing data notation, I'm happy with it. > I don't think `std::reflect` and `std::repr` should even be available > outside of debug builds because they're a huge backwards incompatibility > hazard and prevent Rust from exposing a stable ABI for a reasonable subset > of the standard library. It is for programmer feedback anyway. If 'poly' is removed, I cry. It promises to be the best and most common tool Rust provides to programmers. A way to solve that issue, preventing this format to be mis-used for app output, may be to have funcs specific for programmer feedback, which in standard use 'poly' [1]. Other writing funcs, for app output, would not normally use it. More generally, it may be a good idea to (more) clearly separate "meta" features for programmer help from app modelling features. > I think the following is a great example: > > ``` > use std::hashmap::HashMap; > > fn main() { > let mut xs = HashMap::new(); > xs.insert(5, 5); > println!("{:?}", xs); > } > ``` > > The output is not even usable for debugging, unless what you're debugging > is the hash table implementation: You are right. But the reason for a programmer to print out a hashmap should be to debig it. Else, we should ask for different or more precise data (eg, its size, or the buckets). > ``` > std::hashmap::HashMap{k0: 16592526953366606085u64, k1: > 12349690536349946653u64, resize_at: 24u, size: 1u, buckets: ~[None, None, > None, None, None, None, None, None, > Some(std::hashmap::Bucket{hash: 10818539429618494536u, key: 5, > value: 5}), None, None, None, None, None, None, None, None, None, None, > None, None, None, None, None, None, None, None, None, None, None, None, > None]} > ``` > > Any type containing a hash table or a tree is going to have totally > unusable output too. It quickly becomes unusable for anything that's not a > thin wrapper around primitive types. As said, it cannot be perfect in all cases. At times, we will need custom formats even for programmer feedback. Alternative: change the 'poly' format for hashtables. (But as it is, is looks good to me: it says what we need, and can barely be made more compact or readable.) What I would change is presenting structs (maybe arrays as well) in multiline format whenever some of their fields (items) are complex. This would give: std::hashmap::HashMap { k0: 16592526953366606085u64, k1: 12349690536349946653u64, resize_at: 24u, size: 1u, buckets: ~[None, None, None, None, None, None, None, None, Some(std::hashmap::Bucket{hash: 10818539429618494536u, key: 5, value: 5}), None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None] } Denis [1] When the language lets me do it, such a programmfeedback func is the first utility I write. I call it "note" (as they write data notation) or note* when I can have several of them. From pnkfelix at mozilla.com Mon Nov 11 05:47:27 2013 From: pnkfelix at mozilla.com (Felix Klock) Date: Mon, 11 Nov 2013 05:47:27 -0800 (PST) Subject: [rust-dev] returning an item from a collection In-Reply-To: <5280D114.8010907@gmail.com> References: <5280D114.8010907@gmail.com> Message-ID: <501973145.8294345.1384177647691.JavaMail.zimbra@mozilla.com> Denis (cc'ing rust-dev)- > How does it then interpret the line: > let it = self.items[0]; > The only way to make sense of that is to copy, isn't it? What else? An assignment expression can denote either a copy or a *move* of the right-hand-side into the left-hand-side. Note that your goal ("returning an item from a collection") is unclear, in that I cannot tell whether you want to move item out of the collection, or make a copy of it, or provide a shared reference to the item in the collection (but without removing it from the collection). Anyway, the error message says "cannot move out of dereference of & pointer" In this case, the assignment expression is being interpreted as an attempt to move content out of self.items[0]. But you cannot move the item out of the l-value denoted by that expression, for a couple different reasons (such as: `&self` is an immutable borrow, so you cannot modify it; and also, even if you changed the borrow to be a mutable borrow, you still could not use the expression you want to extract the first item, since the vector needs something to replace the content that was removed). Maybe you are more used to languages like Java/Scheme/ML/Haskell/etc, where a parameter or local variable denotes a *reference* to the value in question, and thus can be freely copied? To get that effect in Rust, and thus allow multiple references to some shared piece of state, you need to use some explicit pointer/reference type. Here is some code to illustrate what I'm saying. Note that you should probably favor a data-structure representation where you can call the vec `pop()` method rather than `shift()`; compare the source code for each in vec.rs to see why. ```rust struct Coll { items : ~[Item] } impl Coll { // *Moves* the first element out of self. // (Doing so requires that we mutably-borrow self.) fn first (&mut self) -> Item { // ^^^ this is new let it = self.items.shift(); // ^^^^^ so is this return it; } // Provides reference to first element of self. fn first_ref<'a> (&'a self) -> &'a Item { // Note: The lifetime 'a tells us that the reference will // survive only as long as the immutable-borrow of self. let it = &'a self.items[0]; return it; } } fn main () { let mut coll = Coll{items:~[1,2,3]}; // ^^^ this is also new. { // This {} block acts effectively as the lifetime 'a for the // call to first_ref. // First lets take a reference, `fref`, into coll... let fref = coll.first_ref(); println!("first ref : {:?}", fref); println!("coll : {:?}", coll); // ... which will only live until here... } // ... which is important, because we need to *mutably* // borrow `coll` in order to invoke `first()` here. println!("first : {:?}", coll.first()); println!("coll : {:?}", coll); } ``` Cheers, -Felix ----- Original Message ----- From: "spir" To: "Rust-dev" Sent: Monday, November 11, 2013 1:44:04 PM Subject: [rust-dev] returning an item from a collection Hello, I am searching for the easy or standard way to return an item from a collection. Here is a fictional example showing the issue: struct Coll { items : ~[Item] } impl Coll { fn first (&self) -> Item { // this line is for comments below: let it = self.items[0]; // error return it; } } fn main () { let coll = Coll{items:~[1,2,3]}; println!("first : {:?}", coll.first()); } ==> _.rs:12:18: 12:30 error: cannot move out of dereference of & pointer _.rs:12 let it = self.items[0]; I could not find any clue in docs. Have tried several approaches, finally succeeded with the following: impl Coll { fn first (&self) -> Item { let it = self.items[0].clone(); return it; } } I find that surprising. A few questions: * What does the error *mean* ? * Is this solution the right way? * What alternatives exist, if any? * What is the difference between copy and clone? * Why does clone work and not simple copy? About the latter 2 questions, well, for me, y = x just copies x into y [1]; and clone is just a synonym of copy. Where am I wrong? That we copy should remove any pointer safety question, shouldn't it? (This consideration was my lead to find a solution.) Again, where am I wrong? The doc of the module 'clone' reads: << The Clone trait for types that cannot be "implicitly copied" In Rust, some simple types are "implicitly copyable" and when you assign them or pass them as arguments, the receiver will get a copy, leaving the original value in place. These types do not require allocation to copy and do not have finalizers (i.e. they do not contain owned boxes or implement Drop), so the compiler considers them cheap and safe to copy. For other types copies must be made explicitly, by convention implementing the Clone trait and calling the clone method. >> This is all good and makes sense for me. But then, in the first code example above, the compiler does not know anything about the "copy-ability" of Val specimens. How does it then interpret the line: let it = self.items[0]; The only way to make sense of that is to copy, isn't it? What else? Then, the language should require Val to declare the trait Clone, shouldn't it? And there should not be a need for an explicit copy via the clone method in my view... Again, what other sense but copying does the compiler assign to a simple assignment "y=x" ? Finally, is it so that for generic collections, item types must always be declared the Clone trait, else we just cannot read them? Same for generic struct fields? (If I add a field of type Item in Coll, I also cannot read it out without error.) Denis [1] shallow copy: the pointer, if x is a pointer, the "fa?ade" struct is x is such an thing, etc... _______________________________________________ Rust-dev mailing list Rust-dev at mozilla.org https://mail.mozilla.org/listinfo/rust-dev From denis.spir at gmail.com Mon Nov 11 06:48:37 2013 From: denis.spir at gmail.com (spir) Date: Mon, 11 Nov 2013 15:48:37 +0100 Subject: [rust-dev] returning an item from a collection In-Reply-To: <501973145.8294345.1384177647691.JavaMail.zimbra@mozilla.com> References: <5280D114.8010907@gmail.com> <501973145.8294345.1384177647691.JavaMail.zimbra@mozilla.com> Message-ID: <5280EE45.7020905@gmail.com> On 11/11/2013 02:47 PM, Felix Klock wrote: > Denis (cc'ing rust-dev)- Thank you very much, Felix, for this clear and exhaustive reply. >> How does it then interpret the line: >> let it = self.items[0]; >> The only way to make sense of that is to copy, isn't it? What else? > > An assignment expression can denote either a copy or a *move* of the right-hand-side into the left-hand-side. > > Note that your goal ("returning an item from a collection") is unclear, in that I cannot tell whether you want to move item out of the collection, or make a copy of it, or provide a shared reference to the item in the collection (but without removing it from the collection). All right. Seems 'move' is to be understood quite literally, no? The datum so-to-say ceases to exist at its original place? I want to copy because (or so it seels to me) it is the standard need: we want something "equivalent". (By copy I do not mean deep copy or copy of contents or of target, for a data structure, collection, or pointer. Just the "fa?ade".) > Anyway, the error message says "cannot move out of dereference of & pointer" > > In this case, the assignment expression is being interpreted as an attempt to move content out of self.items[0]. But you cannot move the item out of the l-value denoted > by that expression, for a couple different reasons (such as: `&self` is an immutable borrow, so you cannot modify it; and also, even if you changed the borrow to be a mutable borrow, you still could not use the expression you want to extract the first item, since the vector needs something to replace the content that was removed). More or less what I understood, but thank to you clearer. > Maybe you are more used to languages like Java/Scheme/ML/Haskell/etc, where a parameter or local variable denotes a *reference* to the value in question, and thus can be freely copied? To get that effect in Rust, and thus allow multiple references to some shared piece of state, you need to use some explicit pointer/reference type. > > Here is some code to illustrate what I'm saying. Note that you should probably favor a data-structure representation where you can call the vec `pop()` method rather than `shift()`; compare the source code for each in vec.rs to see why. > > ```rust > struct Coll { > items : ~[Item] > } > > impl Coll { > // *Moves* the first element out of self. > // (Doing so requires that we mutably-borrow self.) > fn first (&mut self) -> Item { > // ^^^ this is new > > let it = self.items.shift(); > // ^^^^^ so is this > return it; > } > > // Provides reference to first element of self. > fn first_ref<'a> (&'a self) -> &'a Item { > // Note: The lifetime 'a tells us that the reference will > // survive only as long as the immutable-borrow of self. > let it = &'a self.items[0]; > return it; > } > } > > fn main () { > let mut coll = Coll{items:~[1,2,3]}; > // ^^^ this is also new. > > { > // This {} block acts effectively as the lifetime 'a for the > // call to first_ref. > > // First lets take a reference, `fref`, into coll... > let fref = coll.first_ref(); > println!("first ref : {:?}", fref); > println!("coll : {:?}", coll); > // ... which will only live until here... > } > > // ... which is important, because we need to *mutably* > // borrow `coll` in order to invoke `first()` here. > println!("first : {:?}", coll.first()); > println!("coll : {:?}", coll); > } > > ``` All right! I'll keep this code aside for whenever I need these alternatives (ref or move). I conclude that for reading or returning an item by copy, using clone is the right way to go (if the item type is a variable). Correct? Also, what does let y = x; mean in Rust if x's type is constant (as opposed to a generic type var)? Does it depend on the exact type? and specifically what happens in the case of simple, atomic, type? > Cheers, > -Felix From catamorphism at gmail.com Mon Nov 11 11:33:34 2013 From: catamorphism at gmail.com (Tim Chevalier) Date: Mon, 11 Nov 2013 11:33:34 -0800 Subject: [rust-dev] List of rustpkg packages on wiki (add your own!) Message-ID: Hi all -- I started making a list of Rust packages that build with rustpkg, on the wiki: https://github.com/mozilla/rust/wiki/Rustpkg If I left out yours, add it! (And if I included yours but shouldn't have, then remove it; I was going through RustCI and finding the ones with a lib.rs file :-) With hope, the central package database ( https://github.com/mozilla/rust/issues/10041 ) will obviate the need for this list, but in the meantime, let's maintain the list informally. Cheers, Tim -- Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt "If you are silent about your pain, they'll kill you and say you enjoyed it." -- Zora Neale Hurston From oren at ben-kiki.org Mon Nov 11 12:16:24 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Mon, 11 Nov 2013 22:16:24 +0200 Subject: [rust-dev] "Implementation Inheritance" / mixins Message-ID: I googled around and this has been asked before several times; there are answers that use obsolete syntax and Rust concepts, so I thought it might be a good idea to revisit the issue. The basic use case is having some trait, and having some (base/mixin) struct implementing it. Now, one wants to have a 2nd (derived/importing) struct implementing the trait, based on the 1st struct implementation (including its data members). I'm not certain what the idiomatic Rust answers to this common use case is, today. One can obviously simply duplicate the data members and the trait implementation, if the size of the code is small enough. This is very WET though. One can have the derived/importing class contain a member of the base/mixin struct, then delegate each and every trait function to it (providing overrides where needed). This is pretty tedious and results with a lot of boilerplate code. Performance would probably suffer. It is also difficult to override methods that are invoked by imported methods. One can write the 1st struct in a way that is intended to be overridden, e.g. by providing a trait with a "get base" accessor and using that all over the place. This makes the base struct code uglier (and, I think, less efficient), but results in less boilerplate code in the derived class. It makes overrides much trickier though. In general seems pretty restricted. One can implement a bunch of macros to automate injecting the common code into derived structs (I think - I'm not clear whether macros are allowed to add methods and members to a struct). Setting up the macros "isn't fun", especially when one wants to take overrides into account. If there another option? Which one is more "idiomatic" Rust code? There are many options that would require compiler/language support... these basically automate the above approaches. Personally I am fond of a somewhat unusual approach I first saw in Sather (I think), which was to automate the macro based approach. That is, define "implementation inheritance" (actually, "mixins") as a source-level operation. The source code of the imported/reused members from the base (mixin) struct would be (logically anyway) pasted inside the definition of the derived/importing struct, and then compiled as usual. This is very simple to define (it is basically similar to "use" - in fact, this resonates with the idea of changing the division of labor between structs and modules, but it is a separate discussion). It allows for great flexibility: one can import only specific methods and members, providing a different implementation for others; Using the ability to import something under a different name, it is possible to wrap the imported methods with additional functionality (foo { ...; renamed_imported_foo(); ... }), etc. So, this provides the functionality of "virtual functions" (an imported function calling one that is redefined - that is, not imported but implemented locally - will get the overriden behavior). At the same time, unlike "virtual functions", it still allows for aggressive optimizations (since when compiling a struct, all methods are fully known and can be inlined etc.). It sidesteps a lot of sticky issues with a vtable-sharing oriented approach (like in C++). For example, re-importing would cause multiple definitions of the same member/method. It even allows for separate compilation (if the object file contains the AST tucked in it somewhere), and for reuse of compiled methods (if they don't invoke overriden methods - but that may be tricky to implement). At any rate, I'm not claiming this is necessarily the best approach for Rust; I'm just wondering, what is the proposed way to address this use case? None of the manual approaches seems very appealing (unless there's a better one I missed). Thanks, Oren Ben-Kiki -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg at kinostudios.com Mon Nov 11 12:27:39 2013 From: greg at kinostudios.com (Greg) Date: Mon, 11 Nov 2013 15:27:39 -0500 Subject: [rust-dev] Please simplify the syntax for Great Justice Message-ID: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Dear Mozilla, rust devs, and memory-safe enthusiasts everywhere, I'm very happy with the safety improvements that Rust brings. This is true innovation. At the same time, I am disappointed and quite concerned about Rust's unimaginative syntax. It seems to preserve decades of poor decision-making from C++. The FAQ states: "The syntax is still evolving" I hope this is still true today. Syntax plays a significant role in safety: 1. Simple syntax makes software easier to write. 2. Simple syntax makes software easier to understand. 3. Simple syntax makes inserting a backdoor into an open source project more difficult. 4. Simple syntax leads to fewer mistakes. Were I to have written Rust, I would have modeled its syntax after Clojure/Lisp/Scheme instead of C++ [1]. By this point, I'm aware that this is unlikely to happen. However, I would like to ask the Rust architects to seriously consider this issue, and ask themselves what syntax they can remove from the language while maintaining type-safety. Removing syntax should not raise any fears that the language will lose any features or flexibility. To the contrary, a simpler syntax will likely lead to increased flexibility and possibilities. Lisp has demonstrated unequivocally. "Typed Clojure" may provide the authors with needed inspiration: https://github.com/clojure/core.typed/wiki https://s3.amazonaws.com/github/downloads/frenchy64/papers/ambrose-honours.pdf Kind regards, Greg [1] https://www.taoeffect.com/blog/2010/01/how-newlisp-took-my-breath-and-syntax-away/ -- Please do not email me anything that you are not comfortable also sharing with the NSA. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 495 bytes Desc: Message signed with OpenPGP using GPGMail URL: From catamorphism at gmail.com Mon Nov 11 12:33:15 2013 From: catamorphism at gmail.com (Tim Chevalier) Date: Mon, 11 Nov 2013 12:33:15 -0800 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: Hi, Greg -- At this state in Rust's development, we are unlikely to make any major changes to Rust's syntax. Literally years of effort have gone into desgining the syntax, and at this point in the language's development, our focus is on making any non-backwards-compatible changes in preparation for releasing 1.0. I encourage you to check out Rust's syntax extension / macro system: http://static.rust-lang.org/doc/master/tutorial-macros.html and explore how that can be used to extend the base syntax. Cheers, Tim On Mon, Nov 11, 2013 at 12:27 PM, Greg wrote: > Dear Mozilla, rust devs, and memory-safe enthusiasts everywhere, > > I'm very happy with the safety improvements that Rust brings. > > This is true innovation. > > At the same time, I am disappointed and quite concerned about Rust's unimaginative syntax. > > It seems to preserve decades of poor decision-making from C++. > > The FAQ states: "The syntax is still evolving" > > I hope this is still true today. Syntax plays a significant role in safety: > > 1. Simple syntax makes software easier to write. > 2. Simple syntax makes software easier to understand. > 3. Simple syntax makes inserting a backdoor into an open source project more difficult. > 4. Simple syntax leads to fewer mistakes. > > Were I to have written Rust, I would have modeled its syntax after Clojure/Lisp/Scheme instead of C++ [1]. By this point, I'm aware that this is unlikely to happen. > > However, I would like to ask the Rust architects to seriously consider this issue, and ask themselves what syntax they can remove from the language while maintaining type-safety. > > Removing syntax should not raise any fears that the language will lose any features or flexibility. > > To the contrary, a simpler syntax will likely lead to increased flexibility and possibilities. Lisp has demonstrated unequivocally. > > "Typed Clojure" may provide the authors with needed inspiration: > > https://github.com/clojure/core.typed/wiki > https://s3.amazonaws.com/github/downloads/frenchy64/papers/ambrose-honours.pdf > > Kind regards, > Greg > > [1] https://www.taoeffect.com/blog/2010/01/how-newlisp-took-my-breath-and-syntax-away/ > > -- > Please do not email me anything that you are not comfortable also sharing with the NSA. > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt "If you are silent about your pain, they'll kill you and say you enjoyed it." -- Zora Neale Hurston From gmaxwell at gmail.com Mon Nov 11 12:35:40 2013 From: gmaxwell at gmail.com (Gregory Maxwell) Date: Mon, 11 Nov 2013 12:35:40 -0800 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: On Mon, Nov 11, 2013 at 12:27 PM, Greg wrote: > Dear Mozilla, rust devs, and memory-safe enthusiasts everywhere, > > I'm very happy with the safety improvements that Rust brings. > > This is true innovation. > > At the same time, I am disappointed and quite concerned about Rust's unimaginative syntax. [...] I'm not a rust developer? so consider my comments accordingly worthless. But what you're asking for here is very non-specific. Basically you expect that I should study a number of other languages in general and then infer which specific syntactic changes you might prefer. I think thats asking a little too much. My general impression is that the time for broad bike-shedding of the whole syntactic strategy has passed, ... but regardless of how broad or narrow the changes you hope to see happen, specific and actionable examples of places where the current syntax creates avoidable traps for programmers (esp. where they can't be fixed with a suitable use of macros) would likely be much more helpful than a general call for syntax minimalism. From greg at kinostudios.com Mon Nov 11 12:41:46 2013 From: greg at kinostudios.com (Greg) Date: Mon, 11 Nov 2013 15:41:46 -0500 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: > At this state in Rust's development, we are unlikely to make any major > changes to Rust's syntax. *cries* > I encourage you to check out Rust's syntax extension / macro system: > http://static.rust-lang.org/doc/master/tutorial-macros.html *clicks link* O_O *cries more* :'-( I'm not sure what stage I'm at right now: https://en.wikipedia.org/wiki/K%C3%BCbler-Ross_model#Stages Either 3 (Bargaining), or 4 (Depression). - Greg -- Please do not email me anything that you are not comfortable also sharing with the NSA. On Nov 11, 2013, at 3:33 PM, Tim Chevalier wrote: > Hi, Greg -- > > At this state in Rust's development, we are unlikely to make any major > changes to Rust's syntax. Literally years of effort have gone into > desgining the syntax, and at this point in the language's development, > our focus is on making any non-backwards-compatible changes in > preparation for releasing 1.0. > > I encourage you to check out Rust's syntax extension / macro system: > > http://static.rust-lang.org/doc/master/tutorial-macros.html > > and explore how that can be used to extend the base syntax. > > Cheers, > Tim > > > On Mon, Nov 11, 2013 at 12:27 PM, Greg wrote: >> Dear Mozilla, rust devs, and memory-safe enthusiasts everywhere, >> >> I'm very happy with the safety improvements that Rust brings. >> >> This is true innovation. >> >> At the same time, I am disappointed and quite concerned about Rust's unimaginative syntax. >> >> It seems to preserve decades of poor decision-making from C++. >> >> The FAQ states: "The syntax is still evolving" >> >> I hope this is still true today. Syntax plays a significant role in safety: >> >> 1. Simple syntax makes software easier to write. >> 2. Simple syntax makes software easier to understand. >> 3. Simple syntax makes inserting a backdoor into an open source project more difficult. >> 4. Simple syntax leads to fewer mistakes. >> >> Were I to have written Rust, I would have modeled its syntax after Clojure/Lisp/Scheme instead of C++ [1]. By this point, I'm aware that this is unlikely to happen. >> >> However, I would like to ask the Rust architects to seriously consider this issue, and ask themselves what syntax they can remove from the language while maintaining type-safety. >> >> Removing syntax should not raise any fears that the language will lose any features or flexibility. >> >> To the contrary, a simpler syntax will likely lead to increased flexibility and possibilities. Lisp has demonstrated unequivocally. >> >> "Typed Clojure" may provide the authors with needed inspiration: >> >> https://github.com/clojure/core.typed/wiki >> https://s3.amazonaws.com/github/downloads/frenchy64/papers/ambrose-honours.pdf >> >> Kind regards, >> Greg >> >> [1] https://www.taoeffect.com/blog/2010/01/how-newlisp-took-my-breath-and-syntax-away/ >> >> -- >> Please do not email me anything that you are not comfortable also sharing with the NSA. >> >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> > > > > -- > Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt > "If you are silent about your pain, they'll kill you and say you enjoyed it." > -- Zora Neale Hurston -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 495 bytes Desc: Message signed with OpenPGP using GPGMail URL: From corey at octayn.net Mon Nov 11 12:46:01 2013 From: corey at octayn.net (Corey Richardson) Date: Mon, 11 Nov 2013 15:46:01 -0500 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: On Mon, Nov 11, 2013 at 3:41 PM, Greg wrote: >> At this state in Rust's development, we are unlikely to make any major >> changes to Rust's syntax. > > *cries* > I don't think Rust can succeed as a language if it massively differs, visually, from the language it intends to offset (C++). From greg at kinostudios.com Mon Nov 11 13:07:58 2013 From: greg at kinostudios.com (Greg) Date: Mon, 11 Nov 2013 16:07:58 -0500 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: > I don't think Rust can succeed as a language if it massively differs, > visually, from the language it intends to offset (C++). Yes, I agree, and that's why I wrote: "By this point, I'm aware that this is unlikely to happen." I think it's still possible to simplify Rust's existing syntax while maintaining the features it offers. I am hoping that the developers of Rust will consider this issue important enough to put more thought into it. I am aware that I am jumping into an issue at a point in time that's considered "late in the game". From the outside, I can say (with confidence), that Rust is still a nearly unheard-of language, and therefore it still has wiggle-room for improvement, even if the Rust developers and community, because they have been immersed in the language for quite some time, cannot see that this is in fact true. I also believe Tim when he said that years of effort went into designing the syntax. However, during those many years, did any of the brains that were involved in designing the syntax seriously consider Clojure's syntax, or Typed Clojure? I'm almost certain that the answer is "no" (partly because these languages/dialects did not exist at the time). What about Lua, which is more C-like? Or CoffeeScript? Looking at the "Influenced By" section on Wikipedia seems to indicate that the answer to these questions is, again, "no". The list contains some bad role models (in terms of syntactic elegance and simplicity): C++, Haskell, OCaml, and Ruby. Thankfully Common Lisp is mentioned. Although, of the Lisps I'm familiar with, Common Lisp has the ugliest syntax (still better than C++ though). This is all to say that, from what I can tell, simplicity and elegance of syntax was not a design requirement (or goal) that the Rust developers had in mind. And I think that's quite unfortunate for Rust. I'm sorry I was not able to provide this feedback years ago when it might have been more helpful. I only recently became aware of Rust. - Greg -- Please do not email me anything that you are not comfortable also sharing with the NSA. On Nov 11, 2013, at 3:46 PM, Corey Richardson wrote: > On Mon, Nov 11, 2013 at 3:41 PM, Greg wrote: >>> At this state in Rust's development, we are unlikely to make any major >>> changes to Rust's syntax. >> >> *cries* >> > > I don't think Rust can succeed as a language if it massively differs, > visually, from the language it intends to offset (C++). -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 495 bytes Desc: Message signed with OpenPGP using GPGMail URL: From andrew.webb at gmail.com Mon Nov 11 13:12:31 2013 From: andrew.webb at gmail.com (Andrew Webb) Date: Tue, 12 Nov 2013 10:12:31 +1300 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: Hi, I am just a lurker as well, so take all of this with a good dose of salt... > At the same time, I am disappointed and quite concerned about Rust's > unimaginative syntax. > It seems to preserve decades of poor decision-making from C++. > > Personally, I find it very pleasant. There are a few things I would have done differently (mostly to do using full names for e.g., function), but that is all window dressing. > > To the contrary, a simpler syntax will likely lead to increased > flexibility and possibilities. Lisp has demonstrated unequivocally. > > "Typed Clojure" may provide the authors with needed inspiration: > > Clojure is my main language, so don't take this as an attack on it (or lisps in general), but the "flexibility" that those languages show is at least in part due to the dynamic type system. Even typed clojure (and typed racket) are dynamically typed, but with posthoc type checking. Although there are many benefits to dynamic typing, neither efficiency, nor provable safety are usually counted amongst them. -------------- next part -------------- An HTML attachment was scrubbed... URL: From corey at octayn.net Mon Nov 11 13:28:27 2013 From: corey at octayn.net (Corey Richardson) Date: Mon, 11 Nov 2013 16:28:27 -0500 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: On Mon, Nov 11, 2013 at 4:07 PM, Greg wrote: > I don't think Rust can succeed as a language if it massively differs, > visually, from the language it intends to offset (C++). > > Yes, I agree, and that's why I wrote: > > "By this point, I'm aware that this is unlikely to happen." > > I think it's still possible to simplify Rust's existing syntax while > maintaining the features it offers. > My point is that the familiar syntax *is* a feature. What simplifications do you propose? I think everyone is mostly happy with the syntax at this point, so your proposed changes and justification are going to be very pursuasive, and followed by a PR, for there to be a chance of them being accepted. From pcwalton at mozilla.com Mon Nov 11 13:43:43 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Tue, 12 Nov 2013 06:43:43 +0900 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: Message-ID: <52814F8F.3020609@mozilla.com> On 11/12/13 5:16 AM, Oren Ben-Kiki wrote: > I googled around and this has been asked before several times; there are > answers that use obsolete syntax and Rust concepts, so I thought it > might be a good idea to revisit the issue. > > The basic use case is having some trait, and having some (base/mixin) > struct implementing it. Now, one wants to have a 2nd (derived/importing) > struct implementing the trait, based on the 1st struct implementation > (including its data members). There are proposals for this, if I understand you correctly. This is needed in Servo. http://smallcultfollowing.com/babysteps/blog/2013/10/24/single-inheritance/ Patrick From thadguidry at gmail.com Mon Nov 11 14:00:45 2013 From: thadguidry at gmail.com (Thad Guidry) Date: Mon, 11 Nov 2013 16:00:45 -0600 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: >From the outside looking in... I do not see anything preventing Greg from producing many macros or an entire syntax sub-system to emulate and empower him with any sugary languages that he might prefer or desire. It is just going to be quite a bit of work for him, but he could do it himself, if we wanted to turn Rust's syntax into something closer to Type Clojure or create a DSL. Is that not true ? On Mon, Nov 11, 2013 at 3:28 PM, Corey Richardson wrote: > On Mon, Nov 11, 2013 at 4:07 PM, Greg wrote: > > I don't think Rust can succeed as a language if it massively differs, > > visually, from the language it intends to offset (C++). > > > > Yes, I agree, and that's why I wrote: > > > > "By this point, I'm aware that this is unlikely to happen." > > > > I think it's still possible to simplify Rust's existing syntax while > > maintaining the features it offers. > > > > My point is that the familiar syntax *is* a feature. What > simplifications do you propose? I think everyone is mostly happy with > the syntax at this point, so your proposed changes and justification > are going to be very pursuasive, and followed by a PR, for there to be > a chance of them being accepted. > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- -Thad +ThadGuidry Thad on LinkedIn -------------- next part -------------- An HTML attachment was scrubbed... URL: From banderson at mozilla.com Mon Nov 11 14:01:53 2013 From: banderson at mozilla.com (Brian Anderson) Date: Mon, 11 Nov 2013 14:01:53 -0800 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: <528153D1.1030003@mozilla.com> On 11/11/2013 01:07 PM, Greg wrote: >> I don't think Rust can succeed as a language if it massively differs, >> visually, from the language it intends to offset (C++). > > Yes, I agree, and that's why I wrote: > > /"By this point, I'm aware that this is unlikely to happen."/ > > I think it's still possible to simplify Rust's existing syntax while > maintaining the features it offers. > > I am hoping that the developers of Rust will consider this issue > important enough to put more thought into it. > > I am aware that I am jumping into an issue at a point in time that's > considered "late in the game". > > From the outside, I can say (with confidence), that Rust is still a > nearly unheard-of language, and therefore it still has wiggle-room for > improvement, even if the Rust developers and community, because they > have been immersed in the language for quite some time, cannot see > that this is in fact true. > > I also believe Tim when he said that years of effort went into > designing the syntax. > > However, during those many years, did any of the brains that were > involved in designing the syntax seriously consider Clojure's syntax, > or Typed Clojure? > > I'm almost certain that the answer is "no" (partly because these > languages/dialects did not exist at the time). > > What about Lua, which is more C-like? > > Or CoffeeScript? > > Looking at the "Influenced By" section on Wikipedia seems to indicate > that the answer to these questions is, again, "no". The answer is 'yes'. The designers of Rust are well aware of these languages and many others and have debated syntax issues repeatedly (as it is the most beloved pasttime of language designers). The current syntax was designed very intentionally the way it is. -------------- next part -------------- An HTML attachment was scrubbed... URL: From niko at alum.mit.edu Mon Nov 11 14:16:46 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Mon, 11 Nov 2013 17:16:46 -0500 Subject: [rust-dev] returning an item from a collection In-Reply-To: <5280EE45.7020905@gmail.com> References: <5280D114.8010907@gmail.com> <501973145.8294345.1384177647691.JavaMail.zimbra@mozilla.com> <5280EE45.7020905@gmail.com> Message-ID: <20131111221646.GC14427@Mr-Bennet> On Mon, Nov 11, 2013 at 03:48:37PM +0100, spir wrote: > Also, what does > let y = x; > mean in Rust if x's type is constant (as opposed to a generic type > var)? Does it depend on the exact type? and specifically what happens > in the case of simple, atomic, type? The meaning is: - shallow copy the data from x into y; - if x has a type that cannot be copied (e.g., `~T`), invalidate x so that it can no longer be used ("move"). Niko From clements at brinckerhoff.org Mon Nov 11 15:12:27 2013 From: clements at brinckerhoff.org (John Clements) Date: Mon, 11 Nov 2013 15:12:27 -0800 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: On Nov 11, 2013, at 1:07 PM, Greg wrote: >> I don't think Rust can succeed as a language if it massively differs, >> visually, from the language it intends to offset (C++). > > Yes, I agree, and that's why I wrote: > > "By this point, I'm aware that this is unlikely to happen." > ... > However, during those many years, did any of the brains that were involved in designing the syntax seriously consider Clojure's syntax, or Typed Clojure? > > I'm almost certain that the answer is "no" (partly because these languages/dialects did not exist at the time). > > What about Lua, which is more C-like? > > Or CoffeeScript? Greg, thanks for your comments! In fact, nearly all of the designers of Rust are deeply familiar with the syntactic conventions of these and other languages. Speaking only for myself, I come from Racket, and I'm a strong proponent of fully parenthesized syntaxes. But! Rust is not that language. As you suggest (and others confirm), that train left the station long, long ago. The choice of the Rust team to adopt a C++-like syntax was very deliberate, and I'm confident that the members of this team still believe that was the right choice. With that said, though, Rust is a new and exciting language; if you can think of improvements, try coding them up and see what you get! In my experience, the Rust developers are always happy to hear from volunteers who are excited about the language and have concrete pull requests. If you had the energy to build an alternate front-end using a parenthesized syntax, I'm sure there are others that would give it a try. Me, for instance! All the best, John Clements From gaetan at xeberon.net Mon Nov 11 15:21:37 2013 From: gaetan at xeberon.net (Gaetan) Date: Tue, 12 Nov 2013 00:21:37 +0100 Subject: [rust-dev] About owned pointer In-Reply-To: <527E3E3C.3040108@gmail.com> References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D63F0.1030004@mozilla.com> <559DC61A-0CD3-4B74-9A6F-3B8C3A5E734E@sb.org> <527E3E3C.3040108@gmail.com> Message-ID: Just an humble opinion. I kind of like saying that the code i write must be beautiful. The langage should allow to write "beautiful" code. It is more than a personnal point of view, it is also very important. if it is a pain in the ... to use an essential feature, or if i will never remember how to do it without copy paste because there is no "logic" behind it, i will have a bad opinion on the langage itself. The real question are: - as a typicial rust programmer, will i see the usage of "str" or "~str" as logic or will i have to copy paste some sample code each time "because it works this way in rust" - the boilder plates theory. Can i avoid them? I think a good modern language should allow me to avoid writing useless code, each time the same things. That is the real mess with C++. Gaetan Le samedi 9 novembre 2013, spir a ?crit : > On 11/09/2013 06:43 AM, Kevin Ballard wrote:> On Nov 8, 2013, at 9:38 PM, > Daniel Micay wrote: > >> >> On Sat, Nov 9, 2013 at 12:36 AM, Kevin Ballard wrote: >>> On Nov 8, 2013, at 2:21 PM, Patrick Walton wrote: >>> >>> I know that many people don't like the fact that, syntactically, >>>> vectors and strings have a sigil in front of them, but please consider that >>>> there are many design constraints here. What works for another language may >>>> not work for Rust, because of these constraints. >>>> >>> >>> Personally, I find it great that they have a sigil in front of them. It >>> reminds me that they're stored in the heap. >>> >>> -Kevin >>> >>> Since library containers, smart pointers and other types don't have >>> them, I don't think it's helpful in that regard. >>> >> >> Well no, you can't assume that the absence of a sigil means the absence >> of heap storage. But for types that are possibly not stored on the heap, >> such as str (which can be &'static str) and [T] (which can be a fixed-size >> stack-allocated vector), the ~ is a useful distinction. >> >> -Kevin >> > > Can we, then, even consider the opposite: having a sigil for static data > (mainly literal strings stored in static mem, I'd say) or generally > non-heap data (thus including eg static arrays stored on stack)? The > advantage is that this restores coherence between all heap of heap data. > I'd use '$'! (what else can this sign be good for, anyway? ;-) > > [But where should the sigil go? In front of the data literal, as in > let stst = $"Hello, world!"; > let nums = $[1,2,3]; > or in front of the type, or of the id itself?] > > Also, is it at all possible, in the long term maybe, to consider letting > the compiler choose where to store, in cases where a possible pointer is > meaningless, that is it does not express a true reference (shared object, > that a.x is also b.y), instead is used for technical or efficiency reasons > (that memory is not elastic!, for avoiding copy, etc...)? > > Denis > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- ----- Gaetan -------------- next part -------------- An HTML attachment was scrubbed... URL: From catamorphism at gmail.com Mon Nov 11 15:27:42 2013 From: catamorphism at gmail.com (Tim Chevalier) Date: Mon, 11 Nov 2013 15:27:42 -0800 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D63F0.1030004@mozilla.com> <559DC61A-0CD3-4B74-9A6F-3B8C3A5E734E@sb.org> <527E3E3C.3040108@gmail.com> Message-ID: On Mon, Nov 11, 2013 at 3:21 PM, Gaetan wrote: > Just an humble opinion. > > I kind of like saying that the code i write must be beautiful. The langage > should allow to write "beautiful" code. It is more than a personnal point of > view, it is also very important. if it is a pain in the ... to use an > essential feature, or if i will never remember how to do it without copy > paste because there is no "logic" behind it, i will have a bad opinion on > the langage itself. Of course, "beauty" is subjective. Personally, I see it as language-independent, and don't find it any harder to write beautiful code in Rust than in any other language I know. It's certainly easier than in some languages, since I don't have to spend as much time debugging run-time errors and can spend that time making my code aesthetically better. > > The real question are: > - as a typicial rust programmer, will i see the usage of "str" or "~str" as > logic or will i have to copy paste some sample code each time "because it > works this way in rust" Once you gain experience with Rust, this will seem natural. You reason about whether you're passing data by value or by reference (i.e. borrowed pointer) anyway, and Rust just makes that distinction more explicit. > - the boilder plates theory. Can i avoid them? I think a good modern > language should allow me to avoid writing useless code, each time the same > things. That is the real mess with C++. I'm not sure what your question is here, sorry. Cheers, Tim > > Gaetan > > > Le samedi 9 novembre 2013, spir a ?crit : > >> On 11/09/2013 06:43 AM, Kevin Ballard wrote:> On Nov 8, 2013, at 9:38 PM, >> Daniel Micay wrote: >>> >>> >>>> On Sat, Nov 9, 2013 at 12:36 AM, Kevin Ballard wrote: >>>> On Nov 8, 2013, at 2:21 PM, Patrick Walton wrote: >>>> >>>>> I know that many people don't like the fact that, syntactically, >>>>> vectors and strings have a sigil in front of them, but please consider that >>>>> there are many design constraints here. What works for another language may >>>>> not work for Rust, because of these constraints. >>>> >>>> >>>> Personally, I find it great that they have a sigil in front of them. It >>>> reminds me that they're stored in the heap. >>>> >>>> -Kevin >>>> >>>> Since library containers, smart pointers and other types don't have >>>> them, I don't think it's helpful in that regard. >>> >>> >>> Well no, you can't assume that the absence of a sigil means the absence >>> of heap storage. But for types that are possibly not stored on the heap, >>> such as str (which can be &'static str) and [T] (which can be a fixed-size >>> stack-allocated vector), the ~ is a useful distinction. >>> >>> -Kevin >> >> >> Can we, then, even consider the opposite: having a sigil for static data >> (mainly literal strings stored in static mem, I'd say) or generally non-heap >> data (thus including eg static arrays stored on stack)? The advantage is >> that this restores coherence between all heap of heap data. >> I'd use '$'! (what else can this sign be good for, anyway? ;-) >> >> [But where should the sigil go? In front of the data literal, as in >> let stst = $"Hello, world!"; >> let nums = $[1,2,3]; >> or in front of the type, or of the id itself?] >> >> Also, is it at all possible, in the long term maybe, to consider letting >> the compiler choose where to store, in cases where a possible pointer is >> meaningless, that is it does not express a true reference (shared object, >> that a.x is also b.y), instead is used for technical or efficiency reasons >> (that memory is not elastic!, for avoiding copy, etc...)? >> >> Denis >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > > > > -- > ----- > Gaetan > > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt "If you are silent about your pain, they'll kill you and say you enjoyed it." -- Zora Neale Hurston From gaetan at xeberon.net Mon Nov 11 15:52:01 2013 From: gaetan at xeberon.net (Gaetan) Date: Tue, 12 Nov 2013 00:52:01 +0100 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: <528153D1.1030003@mozilla.com> References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> <528153D1.1030003@mozilla.com> Message-ID: Can we have Two rust? The first one would be easy to learn, easy to read, and do most of ones would expect: on demand garbage collector, traits, Owned pointers,... The second one would include all advanced feature we actually don t need everyday. Of course, we don t want to split the language, but rather pr?sent the current things differently. The tutorials are a good starting point however, the rest of the documentations are quite complex. I would be very delighted to help on this matter. There could be some effort on simplification of the API (std/extra): provides just "the right functions" first, and allow all flexibility in a second step, maybe in an "advanced functions" parts in each API doc. For instance url.rs. To parse a string, you have to write this: let u = url::from_str(urlstring).unwrap(); I would propose this solution: let u = parse_url(urlstring); => simpler, easier to read, easier to remember ! Of course, the unwrap thing would still be here. base64.rs: let s = [52, 53, 54].to_base64(STANDARD); => why adding the "standard" argument? One will ALWAYS want the "STANDARD" method of creating the base64 representation of some bytes, why not adding this argument as default. There are some minor change to the API that would help a lot the learning of this language, along with adding more code sample in the documentation. After year of writing C++ code with complex API (boost) I enjoy writing with python which seems to provide just the right methods I need. I'll willing to help, but I don't easily find a easy starting point :) Gaetan Le lundi 11 novembre 2013, Brian Anderson a ?crit : > On 11/11/2013 01:07 PM, Greg wrote: > > I don't think Rust can succeed as a language if it massively differs, > visually, from the language it intends to offset (C++). > > > Yes, I agree, and that's why I wrote: > > * "By this point, I'm aware that this is unlikely to happen."* > > I think it's still possible to simplify Rust's existing syntax while > maintaining the features it offers. > > I am hoping that the developers of Rust will consider this issue > important enough to put more thought into it. > > I am aware that I am jumping into an issue at a point in time that's > considered "late in the game". > > From the outside, I can say (with confidence), that Rust is still a > nearly unheard-of language, and therefore it still has wiggle-room for > improvement, even if the Rust developers and community, because they have > been immersed in the language for quite some time, cannot see that this is > in fact true. > > I also believe Tim when he said that years of effort went into designing > the syntax. > > However, during those many years, did any of the brains that were > involved in designing the syntax seriously consider Clojure's syntax, or > Typed Clojure? > > I'm almost certain that the answer is "no" (partly because these > languages/dialects did not exist at the time). > > What about Lua, which is more C-like? > > Or CoffeeScript? > > Looking at the "Influenced By" section on Wikipedia seems to indicate > that the answer to these questions is, again, "no". > > > The answer is 'yes'. The designers of Rust are well aware of these > languages and many others and have debated syntax issues repeatedly (as it > is the most beloved pasttime of language designers). The current syntax was > designed very intentionally the way it is. > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg at kinostudios.com Mon Nov 11 16:00:49 2013 From: greg at kinostudios.com (Greg) Date: Mon, 11 Nov 2013 19:00:49 -0500 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: <2E45FBF8-8124-45AA-994B-92559C6FB5B8@kinostudios.com> Thanks John, for the friendly email. :-) > The choice of the Rust team to adopt a C++-like syntax was very deliberate, and I'm confident that the members of this team still believe that was the right choice. I wonder, right for what reason? Do they actually *like* it? I wrote a lot of code in C++ back in the day. Can't touch the stuff anymore. *shudders* Or is it 'right' because it's familiar to C++ developers? I should have mentioned Java in my original post to the list. Java is relevant for a few reasons: 1. It has been around for a long time. 2. It's quite popular. 3. It's C-like, familiar, and attempts to implement some safety into the language 4. Its syntax is fairly simple (compared to C++). And most significantly of all: 5. It has gone through some significant syntactic changes, _years_ after being well established and well known. For example, Java 1.5 added Generics to the language (a simplified version of C++ templates). The recent Java has added anonymous functions (lambdas). Other well established languages have also made significant changes to their syntax well after their first birthday. Objective-C, for example, added properties and Automatic Reference Counting in with it turned 2.0. It also added syntax for various literals (arrays, maps, etc.): http://clang.llvm.org/docs/ObjectiveCLiterals.html So, given the history of these well established languages, I think there's still plenty of opportunity for change with Rust. More so, in fact, due to its alpha status. It's easier to remove syntax while a language is young, and Rust is still very young. > With that said, though, Rust is a new and exciting language; if you can think of improvements, try coding them up and see what you get! In my experience, the Rust developers are always happy to hear from volunteers who are excited about the language and have concrete pull requests. If you had the energy to build an alternate front-end using a parenthesized syntax, I'm sure there are others that would give it a try. Me, for instance! I'd love to, but zero time at the moment. :-( Also, I'm not simply advocating a parenthesis-based syntax (though that would be *awesome*!). I think the present syntax is malleable and can be simplified and improved while retaining its C-ness for the sake of developers who haven't quite yet expanded their minds... :-p Cheers, Greg -- Please do not email me anything that you are not comfortable also sharing with the NSA. On Nov 11, 2013, at 6:12 PM, John Clements wrote: > > On Nov 11, 2013, at 1:07 PM, Greg wrote: > >>> I don't think Rust can succeed as a language if it massively differs, >>> visually, from the language it intends to offset (C++). >> >> Yes, I agree, and that's why I wrote: >> >> "By this point, I'm aware that this is unlikely to happen." >> > > ... > >> However, during those many years, did any of the brains that were involved in designing the syntax seriously consider Clojure's syntax, or Typed Clojure? >> >> I'm almost certain that the answer is "no" (partly because these languages/dialects did not exist at the time). >> >> What about Lua, which is more C-like? >> >> Or CoffeeScript? > > Greg, thanks for your comments! > > In fact, nearly all of the designers of Rust are deeply familiar with the syntactic conventions of these and other languages. Speaking only for myself, I come from Racket, and I'm a strong proponent of fully parenthesized syntaxes. > > But! > > Rust is not that language. As you suggest (and others confirm), that train left the station long, long ago. The choice of the Rust team to adopt a C++-like syntax was very deliberate, and I'm confident that the members of this team still believe that was the right choice. > > With that said, though, Rust is a new and exciting language; if you can think of improvements, try coding them up and see what you get! In my experience, the Rust developers are always happy to hear from volunteers who are excited about the language and have concrete pull requests. If you had the energy to build an alternate front-end using a parenthesized syntax, I'm sure there are others that would give it a try. Me, for instance! > > All the best, > > John Clements > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 495 bytes Desc: Message signed with OpenPGP using GPGMail URL: From catamorphism at gmail.com Mon Nov 11 16:01:07 2013 From: catamorphism at gmail.com (Tim Chevalier) Date: Mon, 11 Nov 2013 16:01:07 -0800 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> <528153D1.1030003@mozilla.com> Message-ID: On Mon, Nov 11, 2013 at 3:52 PM, Gaetan wrote: > Can we have Two rust? > > The first one would be easy to learn, easy to read, and do most of ones > would expect: on demand garbage collector, traits, Owned pointers,... > > The second one would include all advanced feature we actually don t need > everyday. > > Of course, we don t want to split the language, but rather pr?sent the > current things differently. The tutorials are a good starting point however, > the rest of the documentations are quite complex. I would be very delighted > to help on this matter. There could be some effort on simplification of the > API (std/extra): provides just "the right functions" first, and allow all > flexibility in a second step, maybe in an "advanced functions" parts in each > API doc. We always welcome documentation patches! A more ambitious project would be to add "language levels" to Rust (like Racket has). If you were interested in pursuing this, you would want to discuss it with members of the core team. I doubt it would be accepted as a patch in the short term (since it's not a 1.0 priority), but in the long term, it's certainly possible. Cheers, Tim > > For instance url.rs. To parse a string, you have to write this: > > let u = url::from_str(urlstring).unwrap(); > > I would propose this solution: > > let u = parse_url(urlstring); > > > => simpler, easier to read, easier to remember ! > Of course, the unwrap thing would still be here. > > base64.rs: > > let s = [52, 53, 54].to_base64(STANDARD); > > > => why adding the "standard" argument? One will ALWAYS want the "STANDARD" > method of creating the base64 representation of some bytes, why not adding > this argument as default. > > There are some minor change to the API that would help a lot the learning of > this language, along with adding more code sample in the documentation. > > After year of writing C++ code with complex API (boost) I enjoy writing with > python which seems to provide just the right methods I need. > > I'll willing to help, but I don't easily find a easy starting point :) > > Gaetan > > Le lundi 11 novembre 2013, Brian Anderson a ?crit : > >> On 11/11/2013 01:07 PM, Greg wrote: >> >> I don't think Rust can succeed as a language if it massively differs, >> visually, from the language it intends to offset (C++). >> >> >> Yes, I agree, and that's why I wrote: >> >> "By this point, I'm aware that this is unlikely to happen." >> >> I think it's still possible to simplify Rust's existing syntax while >> maintaining the features it offers. >> >> I am hoping that the developers of Rust will consider this issue important >> enough to put more thought into it. >> >> I am aware that I am jumping into an issue at a point in time that's >> considered "late in the game". >> >> From the outside, I can say (with confidence), that Rust is still a nearly >> unheard-of language, and therefore it still has wiggle-room for improvement, >> even if the Rust developers and community, because they have been immersed >> in the language for quite some time, cannot see that this is in fact true. >> >> I also believe Tim when he said that years of effort went into designing >> the syntax. >> >> However, during those many years, did any of the brains that were involved >> in designing the syntax seriously consider Clojure's syntax, or Typed >> Clojure? >> >> I'm almost certain that the answer is "no" (partly because these >> languages/dialects did not exist at the time). >> >> What about Lua, which is more C-like? >> >> Or CoffeeScript? >> >> Looking at the "Influenced By" section on Wikipedia seems to indicate that >> the answer to these questions is, again, "no". >> >> >> The answer is 'yes'. The designers of Rust are well aware of these >> languages and many others and have debated syntax issues repeatedly (as it >> is the most beloved pasttime of language designers). The current syntax was >> designed very intentionally the way it is. >> >> > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt "If you are silent about your pain, they'll kill you and say you enjoyed it." -- Zora Neale Hurston From danielmicay at gmail.com Mon Nov 11 16:01:34 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Mon, 11 Nov 2013 19:01:34 -0500 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> <528153D1.1030003@mozilla.com> Message-ID: On Mon, Nov 11, 2013 at 6:52 PM, Gaetan wrote: > > For instance url.rs. To parse a string, you have to write this: > > let u = url::from_str(urlstring).unwrap(); > > I would propose this solution: > > let u = parse_url(urlstring); > > > => simpler, easier to read, easier to remember ! > Of course, the unwrap thing would still be here. > Rust generally uses sum types to report errors. The `from_str` method doesn't work for all inputs, so it returns `None` in those cases. The ability to handle errors does need to be there, and forcing a concious decision on how to handle common, easily recoverable errors makes a lot of sense to me. -------------- next part -------------- An HTML attachment was scrubbed... URL: From catamorphism at gmail.com Mon Nov 11 16:05:29 2013 From: catamorphism at gmail.com (Tim Chevalier) Date: Mon, 11 Nov 2013 16:05:29 -0800 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: <2E45FBF8-8124-45AA-994B-92559C6FB5B8@kinostudios.com> References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> <2E45FBF8-8124-45AA-994B-92559C6FB5B8@kinostudios.com> Message-ID: Mod hat: This thread has become pretty off-topic. Let's wind it down and move any specific questions or concrete proposals regarding Rust to a new, separate thread. Please familiarize yourself with the "Conduct" section of https://github.com/mozilla/rust/wiki/Note-development-policy , particularly these parts: "Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works." In particular, discussing the merits or lack thereof of C or Java syntax is out of scope for this mailing list. I understand that this subject came up because it was cited as a reason for Rust's syntax, but as several people have said, these decisions have been made and won't be revisited (except, *perhaps*, in the presence of a concrete proposal and preferably an implementation). Also, please avoid suggesting that people who do or don't like a particular syntax haven't expanded their mind; it's okay for different people to have different opinions about language design, and choosing any one approach doesn't mean we think less of people who prefer other ones. Cheers, Tim On Mon, Nov 11, 2013 at 4:00 PM, Greg wrote: > Thanks John, for the friendly email. :-) > > The choice of the Rust team to adopt a C++-like syntax was very deliberate, > and I'm confident that the members of this team still believe that was the > right choice. > > > I wonder, right for what reason? Do they actually *like* it? I wrote a lot > of code in C++ back in the day. Can't touch the stuff anymore. *shudders* > > Or is it 'right' because it's familiar to C++ developers? > > I should have mentioned Java in my original post to the list. > > Java is relevant for a few reasons: > > 1. It has been around for a long time. > 2. It's quite popular. > 3. It's C-like, familiar, and attempts to implement some safety into the > language > 4. Its syntax is fairly simple (compared to C++). > > And most significantly of all: > > 5. It has gone through some significant syntactic changes, _years_ after > being well established and well known. > > For example, Java 1.5 added Generics to the language (a simplified version > of C++ templates). > > The recent Java has added anonymous functions (lambdas). > > Other well established languages have also made significant changes to their > syntax well after their first birthday. Objective-C, for example, added > properties and Automatic Reference Counting in with it turned 2.0. > > It also added syntax for various literals (arrays, maps, etc.): > http://clang.llvm.org/docs/ObjectiveCLiterals.html > > So, given the history of these well established languages, I think there's > still plenty of opportunity for change with Rust. More so, in fact, due to > its alpha status. It's easier to remove syntax while a language is young, > and Rust is still very young. > > With that said, though, Rust is a new and exciting language; if you can > think of improvements, try coding them up and see what you get! In my > experience, the Rust developers are always happy to hear from volunteers who > are excited about the language and have concrete pull requests. If you had > the energy to build an alternate front-end using a parenthesized syntax, I'm > sure there are others that would give it a try. Me, for instance! > > > I'd love to, but zero time at the moment. :-( > > Also, I'm not simply advocating a parenthesis-based syntax (though that > would be *awesome*!). I think the present syntax is malleable and can be > simplified and improved while retaining its C-ness for the sake of > developers who haven't quite yet expanded their minds... :-p > > Cheers, > Greg > > -- > Please do not email me anything that you are not comfortable also sharing > with the NSA. > > On Nov 11, 2013, at 6:12 PM, John Clements > wrote: > > > On Nov 11, 2013, at 1:07 PM, Greg wrote: > > I don't think Rust can succeed as a language if it massively differs, > visually, from the language it intends to offset (C++). > > > Yes, I agree, and that's why I wrote: > > "By this point, I'm aware that this is unlikely to happen." > > > ... > > However, during those many years, did any of the brains that were involved > in designing the syntax seriously consider Clojure's syntax, or Typed > Clojure? > > I'm almost certain that the answer is "no" (partly because these > languages/dialects did not exist at the time). > > What about Lua, which is more C-like? > > Or CoffeeScript? > > > Greg, thanks for your comments! > > In fact, nearly all of the designers of Rust are deeply familiar with the > syntactic conventions of these and other languages. Speaking only for > myself, I come from Racket, and I'm a strong proponent of fully > parenthesized syntaxes. > > But! > > Rust is not that language. As you suggest (and others confirm), that train > left the station long, long ago. The choice of the Rust team to adopt a > C++-like syntax was very deliberate, and I'm confident that the members of > this team still believe that was the right choice. > > With that said, though, Rust is a new and exciting language; if you can > think of improvements, try coding them up and see what you get! In my > experience, the Rust developers are always happy to hear from volunteers who > are excited about the language and have concrete pull requests. If you had > the energy to build an alternate front-end using a parenthesized syntax, I'm > sure there are others that would give it a try. Me, for instance! > > All the best, > > John Clements > > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt "If you are silent about your pain, they'll kill you and say you enjoyed it." -- Zora Neale Hurston From greg at kinostudios.com Mon Nov 11 16:24:10 2013 From: greg at kinostudios.com (Greg) Date: Mon, 11 Nov 2013 19:24:10 -0500 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> <2E45FBF8-8124-45AA-994B-92559C6FB5B8@kinostudios.com> Message-ID: <39EE4677-087C-4383-83C1-CF79A0FFC9AB@kinostudios.com> On Nov 11, 2013, at 7:05 PM, Tim Chevalier wrote: > Also, please avoid > suggesting that people who do or don't like a particular syntax > haven't expanded their mind; it's okay for different people to have > different opinions about language design, and choosing any one > approach doesn't mean we think less of people who prefer other ones. I probably could have phrased that better to avoid misunderstandings. No offense was intended. The comment is a reference to anyone who is unfamiliar with the syntax of non-C-type languages. It's not a reference to anyone familiar with various syntaxes (C-type and others) and prefers C++. No superiority-complex, condescension, or anything of that sort was intended, please don't misunderstand. Kind regards, Greg -- Please do not email me anything that you are not comfortable also sharing with the NSA. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 495 bytes Desc: Message signed with OpenPGP using GPGMail URL: From pcwalton at mozilla.com Mon Nov 11 16:59:23 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Tue, 12 Nov 2013 09:59:23 +0900 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: <2E45FBF8-8124-45AA-994B-92559C6FB5B8@kinostudios.com> References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> <2E45FBF8-8124-45AA-994B-92559C6FB5B8@kinostudios.com> Message-ID: <52817D6B.2050608@mozilla.com> On 11/12/13 9:00 AM, Greg wrote: > Thanks John, for the friendly email. :-) > >> The choice of the Rust team to adopt a C++-like syntax was very >> deliberate, and I'm confident that the members of this team still >> believe that was the right choice. > > I wonder, right for what reason? Do they actually */like*/ it? I wrote a > lot of code in C++ back in the day. Can't touch the stuff anymore. > *shudders* I prefer C-like (Algol-like, if you want to be pedantic :)) syntax to S-expressions. Patrick From bjzaba at yahoo.com.au Mon Nov 11 17:15:21 2013 From: bjzaba at yahoo.com.au (Brendan Zabarauskas) Date: Tue, 12 Nov 2013 12:15:21 +1100 Subject: [rust-dev] About owned pointer In-Reply-To: References: <20131108113323.GC23082@Mr-Bennet> <8817533.0HqEL1HLOK@tph-l10036> <527D1ED9.8000008@gmail.com> <527D20C4.3060107@mozilla.com> <527D33E7.4040007@gmail.com> <527D560E.5030807@mozilla.com> <527D6082.7030507@mozilla.com> <527D63F0.1030004@mozilla.com> <559DC61A-0CD3-4B74-9A6F-3B8C3A5E734E@sb.org> <527E3E3C.3040108@gmail.com> Message-ID: <32422932-E7DC-4EB3-865B-DF95023BDC32@yahoo.com.au> On 12 Nov 2013, at 10:21 am, Gaetan wrote: > - as a typicial rust programmer, will i see the usage of "str" or "~str" as logic or will i have to copy paste some sample code each time "because it works this way in rust? This is what I thought at first, but once you use it for a while it will become natural, and you will find the distinction very useful. Just give it a chance before you jump to conclusions - you won?t regret it! :) > - the boilder plates theory. Can i avoid them? I think a good modern language should allow me to avoid writing useless code, each time the same things. That is the real mess with C++. They are not useless - `~str`, `&str`, `&'a str` and `&'static str` all convey extremely important semantic information both to the programmer and to the compiler. Changing `~str` to `str` would cause more inconsistencies (what about the borrowed pointers?) with a loss of the afore mentioned semantic information. ~Brendan From bjzaba at yahoo.com.au Mon Nov 11 17:23:54 2013 From: bjzaba at yahoo.com.au (Brendan Zabarauskas) Date: Tue, 12 Nov 2013 12:23:54 +1100 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: <290552A5-BEB7-4326-B336-FC982D1C60B8@yahoo.com.au> On 12 Nov 2013, at 10:12 am, John Clements wrote: > If you had the energy to build an alternate front-end using a parenthesized syntax, I'm sure there are others that would give it a try. Me, for instance! It would be nice if we could: - A: desugar Rust into a small kernel language - B: allow rustc to take in some sort of raw AST data (not sure if that?s already possible) - C: have a way of outputting the AST data in a certain syntax. That would allow folks like me to have a nice Haskelly syntax as well as an s-expr style! Heh. ~Brendan From sfackler at gmail.com Mon Nov 11 17:35:05 2013 From: sfackler at gmail.com (Steven Fackler) Date: Mon, 11 Nov 2013 17:35:05 -0800 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: <290552A5-BEB7-4326-B336-FC982D1C60B8@yahoo.com.au> References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> <290552A5-BEB7-4326-B336-FC982D1C60B8@yahoo.com.au> Message-ID: > base64.rs: > let s = [52, 53, 54].to_base64(STANDARD); > > => why adding the "standard" argument? One will ALWAYS want the "STANDARD" method of creating the base64 representation of some bytes, why not adding this argument as default. That is not true. If you are going to be putting the Base64 encoded data into a URL you're going to have to use URL_SAFE instead of STANDARD. If you're trying to send an email, you'll need to use MIME instead of STANDARD. If you're talking to a service that requires one of the ~10 other variants of Base64, you'll need to use a custom config struct. Steven Fackler On Mon, Nov 11, 2013 at 5:23 PM, Brendan Zabarauskas wrote: > On 12 Nov 2013, at 10:12 am, John Clements > wrote: > > > If you had the energy to build an alternate front-end using a > parenthesized syntax, I'm sure there are others that would give it a try. > Me, for instance! > > It would be nice if we could: > > - A: desugar Rust into a small kernel language > - B: allow rustc to take in some sort of raw AST data (not sure if that?s > already possible) > - C: have a way of outputting the AST data in a certain syntax. > > That would allow folks like me to have a nice Haskelly syntax as well as > an s-expr style! > > Heh. > > ~Brendan > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From oren at ben-kiki.org Mon Nov 11 23:32:06 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Tue, 12 Nov 2013 09:32:06 +0200 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: <52814F8F.3020609@mozilla.com> References: <52814F8F.3020609@mozilla.com> Message-ID: Ah, thanks. I wasn't aware of that. I should start tracking that RSS feed... I am very concerned that single-inheritance takes the language in the wrong direction. I feel that a more mixin-oriented solution would better match Rust's traits based type system. I posted a comment the blog entry you gave, which I assume is a more appropriate venue than this thread...? Either way, I gather there's no current idiomatic pattern for this - we are waiting until some solution is agreed upon (and implemented :-) Thanks, Oren. On Mon, Nov 11, 2013 at 11:43 PM, Patrick Walton wrote: > On 11/12/13 5:16 AM, Oren Ben-Kiki wrote: > >> I googled around and this has been asked before several times; there are >> answers that use obsolete syntax and Rust concepts, so I thought it >> might be a good idea to revisit the issue. >> >> The basic use case is having some trait, and having some (base/mixin) >> struct implementing it. Now, one wants to have a 2nd (derived/importing) >> struct implementing the trait, based on the 1st struct implementation >> (including its data members). >> > > There are proposals for this, if I understand you correctly. This is > needed in Servo. > > http://smallcultfollowing.com/babysteps/blog/2013/10/24/ > single-inheritance/ > > Patrick > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Mon Nov 11 23:43:44 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Tue, 12 Nov 2013 16:43:44 +0900 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: <52814F8F.3020609@mozilla.com> Message-ID: <5281DC30.8040402@mozilla.com> On 11/12/13 4:32 PM, Oren Ben-Kiki wrote: > Ah, thanks. I wasn't aware of that. I should start tracking that RSS feed... > > I am very concerned that single-inheritance takes the language in the > wrong direction. I feel that a more mixin-oriented solution would better > match Rust's traits based type system. I posted a comment the blog entry > you gave, which I assume is a more appropriate venue than this thread...? Your solution does not match the performance of single inheritance, because it has virtual method calls for every field access from the "outside" of the trait. We don't want single inheritance because we're enamored with Java or anything, we want it because nothing that we've been able to come up with matches the performance that the prefix property on fields buys you. C++ code can be very fast for a reason. We considered Go's anonymous fields but rejected them because they don't support virtual methods at the same time as field embedding. Patrick From oren at ben-kiki.org Mon Nov 11 23:53:18 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Tue, 12 Nov 2013 09:53:18 +0200 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: <5281DC30.8040402@mozilla.com> References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> Message-ID: "Your solution does not match the performance of single inheritance, because it has virtual method calls for every field access from the "outside" of the trait." Sorry, I don't follow. Access to members from outside of the traits would require accessing the concrete type. Since the approach I described used source transformation, then this would just be a normal data member access, as efficient as single inheritance. Put another way, there's no difference for member access from within and from outside the trait; both are interpreted as normal data member access given the concrete struct (which includes the reused data members somewhere in it). pub struct FooS { member: int; } pub struct BarS { ... reuse FooS::*; ... } // Gets expanded to: pub struct BarS { ... member: int; ... } // Then compiled normally /* Either inside or outside any trait, doesn't matter */ { bar: BarS = ...; bar.member; // Just a normal data member access } impl AnyTraitAtAll for BarS { ... { self.member; // Still just a normal data member access } reuse SomeMixin::*; // Doesn't matter, `member` is still just a normal data member } On Tue, Nov 12, 2013 at 9:43 AM, Patrick Walton wrote: > On 11/12/13 4:32 PM, Oren Ben-Kiki wrote: > >> Ah, thanks. I wasn't aware of that. I should start tracking that RSS >> feed... >> >> I am very concerned that single-inheritance takes the language in the >> wrong direction. I feel that a more mixin-oriented solution would better >> match Rust's traits based type system. I posted a comment the blog entry >> you gave, which I assume is a more appropriate venue than this thread...? >> > > Your solution does not match the performance of single inheritance, > because it has virtual method calls for every field access from the > "outside" of the trait. > > We don't want single inheritance because we're enamored with Java or > anything, we want it because nothing that we've been able to come up with > matches the performance that the prefix property on fields buys you. C++ > code can be very fast for a reason. > > We considered Go's anonymous fields but rejected them because they don't > support virtual methods at the same time as field embedding. > > Patrick > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Mon Nov 11 23:56:16 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Tue, 12 Nov 2013 16:56:16 +0900 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> Message-ID: <5281DF20.6030500@mozilla.com> On 11/12/13 4:53 PM, Oren Ben-Kiki wrote: > "Your solution does not match the performance of single inheritance, > because it has virtual method calls for every field access from the > "outside" of the trait." > > Sorry, I don't follow. > > Access to members from outside of the traits would require accessing the > concrete type. Since the approach I described used source > transformation, then this would just be a normal data member access, as > efficient as single inheritance. Oh, source transformation. I didn't read closely. That won't work as a replacement for single inheritance because it doesn't provide truly existential types--for example, an array of heterogeneous objects all of which share a common prefix. Patrick From gaetan at xeberon.net Tue Nov 12 00:15:03 2013 From: gaetan at xeberon.net (Gaetan) Date: Tue, 12 Nov 2013 09:15:03 +0100 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> <290552A5-BEB7-4326-B336-FC982D1C60B8@yahoo.com.au> Message-ID: The name itself is "standard", like "it is the default settings"... Le 12 nov. 2013 02:35, "Steven Fackler" a ?crit : > > base64.rs: > > let s = [52, 53, 54].to_base64(STANDARD); > > > > => why adding the "standard" argument? One will ALWAYS want the > "STANDARD" method of creating the base64 representation of some bytes, why > not adding this argument as default. > > That is not true. If you are going to be putting the Base64 encoded data > into a URL you're going to have to use URL_SAFE instead of STANDARD. If > you're trying to send an email, you'll need to use MIME instead of > STANDARD. If you're talking to a service that requires one of the ~10 other > variants of Base64, you'll need to use a custom config struct. > > Steven Fackler > > > On Mon, Nov 11, 2013 at 5:23 PM, Brendan Zabarauskas wrote: > >> On 12 Nov 2013, at 10:12 am, John Clements >> wrote: >> >> > If you had the energy to build an alternate front-end using a >> parenthesized syntax, I'm sure there are others that would give it a try. >> Me, for instance! >> >> It would be nice if we could: >> >> - A: desugar Rust into a small kernel language >> - B: allow rustc to take in some sort of raw AST data (not sure if that?s >> already possible) >> - C: have a way of outputting the AST data in a certain syntax. >> >> That would allow folks like me to have a nice Haskelly syntax as well as >> an s-expr style! >> >> Heh. >> >> ~Brendan >> >> _______________________________________________ >> 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: From oren at ben-kiki.org Tue Nov 12 00:17:49 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Tue, 12 Nov 2013 10:17:49 +0200 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: <5281DF20.6030500@mozilla.com> References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <5281DF20.6030500@mozilla.com> Message-ID: The Rust way to do that would be to have an array of objects that all implement the needed trait. But that would mean that access to the data members would be a "virtual function call", while access to the data members of the new kind of traits you described would be cheap. I think that introducing two kinds of traits would have non-obvious implications on the type system, in addition to saddling us with all the pains of a single-inheritance types hierarchy system. Also, assuming you do introduce two types of traits, for the reason you described, making implementation reuse a feature of _only_ one kind of traits feels very wrong. There should be some way to do reasonable implementation reuse for the current kind of traits as well. You could view the new kind of traits you described as a special case of what I described. In fact you could say that `pub struct Foo : Bar { ... }` means exactly `pub struct Foo { reuse Bar::*; ... }`, and also allow the kind of pointer casts/heterogeneous arrays you are talking about. Or, we could move in the direction of anonymous members, which should also allow for the kind of pointer casts/heterogeneous arrays you want... These would offer a somewhat different tradeoff than the source code transformation approach, so you might like them better :-) On Tue, Nov 12, 2013 at 9:56 AM, Patrick Walton wrote: > On 11/12/13 4:53 PM, Oren Ben-Kiki wrote: > >> "Your solution does not match the performance of single inheritance, >> because it has virtual method calls for every field access from the >> "outside" of the trait." >> >> Sorry, I don't follow. >> >> Access to members from outside of the traits would require accessing the >> concrete type. Since the approach I described used source >> transformation, then this would just be a normal data member access, as >> efficient as single inheritance. >> > > Oh, source transformation. I didn't read closely. That won't work as a > replacement for single inheritance because it doesn't provide truly > existential types--for example, an array of heterogeneous objects all of > which share a common prefix. > > Patrick > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Tue Nov 12 00:28:00 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Tue, 12 Nov 2013 17:28:00 +0900 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <5281DF20.6030500@mozilla.com> Message-ID: <5281E690.1080901@mozilla.com> On 11/12/13 5:17 PM, Oren Ben-Kiki wrote: > I think that introducing two kinds of traits would have non-obvious > implications on the type system Example? > in addition to saddling us with all the > pains of a single-inheritance types hierarchy system. I don't think so. In any case. > Also, assuming you do introduce two types of traits, for the reason you > described, making implementation reuse a feature of _only_ one kind of > traits feels very wrong. There should be some way to do reasonable > implementation reuse for the current kind of traits as well. The general way to do that is to make accessors and mutators in the trait for fields. If we want sugar for accessors and mutators (i.e. properties), then we can cross that bridge later. > You could view the new kind of traits you described as a special case of > what I described. In fact you could say that `pub struct Foo : Bar { ... > }` means exactly `pub struct Foo { reuse Bar::*; ... }`, and also allow > the kind of pointer casts/heterogeneous arrays you are talking about. How would that enforce the prefix property? > Or, we could move in the direction of anonymous members, which should > also allow for the kind of pointer casts/heterogeneous arrays you > want... These would offer a somewhat different tradeoff than the source > code transformation approach, so you might like them better :-) No, they don't work for all the use cases. You cannot downcast with anonymous fields. You also cannot mix them with virtual methods in the Go implementation. Patrick From denis.spir at gmail.com Tue Nov 12 01:53:52 2013 From: denis.spir at gmail.com (spir) Date: Tue, 12 Nov 2013 10:53:52 +0100 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: <5281FAB0.4050602@gmail.com> On 11/11/2013 09:46 PM, Corey Richardson wrote: > I don't think Rust can succeed as a language if it massively differs, > visually, from the language it intends to offset (C++). I don't think Rust can succeed as a language if it massively resembles the language it intends to offset (C++). Denis From illissius at gmail.com Tue Nov 12 01:59:16 2013 From: illissius at gmail.com (=?ISO-8859-1?Q?G=E1bor_Lehel?=) Date: Tue, 12 Nov 2013 10:59:16 +0100 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: <5281FAB0.4050602@gmail.com> References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> <5281FAB0.4050602@gmail.com> Message-ID: Does anyone have empirical data (or even anecdotes) about whether or not C++ hackers find Rust's syntax appealing? :-) On Tue, Nov 12, 2013 at 10:53 AM, spir wrote: > On 11/11/2013 09:46 PM, Corey Richardson wrote: > >> I don't think Rust can succeed as a language if it massively differs, >> visually, from the language it intends to offset (C++). >> > > I don't think Rust can succeed as a language if it massively resembles > > the language it intends to offset (C++). > > Denis > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- Your ship was destroyed in a monadic eruption. -------------- next part -------------- An HTML attachment was scrubbed... URL: From lists at dhardy.name Tue Nov 12 02:35:22 2013 From: lists at dhardy.name (Diggory Hardy) Date: Tue, 12 Nov 2013 11:35:22 +0100 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> <5281FAB0.4050602@gmail.com> Message-ID: <6471572.234dVfOntQ@tph-l10036> My opinion is that clear semantics and good documentation is much more important than familiar syntax. Besides, it's not too closely C++ syntax; for example `let x : T = v` is much closer to Scala's `val x : T = v` than C++'s `T x = v`. (This is a good choice, as anyone who know's why C++ has a `typename` keyword will realise.) But why is this discussion continuing here? The developers have already stated that major type changes are not an option for Rust 1.0. I have been considering some (fairly major) syntax variations myself, but here is not the place; if you want to try out some other syntax then why not write a compiler extension which allows the option of different syntax through a different file extension (e.g. .rs2) or some such switch? I for one am not convinced that pure syntax changes can make that big a difference; far more interesting would be an interactive IDE which lets the programmer write plain English (or restricted English or German or Japanese or whatever you like) and attempts to infer what code is meant. Of course English is not precise enough to specify exact code (without a _lot_ of words), so the interesting part would be how to make the IDE smart enough and interact with the programmer well enough to produce good code easily. (The point of this in the first place is to allow the programmer to write things like "sort this list" or "give me an n*n identity matrix" without expecting the programmer to know in advance how the relevant APIs work.) On Tuesday 12 November 2013 10:59:16 G?bor Lehel wrote: > Does anyone have empirical data (or even anecdotes) about whether or not > C++ hackers find Rust's syntax appealing? :-) > > On Tue, Nov 12, 2013 at 10:53 AM, spir wrote: > > On 11/11/2013 09:46 PM, Corey Richardson wrote: > >> I don't think Rust can succeed as a language if it massively differs, > >> visually, from the language it intends to offset (C++). > > > > I don't think Rust can succeed as a language if it massively resembles > > > > the language it intends to offset (C++). > > > > Denis > > > > _______________________________________________ > > Rust-dev mailing list > > Rust-dev at mozilla.org > > https://mail.mozilla.org/listinfo/rust-dev -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 490 bytes Desc: This is a digitally signed message part. URL: From denis.spir at gmail.com Tue Nov 12 02:46:43 2013 From: denis.spir at gmail.com (spir) Date: Tue, 12 Nov 2013 11:46:43 +0100 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: Message-ID: <52820713.6060001@gmail.com> On 11/11/2013 09:16 PM, Oren Ben-Kiki wrote: > At any rate, I'm not claiming this is necessarily the best approach for > Rust; I'm just wondering, what is the proposed way to address this use > case? None of the manual approaches seems very appealing (unless there's a > better one I missed). My preferred approach is explicite derivation. May look like: struct S1 { x1 : uint, x2 : uint, x3 : uint = 1, x4 : uint = 1, fn f1 () {...}, fn f2 () {...}, } struct S2 [: S1] { // optional subtyping for polymorphism x1 : uint, // same field x2 : uint = 2, // same field, with std value x3 : uint = 1, // same field, same std value x4 : uint = 2, // same field, diff std value x5 : uint, // new field x6 : uint = 2, // new field, with std value fn f1 () = S1.f1, // same func, same value (reuse) fn f2 () {...}, // same func, diff value (override) fn f3 () {...}, // new func } // more structs derived from S1 An advantage is that each new type is completely defined on place; except for the body of reused functions, but one still has the signature and knows where the body is to be found. This apparently brings no novel issue and avoids a few know problems due to conventional "inductive" or "recursive" inheritance. All methods are right here. In theory and practice, I guess, one can well reuse from various existing types any suitable method; or more generally any role, trait, in ordinary sense of the terms. In case of conflict, the user explicitely states which one is intended, and there is no diamond problem. But the main gain in my view is that this scheme provides very good auto-documentation, I guess. I have however no idea of how to implement that in a static lang, esp the subtyping aspect (but do think it's no more complicated, maybe even less) (I implemented it in Lua, rather easy). Denis From gaetan at xeberon.net Tue Nov 12 02:49:18 2013 From: gaetan at xeberon.net (Gaetan) Date: Tue, 12 Nov 2013 11:49:18 +0100 Subject: [rust-dev] Please simplify the syntax for Great Justice In-Reply-To: <6471572.234dVfOntQ@tph-l10036> References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> <5281FAB0.4050602@gmail.com> <6471572.234dVfOntQ@tph-l10036> Message-ID: More concretely, a good ide with completion, the right snippets and contextual help is very helpful for learning new language. I thing this could be a good idea to have an official set of "snippets", typical every day codes, that can be used to create a common contextual helps for editors (vim, sublim,...) When i arrive in a new language, i m used to gather the common "experience" and write some automatisation tool and documentation to have a unique point of entry for all "what should i do in this situation". This covers: - code styling - source organisation - file handling (open/close) - error handling - for python, import lines organisation - argument passing... Le 12 nov. 2013 11:35, "Diggory Hardy" a ?crit : > My opinion is that clear semantics and good documentation is much more > important than familiar syntax. Besides, it's not too closely C++ syntax; > for > example `let x : T = v` is much closer to Scala's `val x : T = v` than > C++'s > `T x = v`. (This is a good choice, as anyone who know's why C++ has a > `typename` keyword will realise.) > > But why is this discussion continuing here? The developers have already > stated > that major type changes are not an option for Rust 1.0. I have been > considering some (fairly major) syntax variations myself, but here is not > the > place; if you want to try out some other syntax then why not write a > compiler > extension which allows the option of different syntax through a different > file > extension (e.g. .rs2) or some such switch? > > I for one am not convinced that pure syntax changes can make that big a > difference; far more interesting would be an interactive IDE which lets the > programmer write plain English (or restricted English or German or > Japanese or > whatever you like) and attempts to infer what code is meant. Of course > English > is not precise enough to specify exact code (without a _lot_ of words), so > the > interesting part would be how to make the IDE smart enough and interact > with > the programmer well enough to produce good code easily. (The point of this > in > the first place is to allow the programmer to write things like "sort this > list" or "give me an n*n identity matrix" without expecting the programmer > to > know in advance how the relevant APIs work.) > > On Tuesday 12 November 2013 10:59:16 G?bor Lehel wrote: > > Does anyone have empirical data (or even anecdotes) about whether or not > > C++ hackers find Rust's syntax appealing? :-) > > > > On Tue, Nov 12, 2013 at 10:53 AM, spir wrote: > > > On 11/11/2013 09:46 PM, Corey Richardson wrote: > > >> I don't think Rust can succeed as a language if it massively differs, > > >> visually, from the language it intends to offset (C++). > > > > > > I don't think Rust can succeed as a language if it massively resembles > > > > > > the language it intends to offset (C++). > > > > > > Denis > > > > > > _______________________________________________ > > > 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: From oren at ben-kiki.org Tue Nov 12 03:18:31 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Tue, 12 Nov 2013 13:18:31 +0200 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: <52820713.6060001@gmail.com> References: <52820713.6060001@gmail.com> Message-ID: It does force one to repeat all the members and all the function signatures, which is (1) pretty tedious and (2) fragile, as making change to the base would require making the same changes "everywhere". The reuse-as-macro idea is to automate this process, so changes would propagate without changing all the places in the code that use the mixin. Another difference is that if f1 invokes f2, in the manual method, f1 will invoke the original f2, while in the reuse-as-macro approach, it would invoke the new f2. Otherwise, this is basically the same thing, only manual. Oren. On Tue, Nov 12, 2013 at 12:46 PM, spir wrote: > On 11/11/2013 09:16 PM, Oren Ben-Kiki wrote: > >> At any rate, I'm not claiming this is necessarily the best approach for >> Rust; I'm just wondering, what is the proposed way to address this use >> case? None of the manual approaches seems very appealing (unless there's a >> better one I missed). >> > > My preferred approach is explicite derivation. May look like: > > struct S1 { > x1 : uint, > x2 : uint, > x3 : uint = 1, > x4 : uint = 1, > > fn f1 () {...}, > fn f2 () {...}, > } > > struct S2 [: S1] { // optional subtyping for polymorphism > x1 : uint, // same field > x2 : uint = 2, // same field, with std value > x3 : uint = 1, // same field, same std value > x4 : uint = 2, // same field, diff std value > x5 : uint, // new field > x6 : uint = 2, // new field, with std value > > fn f1 () = S1.f1, // same func, same value (reuse) > fn f2 () {...}, // same func, diff value (override) > fn f3 () {...}, // new func > } > > // more structs derived from S1 > > An advantage is that each new type is completely defined on place; except > for the body of reused functions, but one still has the signature and knows > where the body is to be found. > > This apparently brings no novel issue and avoids a few know problems due > to conventional "inductive" or "recursive" inheritance. All methods are > right here. In theory and practice, I guess, one can well reuse from > various existing types any suitable method; or more generally any role, > trait, in ordinary sense of the terms. In case of conflict, the user > explicitely states which one is intended, and there is no diamond problem. > > But the main gain in my view is that this scheme provides very good > auto-documentation, I guess. I have however no idea of how to implement > that in a static lang, esp the subtyping aspect (but do think it's no more > complicated, maybe even less) (I implemented it in Lua, rather easy). > > Denis > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From denis.spir at gmail.com Tue Nov 12 04:24:52 2013 From: denis.spir at gmail.com (spir) Date: Tue, 12 Nov 2013 13:24:52 +0100 Subject: [rust-dev] linking to cells inside a data structure Message-ID: <52821E14.5010509@gmail.com> Hello Rust people, A data structure holds (unpointed) cells in an array. Then, a number of linked lists part of the data structure link to those same cells. What is the right Rust way to do that? I cannot have the language accept the instruction establishing a link, whatever kind of pointer I use (both for self and for cells). Code and/or details on demand. Denis PS: It is in fact a hash table [1] which buckets are link lists as usually, but the cells are stored in an array instead of spread around the memory at the allocator's convenience ;-). First advantage is indeed entries are in order. (To move on in the meanwhile, I'll remove this aspect.) [1] Actually a "mod table" since keys are uints, there is no hash, only modulo. From cadencemarseille at gmail.com Tue Nov 12 04:41:50 2013 From: cadencemarseille at gmail.com (Cadence Marseille) Date: Tue, 12 Nov 2013 07:41:50 -0500 Subject: [rust-dev] Interest in OptionStr? Message-ID: Hi, I was thinking about a small enhancement for Option objects where S: Str that would add a utility method for returning a slice option. There is some code in rust-pcre, https://github.com/cadencemarseille/rust-pcre/blob/d833054/src/pcre/mod.rs#L137, that I think illustrates what I am trying to achieve. I want to use pattern matching, but both of these versions fail to compile: match self.opt_err { None => format!("compilation failed at offset {:u}", self.erroffset as uint), Some(s) => format!("compilation failed at offset {:u}: {:s}", self.erroffset as uint, s) } (error: cannot move out of dereference of & pointer). Makes sense. This is fixed by clone()ing self.opt_err. match self.opt_err.clone().map(|s| s.as_slice()) { None => format!("compilation failed at offset {:u}", self.erroffset as uint), Some(s) => format!("compilation failed at offset {:u}: {:s}", self.erroffset as uint, s) } (error: borrowed value does not live long enough). Also makes sense. I want to avoid the clone(), so I thought that maybe an additional utility method is needed to return a slice option given an Option. I have tried this idea out with: use std::option::Option; trait OptionStr { fn as_slice<'a>(&'a self) -> Option<&'a str>; } impl OptionStr for Option { #[inline] fn as_slice<'a>(&'a self) -> Option<&'a str> { match *self { Some(ref s) => Some(s.as_slice()), None => None } } } fn main() { let opt_str = Some(~"hello world!"); match opt_str.as_slice() { Some(s) => println(s), None => return } } I don't think that the OptionStr would need an into_owned() method (like Str.into_owned()) because that can be done with map: opt_str.map(|s| s.into_owned()). Does this sound like a good idea? I can put together a Pull Request if there is interest in this. Cadence -------------- next part -------------- An HTML attachment was scrubbed... URL: From oren at ben-kiki.org Tue Nov 12 04:51:53 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Tue, 12 Nov 2013 14:51:53 +0200 Subject: [rust-dev] linking to cells inside a data structure In-Reply-To: <52821E14.5010509@gmail.com> References: <52821E14.5010509@gmail.com> Message-ID: I have been struggling with variants of this for a while and there's no "best" solution. First, if the array holds values (as opposed to pointers to values), then pretty much your only option is to replace your pointers with indices to the array. You'd need access to the container to access the values, of course. But this is the only safe way because adding into the array may relocate it, invalidating all pointers. If your array holds pointers, then you can do something; e.g., store Rc in the array cells and also in the places you want to link to the values. If reference cycles are an issue you can use @T instead of Rc (keep in mind this will change to Gc or something in the future). If sending the whole thing is an issue, you are pretty much forced to use Arc (and forget about reference cycles). And, of course, each of these (Rc, @, Arc) has a different name if you want mutation (RcMut, @mut, ArcRW). In performance-critical code I sometimes give up and just have an array of ~T and use an unsafe ptr to T in all my other references... which is OK as long as these only live as long as the container, but I get zero compiler support for that. I wish there was a way to say "this borrowed pointer lives only as long as its container". That doesn't seem to be in the cards though :-( On Tue, Nov 12, 2013 at 2:24 PM, spir wrote: > Hello Rust people, > > A data structure holds (unpointed) cells in an array. Then, a number of > linked lists part of the data structure link to those same cells. What is > the right Rust way to do that? I cannot have the language accept the > instruction establishing a link, whatever kind of pointer I use (both for > self and for cells). > > Code and/or details on demand. > > Denis > > PS: It is in fact a hash table [1] which buckets are link lists as > usually, but the cells are stored in an array instead of spread around the > memory at the allocator's convenience ;-). First advantage is indeed > entries are in order. > (To move on in the meanwhile, I'll remove this aspect.) > > [1] Actually a "mod table" since keys are uints, there is no hash, only > modulo. > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From micah at micahchalmer.net Tue Nov 12 05:01:42 2013 From: micah at micahchalmer.net (Micah Chalmer) Date: Tue, 12 Nov 2013 08:01:42 -0500 Subject: [rust-dev] Interest in OptionStr? In-Reply-To: References: Message-ID: This will work for your pattern match without cloning: match self.opt_err { None => format!("compilation failed at offset {:u}", self.erroffset as uint), Some(ref s) => format!("compilation failed at offset {:u}: {:s}", self.erroffset as uint, *s) } It takes a reference to the string instead of moving it. You end up with a pointer to a pointer (&~) which is why you have to explicitly dereference it when you use it. -Micah On Nov 12, 2013, at 7:41 AM, Cadence Marseille wrote: > Hi, > > I was thinking about a small enhancement for Option objects where S: Str that would add a utility method for returning a slice option. > > There is some code in rust-pcre, https://github.com/cadencemarseille/rust-pcre/blob/d833054/src/pcre/mod.rs#L137, that I think illustrates what I am trying to achieve. I want to use pattern matching, but both of these versions fail to compile: > > match self.opt_err { > None => format!("compilation failed at offset {:u}", self.erroffset as uint), > Some(s) => format!("compilation failed at offset {:u}: {:s}", self.erroffset as uint, s) > } > > (error: cannot move out of dereference of & pointer). Makes sense. This is fixed by clone()ing self.opt_err. > > match self.opt_err.clone().map(|s| s.as_slice()) { > None => format!("compilation failed at offset {:u}", self.erroffset as uint), > Some(s) => format!("compilation failed at offset {:u}: {:s}", self.erroffset as uint, s) > } > > (error: borrowed value does not live long enough). Also makes sense. > > I want to avoid the clone(), so I thought that maybe an additional utility method is needed to return a slice option given an Option. > > I have tried this idea out with: > > use std::option::Option; > > trait OptionStr { > fn as_slice<'a>(&'a self) -> Option<&'a str>; > } > > impl OptionStr for Option { > #[inline] > fn as_slice<'a>(&'a self) -> Option<&'a str> { > match *self { > Some(ref s) => Some(s.as_slice()), > None => None > } > } > } > > fn main() { > let opt_str = Some(~"hello world!"); > match opt_str.as_slice() { > Some(s) => println(s), > None => return > } > } > > I don't think that the OptionStr would need an into_owned() method (like Str.into_owned()) because that can be done with map: opt_str.map(|s| s.into_owned()). > > Does this sound like a good idea? I can put together a Pull Request if there is interest in this. > > Cadence > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Tue Nov 12 05:13:09 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Tue, 12 Nov 2013 22:13:09 +0900 Subject: [rust-dev] linking to cells inside a data structure In-Reply-To: References: <52821E14.5010509@gmail.com> Message-ID: <52822965.7090004@mozilla.com> On 11/12/13 9:51 PM, Oren Ben-Kiki wrote: > If sending the whole thing is an issue, you are pretty much forced to > use Arc (and forget about reference cycles). And, of course, each of > these (Rc, @, Arc) has a different name if you want mutation (RcMut, > @mut, ArcRW). I think having to choose between thread-safe and non-thread-safe reference counting is just part of systems programming. But the mutation part is painful. I'd like to move most code that uses `@mut` and friends to the `Slot` pattern that I'm starting to use in Servo, whereby you wrap individual fields in `Slot`s and just use `.get()` and `.set()`, instead of making the entire object mutable. So for example: struct MyObject { x: Slot, y: Slot, } let obj = Rc::new(MyObject { x: Slot::init(1), y: Slot::init(2), }); println!("{} {}", obj.x.get(), obj.y.get()); obj.x.set(obj.x.get() * 2); obj.y.set(obj.y.get() * 3); The biggest nice thing about this is that you don't have to worry about all of those dynamic borrow failures. (Slots support borrowing in case you have to have a reference to the value for some reason, but `.get()` and `.set()` are preferred, as sticking to those will prevent you from ever having dynamic borrow check failures.) The other nice thing is you don't have to use separate mutable smart pointers. You can write `Rc` instead of `RcMut`. > In performance-critical code I sometimes give up and just have an array > of ~T and use an unsafe ptr to T in all my other references... which is > OK as long as these only live as long as the container, but I get zero > compiler support for that. I wish there was a way to say "this borrowed > pointer lives only as long as its container". That doesn't seem to be in > the cards though :-( I don't know how to make that sound, unfortunately, other than using an arena and allocating all the nodes into it (losing the ability to deallocate individual nodes). Patrick From oren at ben-kiki.org Tue Nov 12 05:27:18 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Tue, 12 Nov 2013 15:27:18 +0200 Subject: [rust-dev] linking to cells inside a data structure In-Reply-To: <52822965.7090004@mozilla.com> References: <52821E14.5010509@gmail.com> <52822965.7090004@mozilla.com> Message-ID: Yes, you lose the ability to deallocate individual nodes. Pretty hard to express in a type system. Still I wish I could at least have the compiler help me to ensure my unsafe pointers never escape the lifetime of the container; right now I must trust the programmer (and in my case, the container basically lives as long as the program, anyway). Slots sound nice. Is the idea that one would do Rc for read-only access and Rc> for mutable access? How does this protect against multiple mutations "at once"? On Tue, Nov 12, 2013 at 3:13 PM, Patrick Walton wrote: > >> In performance-critical code I sometimes give up and just have an array >> of ~T and use an unsafe ptr to T in all my other references... which is >> OK as long as these only live as long as the container, but I get zero >> compiler support for that. I wish there was a way to say "this borrowed >> pointer lives only as long as its container". That doesn't seem to be in >> the cards though :-( >> > > I don't know how to make that sound, unfortunately, other than using an > arena and allocating all the nodes into it (losing the ability to > deallocate individual nodes). > > Patrick > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From denis.spir at gmail.com Tue Nov 12 05:52:47 2013 From: denis.spir at gmail.com (spir) Date: Tue, 12 Nov 2013 14:52:47 +0100 Subject: [rust-dev] copying pointers Message-ID: <528232AF.40906@gmail.com> Hello, The ref manual speaks of copying pointers [http://static.rust-lang.org/doc/0.8/rust.html#pointer-types]: << Managed pointers (@) These point to managed heap allocations (or "boxes") in the task-local, managed heap. Managed pointers are written @content, for example @int means a managed pointer to a managed box containing an integer. Copying a managed pointer is a "shallow" operation: it involves only copying the pointer itself (as well as any reference-count or GC-barriers required by the managed heap). Dropping a managed pointer does not necessarily release the box it points to; the lifecycles of managed boxes are subject to an unspecified garbage collection algorithm. Owning pointers (~) These point to owned heap allocations (or "boxes") in the shared, inter-task heap. Each owned box has a single owning pointer; pointer and pointee retain a 1:1 relationship at all times. Owning pointers are written ~content, for example ~int means an owning pointer to an owned box containing an integer. Copying an owned box is a "deep" operation: it involves allocating a new owned box and copying the contents of the old box into the new box. Releasing an owning pointer immediately releases its corresponding owned box. Borrowed pointers (&) These point to memory owned by some other value. Borrowed pointers arise by (automatic) conversion from owning pointers, managed pointers, or by applying the borrowing operator & to some other value, including lvalues, rvalues or temporaries. Borrowed pointers are written &content, or in some cases &f/content for some lifetime-variable f, for example &int means a borrowed pointer to an integer. Copying a borrowed pointer is a "shallow" operation: it involves only copying the pointer itself. Releasing a borrowed pointer typically has no effect on the value it points to, with the exception of temporary values, which are released when the last borrowed pointer to them is released. >> But what is the syntax to do that? I always get errors related to moving, which i don' twant to do. In particular, how does one establish or modify link list links? Denis From cadencemarseille at gmail.com Tue Nov 12 05:58:51 2013 From: cadencemarseille at gmail.com (Cadence Marseille) Date: Tue, 12 Nov 2013 08:58:51 -0500 Subject: [rust-dev] Interest in OptionStr? In-Reply-To: References: Message-ID: Thank you, Micah. Your suggestion and L?o Testard's suggestion using s.as_slice() (emailed off-list) work well. Cadence On Tue, Nov 12, 2013 at 8:01 AM, Micah Chalmer wrote: > This will work for your pattern match without cloning: > > match self.opt_err { > None => format!("compilation failed at offset {:u}", > self.erroffset as uint), > Some(ref s) => format!("compilation failed at offset {:u}: > {:s}", self.erroffset as uint, *s) > } > > It takes a reference to the string instead of moving it. You end up with > a pointer to a pointer (&~) which is why you have to explicitly dereference > it when you use it. > > -Micah > > On Nov 12, 2013, at 7:41 AM, Cadence Marseille > wrote: > > Hi, > > I was thinking about a small enhancement for Option objects where S: > Str that would add a utility method for returning a slice option. > > There is some code in rust-pcre, > https://github.com/cadencemarseille/rust-pcre/blob/d833054/src/pcre/mod.rs#L137, > that I think illustrates what I am trying to achieve. I want to use > pattern matching, but both of these versions fail to compile: > > match self.opt_err { > None => format!("compilation failed at offset {:u}", > self.erroffset as uint), > Some(s) => format!("compilation failed at offset {:u}: {:s}", > self.erroffset as uint, s) > } > > (error: cannot move out of dereference of & pointer). Makes sense. This > is fixed by clone()ing self.opt_err. > > match self.opt_err.clone().map(|s| s.as_slice()) { > None => format!("compilation failed at offset {:u}", > self.erroffset as uint), > Some(s) => format!("compilation failed at offset {:u}: {:s}", > self.erroffset as uint, s) > } > > (error: borrowed value does not live long enough). Also makes sense. > > I want to avoid the clone(), so I thought that maybe an additional utility > method is needed to return a slice option given an Option. > > I have tried this idea out with: > > use std::option::Option; > > trait OptionStr { > fn as_slice<'a>(&'a self) -> Option<&'a str>; > } > > impl OptionStr for Option { > #[inline] > fn as_slice<'a>(&'a self) -> Option<&'a str> { > match *self { > Some(ref s) => Some(s.as_slice()), > None => None > } > } > } > > fn main() { > let opt_str = Some(~"hello world!"); > match opt_str.as_slice() { > Some(s) => println(s), > None => return > } > } > > I don't think that the OptionStr would need an into_owned() method (like > Str.into_owned()) > because that can be done with map: opt_str.map(|s| s.into_owned()). > > Does this sound like a good idea? I can put together a Pull Request if > there is interest in this. > > Cadence > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From leo.testard at gmail.com Tue Nov 12 06:01:11 2013 From: leo.testard at gmail.com (=?iso-8859-1?Q?L=E9o_Testard?=) Date: Tue, 12 Nov 2013 15:01:11 +0100 Subject: [rust-dev] Interest in OptionStr? In-Reply-To: References: Message-ID: <248BC260-A6D9-49C8-B161-C98FDC6D6827@gmail.com> Hello Sorry for the mail being sent off-list. Here's what I suggested in case it helps somebody else: match opt_err { None => format!("compilation failed at offset {:u}", 0u), Some(ref s) => format!("compilation failed at offset {:u}: {:s}", 0u, s.as_slice()) }; Le 12 nov. 2013 ? 14:58, Cadence Marseille a ?crit : > Thank you, Micah. Your suggestion and L?o Testard's suggestion using s.as_slice() (emailed off-list) work well. > > Cadence > > > On Tue, Nov 12, 2013 at 8:01 AM, Micah Chalmer wrote: > This will work for your pattern match without cloning: > > match self.opt_err { > None => format!("compilation failed at offset {:u}", self.erroffset as uint), > Some(ref s) => format!("compilation failed at offset {:u}: {:s}", self.erroffset as uint, *s) > } > > It takes a reference to the string instead of moving it. You end up with a pointer to a pointer (&~) which is why you have to explicitly dereference it when you use it. > > -Micah > > On Nov 12, 2013, at 7:41 AM, Cadence Marseille wrote: > >> Hi, >> >> I was thinking about a small enhancement for Option objects where S: Str that would add a utility method for returning a slice option. >> >> There is some code in rust-pcre, https://github.com/cadencemarseille/rust-pcre/blob/d833054/src/pcre/mod.rs#L137, that I think illustrates what I am trying to achieve. I want to use pattern matching, but both of these versions fail to compile: >> >> match self.opt_err { >> None => format!("compilation failed at offset {:u}", self.erroffset as uint), >> Some(s) => format!("compilation failed at offset {:u}: {:s}", self.erroffset as uint, s) >> } >> >> (error: cannot move out of dereference of & pointer). Makes sense. This is fixed by clone()ing self.opt_err. >> >> match self.opt_err.clone().map(|s| s.as_slice()) { >> None => format!("compilation failed at offset {:u}", self.erroffset as uint), >> Some(s) => format!("compilation failed at offset {:u}: {:s}", self.erroffset as uint, s) >> } >> >> (error: borrowed value does not live long enough). Also makes sense. >> >> I want to avoid the clone(), so I thought that maybe an additional utility method is needed to return a slice option given an Option. >> >> I have tried this idea out with: >> >> use std::option::Option; >> >> trait OptionStr { >> fn as_slice<'a>(&'a self) -> Option<&'a str>; >> } >> >> impl OptionStr for Option { >> #[inline] >> fn as_slice<'a>(&'a self) -> Option<&'a str> { >> match *self { >> Some(ref s) => Some(s.as_slice()), >> None => None >> } >> } >> } >> >> fn main() { >> let opt_str = Some(~"hello world!"); >> match opt_str.as_slice() { >> Some(s) => println(s), >> None => return >> } >> } >> >> I don't think that the OptionStr would need an into_owned() method (like Str.into_owned()) because that can be done with map: opt_str.map(|s| s.into_owned()). >> >> Does this sound like a good idea? I can put together a Pull Request if there is interest in this. >> >> Cadence >> _______________________________________________ >> 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: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: Message signed with OpenPGP using GPGMail URL: From denis.spir at gmail.com Tue Nov 12 06:06:59 2013 From: denis.spir at gmail.com (spir) Date: Tue, 12 Nov 2013 15:06:59 +0100 Subject: [rust-dev] copying pointers In-Reply-To: <528232AF.40906@gmail.com> References: <528232AF.40906@gmail.com> Message-ID: <52823603.1030901@gmail.com> PS: What would be, in fact, the rusty way for a simplissim linked list. I use Option<~Cell> for now, to have something clean (None) to end the list, since Rust looks rather functional. But as always with Option this way quite obscures and complicates the code (Some() expressions, match expressions...). I'd rather just use a NULL pointer, for here it is fully safe. But this does not look rusty at all, I guess. What is your view? Denis From oren at ben-kiki.org Tue Nov 12 06:21:08 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Tue, 12 Nov 2013 16:21:08 +0200 Subject: [rust-dev] copying pointers In-Reply-To: <52823603.1030901@gmail.com> References: <528232AF.40906@gmail.com> <52823603.1030901@gmail.com> Message-ID: For linked lists with no cycles, why not use Option> (or RcMut)? On Tue, Nov 12, 2013 at 4:06 PM, spir wrote: > PS: What would be, in fact, the rusty way for a simplissim linked list. I > use Option<~Cell> for now, to have something clean (None) to end the list, > since Rust looks rather functional. But as always with Option this way > quite obscures and complicates the code (Some() expressions, match > expressions...). I'd rather just use a NULL pointer, for here it is fully > safe. But this does not look rusty at all, I guess. > What is your view? > > > Denis > > > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From corey at octayn.net Tue Nov 12 08:11:42 2013 From: corey at octayn.net (Corey Richardson) Date: Tue, 12 Nov 2013 11:11:42 -0500 Subject: [rust-dev] copying pointers In-Reply-To: <528232AF.40906@gmail.com> References: <528232AF.40906@gmail.com> Message-ID: #[feature(managed_boxes)]; #[deriving(Clone)] struct Foo; impl Drop for Foo { fn drop(&mut self) { } } fn main() { let x = ~Foo; let y = @Foo; let _z = Foo; let z = &_z; // needs a clone since just `a = x` would be a move let a: ~Foo = x.clone(); // just copies the pointer (and bumps the refcount) let b: @Foo = y; // copies the pointer let c = z; // *NOT* allowed; would be a move out of a borrowed pointer, which is not allowed since borrowed // pointers don't have ownership. // let d = *z; } On Tue, Nov 12, 2013 at 8:52 AM, spir wrote: > Hello, > > The ref manual speaks of copying pointers > [http://static.rust-lang.org/doc/0.8/rust.html#pointer-types]: > > << > Managed pointers (@) > These point to managed heap allocations (or "boxes") in the task-local, > managed heap. Managed pointers are written @content, for example @int means > a managed pointer to a managed box containing an integer. Copying a managed > pointer is a "shallow" operation: it involves only copying the pointer > itself (as well as any reference-count or GC-barriers required by the > managed heap). Dropping a managed pointer does not necessarily release the > box it points to; the lifecycles of managed boxes are subject to an > unspecified garbage collection algorithm. > > Owning pointers (~) > These point to owned heap allocations (or "boxes") in the shared, > inter-task heap. Each owned box has a single owning pointer; pointer and > pointee retain a 1:1 relationship at all times. Owning pointers are written > ~content, for example ~int means an owning pointer to an owned box > containing an integer. Copying an owned box is a "deep" operation: it > involves allocating a new owned box and copying the contents of the old box > into the new box. Releasing an owning pointer immediately releases its > corresponding owned box. > > Borrowed pointers (&) > These point to memory owned by some other value. Borrowed pointers arise > by (automatic) conversion from owning pointers, managed pointers, or by > applying the borrowing operator & to some other value, including lvalues, > rvalues or temporaries. Borrowed pointers are written &content, or in some > cases &f/content for some lifetime-variable f, for example &int means a > borrowed pointer to an integer. Copying a borrowed pointer is a "shallow" > operation: it involves only copying the pointer itself. Releasing a borrowed > pointer typically has no effect on the value it points to, with the > exception of temporary values, which are released when the last borrowed > pointer to them is released. >>> >>> > > But what is the syntax to do that? I always get errors related to moving, > which i don' twant to do. In particular, how does one establish or modify > link list links? > > Denis > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From thadguidry at gmail.com Tue Nov 12 09:11:31 2013 From: thadguidry at gmail.com (Thad Guidry) Date: Tue, 12 Nov 2013 11:11:31 -0600 Subject: [rust-dev] RosettaCode.org and Color of a Screen Pixel Message-ID: Curious if Rust has a way to get the Color of a Screen Pixel yet ? http://rosettacode.org/wiki/Color_of_a_screen_pixel -- -Thad +ThadGuidry Thad on LinkedIn -------------- next part -------------- An HTML attachment was scrubbed... URL: From tiffany at stormbit.net Tue Nov 12 09:15:58 2013 From: tiffany at stormbit.net (Tiffany Bennett) Date: Tue, 12 Nov 2013 12:15:58 -0500 Subject: [rust-dev] Fwd: Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: On Mon, Nov 11, 2013 at 4:07 PM, Greg wrote: > I think it's still possible to simplify Rust's existing syntax while > maintaining the features it offers. > You haven't actually explained which syntax you want to remove. > I'm almost certain that the answer is "no" (partly because these > languages/dialects did not exist at the time). > The language is very similar in semantics to OCaml, to say that Rust is only inspired by C++ would be a lie. What about Lua, which is more C-like? > You've obviously never used Lua, it's nothing like C. Or CoffeeScript? > Coffeescript is the exact opposite of what you ask - it's a superset of javascript that adds some syntax sugar. The fact it compiles to very readable javascript is a testament to this. > The list contains some bad role models (in terms of syntactic elegance and > simplicity): C++, Haskell, OCaml, and Ruby. > I seriously doubt your taste in syntax if you think Haskell and OCaml are undesirable. > Thankfully Common Lisp is mentioned. Although, of the Lisps I'm familiar > with, Common Lisp has the ugliest syntax (still better than C++ though). > You are clearly misusing the word "syntax"... Common lisp's syntax consists of only S-exprs and the quote sugar, as other lisps do. This is all to say that, from what I can tell, simplicity and elegance of > syntax was not a design requirement (or goal) that the Rust developers had > in mind. > The goal of Rust was to produce a type-safe, memory-safe, programmer-safe programming language, in the niche of system's languages. And I think that's quite unfortunate for Rust. > It's quite unfortunate that the language doesn't abide by your nebulous, sparsely defined ideas of what a "good" language looks like? > I'm sorry I was not able to provide this feedback years ago when it might > have been more helpful. I only recently became aware of Rust. > I doubt it would have been taken seriously then. > - Greg > > -- > Please do not email me anything that you are not comfortable also sharing > with the NSA. > > On Nov 11, 2013, at 3:46 PM, Corey Richardson wrote: > > On Mon, Nov 11, 2013 at 3:41 PM, Greg wrote: > > At this state in Rust's development, we are unlikely to make any major > changes to Rust's syntax. > > > *cries* > > > I don't think Rust can succeed as a language if it massively differs, > visually, from the language it intends to offset (C++). > > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From corey at octayn.net Tue Nov 12 09:20:34 2013 From: corey at octayn.net (Corey Richardson) Date: Tue, 12 Nov 2013 12:20:34 -0500 Subject: [rust-dev] RosettaCode.org and Color of a Screen Pixel In-Reply-To: References: Message-ID: With the xlib bindings it'd look a lot like the C version. On Tue, Nov 12, 2013 at 12:11 PM, Thad Guidry wrote: > Curious if Rust has a way to get the Color of a Screen Pixel yet ? > > http://rosettacode.org/wiki/Color_of_a_screen_pixel > > -- > -Thad > +ThadGuidry > Thad on LinkedIn > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > From greg at kinostudios.com Tue Nov 12 09:37:33 2013 From: greg at kinostudios.com (Greg) Date: Tue, 12 Nov 2013 12:37:33 -0500 Subject: [rust-dev] Fwd: Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: <21D511A4-ADC2-4D2E-BD65-FDF93AB8AEEB@kinostudios.com> On Nov 12, 2013, at 12:15 PM, Tiffany Bennett wrote: > [.. a bunch of flamebait ..] Sorry, not gonna bite. I think there was one reply-worthy comment buried in there, perhaps a tacit request for remove-worthy syntax examples? I can point out syntax that I don't like, but I think it'd be more productive to simultaneously offer alternatives, and I haven't studied Rust in enough depth to where I'd be comfortable doing that. Here are some areas that caught my eye in the Doc-language-FAQ on Github. If I were to start using Rust, I'd research these in more depth to try and simplify the syntax: 1. ~[Option>] 2. fn linear_map_with_capacity(capacity: uint) -> LinearMap 3. fn contains_key(&self, k: &K) My approach would be to try and get rid of templates through better type inference in the compiler. I'd introduce the common brace literal syntax for maps that can be found in JS and elsewhere, and perhaps additional literal syntax (ala ObjC + Clojure). I'd also look at the symbols '~', '@', and '&', and see what could be done to remove or simplify those. I'd look to see whether ARC could be used instead of garbage collection, and whether that would have an impact on syntax or not. There's also the question of whether symbols (ala Lisp/Scheme/Clojure) could be useful in simplifying the language and making it more versatile. Finally, if all else fails, I'd go for broke and S-expr the whole thing. :-p - Greg P.S. Accusing me of lying, and then misrepresenting what I said, is not going to take this conversation down a productive path. You'll probably just end up getting ignored (or worse). -- Please do not email me anything that you are not comfortable also sharing with the NSA. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 495 bytes Desc: Message signed with OpenPGP using GPGMail URL: From catamorphism at gmail.com Tue Nov 12 09:43:53 2013 From: catamorphism at gmail.com (Tim Chevalier) Date: Tue, 12 Nov 2013 09:43:53 -0800 Subject: [rust-dev] Closing this thread [Was: Re: Fwd: Please simplify the syntax for Great Justice] Message-ID: Hi folks -- I already requested that this thread end, and from here on I'm going to place anyone who replies to this thread further (with the same subject line or quoting anything from the same thread) on temporary moderation. For any specific discussion about Rust that originates from this thread, you're welcome to start a new thread about it with a new subject line. Tim (list co-moderator) On Tue, Nov 12, 2013 at 9:37 AM, Greg wrote: > On Nov 12, 2013, at 12:15 PM, Tiffany Bennett wrote: >> [.. a bunch of flamebait ..] > > Sorry, not gonna bite. > > I think there was one reply-worthy comment buried in there, perhaps a tacit request for remove-worthy syntax examples? > > I can point out syntax that I don't like, but I think it'd be more productive to simultaneously offer alternatives, and I haven't studied Rust in enough depth to where I'd be comfortable doing that. > > Here are some areas that caught my eye in the Doc-language-FAQ on Github. If I were to start using Rust, I'd research these in more depth to try and simplify the syntax: > > 1. ~[Option>] > > 2. fn linear_map_with_capacity(capacity: uint) -> LinearMap > > 3. fn contains_key(&self, k: &K) > > My approach would be to try and get rid of templates through better type inference in the compiler. I'd introduce the common brace literal syntax for maps that can be found in JS and elsewhere, and perhaps additional literal syntax (ala ObjC + Clojure). > > I'd also look at the symbols '~', '@', and '&', and see what could be done to remove or simplify those. > > I'd look to see whether ARC could be used instead of garbage collection, and whether that would have an impact on syntax or not. > > There's also the question of whether symbols (ala Lisp/Scheme/Clojure) could be useful in simplifying the language and making it more versatile. > > Finally, if all else fails, I'd go for broke and S-expr the whole thing. :-p > > - Greg > > P.S. Accusing me of lying, and then misrepresenting what I said, is not going to take this conversation down a productive path. You'll probably just end up getting ignored (or worse). > > -- > Please do not email me anything that you are not comfortable also sharing with the NSA. > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt "If you are silent about your pain, they'll kill you and say you enjoyed it." -- Zora Neale Hurston From tiffany at stormbit.net Tue Nov 12 10:00:43 2013 From: tiffany at stormbit.net (Tiffany Bennett) Date: Tue, 12 Nov 2013 13:00:43 -0500 Subject: [rust-dev] Fwd: Please simplify the syntax for Great Justice In-Reply-To: <21D511A4-ADC2-4D2E-BD65-FDF93AB8AEEB@kinostudios.com> References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> <21D511A4-ADC2-4D2E-BD65-FDF93AB8AEEB@kinostudios.com> Message-ID: On Tue, Nov 12, 2013 at 12:37 PM, Greg wrote: > On Nov 12, 2013, at 12:15 PM, Tiffany Bennett > wrote: > > [.. a bunch of flamebait ..] > > Sorry, not gonna bite. > > I think there was one reply-worthy comment buried in there, perhaps a > tacit request for remove-worthy syntax examples? > > I can point out syntax that I don't like, but I think it'd be more > productive to simultaneously offer alternatives, and I haven't studied Rust > in enough depth to where I'd be comfortable doing that. > > Here are some areas that caught my eye in the Doc-language-FAQ on Github. > If I were to start using Rust, I'd research these in more depth to try and > simplify the syntax: > > 1. ~[Option>] > > 2. fn linear_map_with_capacity(capacity: uint) -> > LinearMap > > 3. fn contains_key(&self, k: &K) > > My approach would be to try and get rid of templates through better type > inference in the compiler. I'd introduce the common brace literal syntax > for maps that can be found in JS and elsewhere, and perhaps additional > literal syntax (ala ObjC + Clojure). > Type inference for function signatures leads to programmer errors where it infers the wrong type. You seem to have the idea that much of this syntax is unnecessary, when it really is - all of it is important to specifying exactly what you mean. In a system's language like Rust, there are a lot of things that you could mean. You should try providing real examples of how you could simplify the examples you provided. > I'd also look at the symbols '~', '@', and '&', and see what could be done > to remove or simplify those. > Anything you do to simplify Rust's memory management will be of detriment to the language, because it is an important part of Rust's ability to function as a system's language. Each of those symbols has an important meaning in regards to memory management - ~ being RAII-like, @ being garbage collected (and now behind a feature gate while everyone figures out whether to keep the symbol or just use RC/GC), & is a way to take temporary references to something. > I'd look to see whether ARC could be used instead of garbage collection, > and whether that would have an impact on syntax or not. > ARC /is/ garbage collection. It's an atomic reference counter that can be sent between tasks. > There's also the question of whether symbols (ala Lisp/Scheme/Clojure) > could be useful in simplifying the language and making it more versatile. > > Finally, if all else fails, I'd go for broke and S-expr the whole thing. > :-p > I've tried implementing an S-expr based language myself, and the benefits are really not as great as they first seem. One thing you eventually realize is that although lisp has an incredible macro system, needing macros in the first place is often a sign of a type system that isn't powerful enough to express many concepts. Do you often see macros used in languages like Haskell or Idris? > - Greg > > P.S. Accusing me of lying, and then misrepresenting what I said, is not > going to take this conversation down a productive path. You'll probably > just end up getting ignored (or worse). > > -- > Please do not email me anything that you are not comfortable also sharing > with the NSA. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From tiffany at stormbit.net Tue Nov 12 10:03:56 2013 From: tiffany at stormbit.net (Tiffany Bennett) Date: Tue, 12 Nov 2013 13:03:56 -0500 Subject: [rust-dev] Fwd: Please simplify the syntax for Great Justice In-Reply-To: References: <7548192E-7C36-4AF2-8338-D62AC26E3A16@kinostudios.com> Message-ID: Sorry, I did go a bit overboard On Tue, Nov 12, 2013 at 12:48 PM, Tim Chevalier wrote: > Hey Tiffany -- > > Just wanted to let you know that I thought this was a totally > appropriate email on your part :-) Normally I would warn about the > code of conduct, but tbh, in this case I think Greg deserved it. > > Just my opinion, of course, and not the official opinion of the team :-) > > That said, when you want to shut people down in the future (a role > that is very much needed given the number of cranks that Rust > attracts, especially now that neither I nor Graydon will be mods after > this week), try to do it in a way that you can argue is "kind and > courteous" (as per the conduct section of > https://github.com/mozilla/rust/wiki/Note-development-policy ), so > that the other list mods will have no reason to criticize it :-) > > Cheers, > Tim > > > On Tue, Nov 12, 2013 at 9:15 AM, Tiffany Bennett > wrote: > > On Mon, Nov 11, 2013 at 4:07 PM, Greg wrote: > >> > >> I think it's still possible to simplify Rust's existing syntax while > >> maintaining the features it offers. > > > > > > You haven't actually explained which syntax you want to remove. > > > >> > >> I'm almost certain that the answer is "no" (partly because these > >> languages/dialects did not exist at the time). > > > > > > The language is very similar in semantics to OCaml, to say that Rust is > only > > inspired by C++ would be a lie. > > > >> What about Lua, which is more C-like? > > > > > > You've obviously never used Lua, it's nothing like C. > > > >> Or CoffeeScript? > > > > > > Coffeescript is the exact opposite of what you ask - it's a superset of > > javascript that adds some syntax sugar. The fact it compiles to very > > readable javascript is a testament to this. > > > >> > >> The list contains some bad role models (in terms of syntactic elegance > and > >> simplicity): C++, Haskell, OCaml, and Ruby. > > > > > > I seriously doubt your taste in syntax if you think Haskell and OCaml are > > undesirable. > > > >> > >> Thankfully Common Lisp is mentioned. Although, of the Lisps I'm familiar > >> with, Common Lisp has the ugliest syntax (still better than C++ though). > > > > > > You are clearly misusing the word "syntax"... Common lisp's syntax > consists > > of only S-exprs and the quote sugar, as other lisps do. > > > >> This is all to say that, from what I can tell, simplicity and elegance > of > >> syntax was not a design requirement (or goal) that the Rust developers > had > >> in mind. > > > > > > The goal of Rust was to produce a type-safe, memory-safe, programmer-safe > > programming language, in the niche of system's languages. > > > >> And I think that's quite unfortunate for Rust. > > > > > > It's quite unfortunate that the language doesn't abide by your nebulous, > > sparsely defined ideas of what a "good" language looks like? > > > >> > >> I'm sorry I was not able to provide this feedback years ago when it > might > >> have been more helpful. I only recently became aware of Rust. > > > > > > I doubt it would have been taken seriously then. > > > >> > >> - Greg > >> > >> -- > >> Please do not email me anything that you are not comfortable also > sharing > >> with the NSA. > >> > >> On Nov 11, 2013, at 3:46 PM, Corey Richardson wrote: > >> > >> On Mon, Nov 11, 2013 at 3:41 PM, Greg wrote: > >> > >> At this state in Rust's development, we are unlikely to make any major > >> changes to Rust's syntax. > >> > >> > >> *cries* > >> > >> > >> I don't think Rust can succeed as a language if it massively differs, > >> visually, from the language it intends to offset (C++). > >> > >> > >> > >> _______________________________________________ > >> 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 > > > > > > -- > Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt > "If you are silent about your pain, they'll kill you and say you enjoyed > it." > -- Zora Neale Hurston > -------------- next part -------------- An HTML attachment was scrubbed... URL: From catamorphism at gmail.com Tue Nov 12 10:10:13 2013 From: catamorphism at gmail.com (Tim Chevalier) Date: Tue, 12 Nov 2013 10:10:13 -0800 Subject: [rust-dev] Closing this thread [Was: Re: Fwd: Please simplify the syntax for Great Justice] Message-ID: I've placed the list on full moderation for now, which will hopefully be for less than 12 hours. Sorry -- I or other mods will approve on-topic postings as they come on, but unfortunately Mailman doesn't have a way to freeze a single thread (that I know of). Cheers, Tim On Tue, Nov 12, 2013 at 9:43 AM, Tim Chevalier wrote: > Hi folks -- > > I already requested that this thread end, and from here on I'm going > to place anyone who replies to this thread further (with the same > subject line or quoting anything from the same thread) on temporary > moderation. For any specific discussion about Rust that originates > from this thread, you're welcome to start a new thread about it with a > new subject line. > > Tim (list co-moderator) > From kevin at sb.org Tue Nov 12 10:57:34 2013 From: kevin at sb.org (Kevin Ballard) Date: Tue, 12 Nov 2013 10:57:34 -0800 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: <5281DC30.8040402@mozilla.com> References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> Message-ID: <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> On Nov 11, 2013, at 11:43 PM, Patrick Walton wrote: > We considered Go's anonymous fields but rejected them because they don't support virtual methods at the same time as field embedding. I don?t follow. Why do Go?s anonymous fields not support virtual methods at the same time as field embedding? -Kevin -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevin at sb.org Tue Nov 12 11:07:50 2013 From: kevin at sb.org (Kevin Ballard) Date: Tue, 12 Nov 2013 11:07:50 -0800 Subject: [rust-dev] Danger of throwing exceptions through Rust code Message-ID: Right now, Rust does not support catching task failure from within a task, it only supports preventing task failure from cascading into other tasks. My understanding is that this limitation is done because of safety; if a task unwinds through a few frames of code, and then stops unwinding, data structure invariants may have been broken by the unwinding, leaving the task in an unsafe state. Is this correct? Given this assumption, my worry now is about task unwinding outside of the control of Rust. Namely, if I?m using Rust to write a library with extern ?C? functions, or I?m providing callbacks to C code from within Rust, (and my Rust code calls back into C at some point), then it?s very possible for the called C code to throw an exception that is then caught in the calling C code a few frames up. The net effect is that the thread will unwind through my Rust code, but it will then be caught before unwinding any further, potentially leaving any data structures in an invalid state (assuming that there?s still Rust code higher up on this same stack that cares). Has this been considered before? Is this actually a danger or am I just being paranoid? -Kevin From rusty.gates at icloud.com Tue Nov 12 11:17:32 2013 From: rusty.gates at icloud.com (Tommi) Date: Tue, 12 Nov 2013 21:17:32 +0200 Subject: [rust-dev] Could the compiler elide unused static items? Message-ID: Could the compiler figure out if a static item is not used and then elide it altogether. Or does it do this already? I can use the following idiom in C++ (can't do it in Rust though) to have the compiler elide static data (large lookup tables in library code for example) if the end-user doesn't use it: template class Data { static_assert(n == 42, ""); template friend int get_value(int); static const int values[3]; }; template const int Data::values[3] = { 1, 2, 3 }; template int get_value(int idx) { return Data::values[idx]; } If the end-user never calls get_value(...), then Data never gets instantiated and the (potentially large) array never exists. -Tommi From corey at octayn.net Tue Nov 12 11:27:33 2013 From: corey at octayn.net (Corey Richardson) Date: Tue, 12 Nov 2013 14:27:33 -0500 Subject: [rust-dev] Could the compiler elide unused static items? In-Reply-To: References: Message-ID: On Tue, Nov 12, 2013 at 2:17 PM, Tommi wrote: > Could the compiler figure out if a static item is not used and then elide it altogether. Or does it do this already? > If it's a `pub static`, and you're compiling a library, it cannot be removed. But if it's just static and it's never used, it can and will be optimized out. Example: static X: [u8, ..30_000_000] = [1, ..30_000_000]; fn main() { println("Look ma, small binary!"); } When compiled with optimization, the resulting executable is 12K. Without, 29M. From corey at octayn.net Tue Nov 12 11:22:11 2013 From: corey at octayn.net (Corey Richardson) Date: Tue, 12 Nov 2013 14:22:11 -0500 Subject: [rust-dev] Danger of throwing exceptions through Rust code In-Reply-To: References: Message-ID: Is it possible for data low in the stack to propagate upwards through the stack before function return? It seems like if this were to be an issue, you would need to move into something parent gives you, at which point you no longer have ownership and unwinding won't destroy it. It seems like the lifetime system prevents this from being a problem. I think Rust *could* have catchable exceptions, you just wouldn't be allowed to use anything that can throw when constructing a value. That way, everything is fully constructed when an exception happens, so destructors can never run on inconsistent state and resources won't leak. Maybe there's something I'm missing, though. On Tue, Nov 12, 2013 at 2:07 PM, Kevin Ballard wrote: > Right now, Rust does not support catching task failure from within a task, it only supports preventing task failure from cascading into other tasks. My understanding is that this limitation is done because of safety; if a task unwinds through a few frames of code, and then stops unwinding, data structure invariants may have been broken by the unwinding, leaving the task in an unsafe state. Is this correct? > > Given this assumption, my worry now is about task unwinding outside of the control of Rust. Namely, if I?m using Rust to write a library with extern ?C? functions, or I?m providing callbacks to C code from within Rust, (and my Rust code calls back into C at some point), then it?s very possible for the called C code to throw an exception that is then caught in the calling C code a few frames up. The net effect is that the thread will unwind through my Rust code, but it will then be caught before unwinding any further, potentially leaving any data structures in an invalid state (assuming that there?s still Rust code higher up on this same stack that cares). > > Has this been considered before? Is this actually a danger or am I just being paranoid? > > -Kevin > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From alex at crichton.co Tue Nov 12 11:35:08 2013 From: alex at crichton.co (Alex Crichton) Date: Tue, 12 Nov 2013 11:35:08 -0800 Subject: [rust-dev] Danger of throwing exceptions through Rust code In-Reply-To: References: Message-ID: You're correct about the safeness of catching failure at a task boundary. Rust's invariants about spawning a task involve knowing a fair bit about what's allowable to share between a task boundary, and that allows us to reason about the failure unwinding to the task boundary being a safe operation (as opposed to stopping unwinding at an arbitrary location). I'm not entirely sure what you mean by throwing an exception from C (I think there are many flavors of doing this). Right now we implement unwinding via C++ exceptions. When a task unwinds, it actually throws a magical uint token which then triggers all the C++ machinery for unwinding the stack. When compiling with LLVM, we using LLVM's invoke instruction + landing pads to generate our "cleanup locations", and LLVM will codegen the right code such that all the landing pads are invoked during unwinding. What this means is that the C++ exception throwing infrastructure will probably fly right past all C code because none of it is hooked into the exception handling stuff of C++. This may mean, however, that intermediate C++ code may have landing pads run (not entirely sure). All that being said, that's just how it's currently implemented today. I don't think that we're guaranteeing this sort of behavior to always happen. It will probably always be the case that C stack frames are always sailed past during unwinding, but we may implement unwinding via precise stack tables and manual stack unwinding at some point which wouldn't trigger C++ landing pads (or use LLVM's landing pad infrastructure the same way that we're using it today). Right now it's basically the case that intermingling C with Rust stack frames and then triggering failure will only trigger unwinding in rust functions (what does it mean to unwind in C?), and I'm not sure I'd recommend that as a safe strategy for implementing bindings to a C function (all intermediate C allocations are leaked). Does that make sense? It may not quite answer your question, but hopefully that clears up at least a little bit about how it's implemented today. On Tue, Nov 12, 2013 at 11:07 AM, Kevin Ballard wrote: > Right now, Rust does not support catching task failure from within a task, it only supports preventing task failure from cascading into other tasks. My understanding is that this limitation is done because of safety; if a task unwinds through a few frames of code, and then stops unwinding, data structure invariants may have been broken by the unwinding, leaving the task in an unsafe state. Is this correct? > > Given this assumption, my worry now is about task unwinding outside of the control of Rust. Namely, if I?m using Rust to write a library with extern ?C? functions, or I?m providing callbacks to C code from within Rust, (and my Rust code calls back into C at some point), then it?s very possible for the called C code to throw an exception that is then caught in the calling C code a few frames up. The net effect is that the thread will unwind through my Rust code, but it will then be caught before unwinding any further, potentially leaving any data structures in an invalid state (assuming that there?s still Rust code higher up on this same stack that cares). > > Has this been considered before? Is this actually a danger or am I just being paranoid? > > -Kevin > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From danielmicay at gmail.com Tue Nov 12 11:50:06 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Tue, 12 Nov 2013 14:50:06 -0500 Subject: [rust-dev] Danger of throwing exceptions through Rust code In-Reply-To: References: Message-ID: On Tue, Nov 12, 2013 at 2:35 PM, Alex Crichton wrote: > You're correct about the safeness of catching failure at a task > boundary. Rust's invariants about spawning a task involve knowing a > fair bit about what's allowable to share between a task boundary, and > that allows us to reason about the failure unwinding to the task > boundary being a safe operation (as opposed to stopping unwinding at > an arbitrary location). > > I'm not entirely sure what you mean by throwing an exception from C (I > think there are many flavors of doing this). Right now we implement > unwinding via C++ exceptions. When a task unwinds, it actually throws > a magical uint token which then triggers all the C++ machinery for > unwinding the stack. When compiling with LLVM, we using LLVM's invoke > instruction + landing pads to generate our "cleanup locations", and > LLVM will codegen the right code such that all the landing pads are > invoked during unwinding. What this means is that the C++ exception > throwing infrastructure will probably fly right past all C code > because none of it is hooked into the exception handling stuff of C++. > This may mean, however, that intermediate C++ code may have landing > pads run (not entirely sure). > > All that being said, that's just how it's currently implemented today. > I don't think that we're guaranteeing this sort of behavior to always > happen. It will probably always be the case that C stack frames are > always sailed past during unwinding, but we may implement unwinding > via precise stack tables and manual stack unwinding at some point > which wouldn't trigger C++ landing pads (or use LLVM's landing pad > infrastructure the same way that we're using it today). > > Right now it's basically the case that intermingling C with Rust stack > frames and then triggering failure will only trigger unwinding in rust > functions (what does it mean to unwind in C?), and I'm not sure I'd > recommend that as a safe strategy for implementing bindings to a C > function (all intermediate C allocations are leaked). > > Does that make sense? It may not quite answer your question, but > hopefully that clears up at least a little bit about how it's > implemented today. > It's undefined behaviour for a C++ function to throw an exception past an `extern "C"` boundary so Rust doesn't need to worry about a need to handle exceptions from foreign libraries. In practice, compilers will often build code with support for passing through exceptions but it's not required and C cannot maintain the invariants required for safety in the face of unwinding. It's simply not safe to pass Rust functions directly as callbacks into C if they aren't known to never throw. Rust isn't committed to using the C++ exception personality so interoperability with unwrapped C++ libraries just isn't on the table at this point. It actually *doesn't* even use the C++ exception personality because there are hooks to reset the used stack space. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ecreed at cs.washington.edu Tue Nov 12 12:10:42 2013 From: ecreed at cs.washington.edu (Eric Reed) Date: Tue, 12 Nov 2013 12:10:42 -0800 Subject: [rust-dev] copying pointers In-Reply-To: References: <528232AF.40906@gmail.com> <52823603.1030901@gmail.com> Message-ID: I'd suggest extra::list, but it looks a little dated. On Tue, Nov 12, 2013 at 6:21 AM, Oren Ben-Kiki wrote: > For linked lists with no cycles, why not use Option> (or RcMut)? > > > On Tue, Nov 12, 2013 at 4:06 PM, spir wrote: > >> PS: What would be, in fact, the rusty way for a simplissim linked list. I >> use Option<~Cell> for now, to have something clean (None) to end the list, >> since Rust looks rather functional. But as always with Option this way >> quite obscures and complicates the code (Some() expressions, match >> expressions...). I'd rather just use a NULL pointer, for here it is fully >> safe. But this does not look rusty at all, I guess. >> What is your view? >> >> >> Denis >> >> >> >> >> _______________________________________________ >> 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: From pcwalton at mozilla.com Tue Nov 12 13:22:00 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Wed, 13 Nov 2013 06:22:00 +0900 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> Message-ID: <52829BF8.3000200@mozilla.com> On 11/13/13 3:57 AM, Kevin Ballard wrote: > On Nov 11, 2013, at 11:43 PM, Patrick Walton > wrote: > >> We considered Go's anonymous fields but rejected them because they >> don't support virtual methods at the same time as field embedding. > > I don?t follow. Why do Go?s anonymous fields not support virtual methods > at the same time as field embedding? I want to write this but I can't: package main import "fmt" type A struct { x int } type B struct { A y int } type C struct { A z int } func(self *B) Foo() { fmt.Printf("Hello!") } func(self *B) Upcast() *A { return &self.A } func(self *C) Foo() { fmt.Printf("Goodbye!") } func(self *C) Upcast() *A { return &self.A } func main() { myArray := []*A { (&B { A: A { x: 1 }, y: 2 }).Upcast(), (&C { A: A { x: 3 }, z: 4 }).Upcast(), } for i := 0; i < 2; i++ { myArray[i].Foo() } } Error: prog.go:41: myArray[i].Foo undefined (type *A has no field or method Foo) You can't really write the thing you need to write inside `Upcast` to make this code work. You would need to use an interface instead, but then interfaces don't support shared fields, just like in Rust, leading to the same problem. Patrick From catamorphism at gmail.com Tue Nov 12 17:00:30 2013 From: catamorphism at gmail.com (Tim Chevalier) Date: Tue, 12 Nov 2013 17:00:30 -0800 Subject: [rust-dev] Closing this thread [Was: Re: Fwd: Please simplify the syntax for Great Justice] In-Reply-To: References: Message-ID: The list is no longer on moderation. Posts from subscribers should go through to the list without moderator intervention now. Sorry for any inconvenience. Cheers, Tim On Tue, Nov 12, 2013 at 10:10 AM, Tim Chevalier wrote: > I've placed the list on full moderation for now, which will hopefully > be for less than 12 hours. Sorry -- I or other mods will approve > on-topic postings as they come on, but unfortunately Mailman doesn't > have a way to freeze a single thread (that I know of). > > Cheers, > Tim > > > On Tue, Nov 12, 2013 at 9:43 AM, Tim Chevalier wrote: >> Hi folks -- >> >> I already requested that this thread end, and from here on I'm going >> to place anyone who replies to this thread further (with the same >> subject line or quoting anything from the same thread) on temporary >> moderation. For any specific discussion about Rust that originates >> from this thread, you're welcome to start a new thread about it with a >> new subject line. >> >> Tim (list co-moderator) >> -- Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt "If you are silent about your pain, they'll kill you and say you enjoyed it." -- Zora Neale Hurston From kevin at sb.org Tue Nov 12 18:42:49 2013 From: kevin at sb.org (Kevin Ballard) Date: Tue, 12 Nov 2013 18:42:49 -0800 Subject: [rust-dev] Danger of throwing exceptions through Rust code In-Reply-To: References: Message-ID: I guess I was being too vague when I said ?C exceptions?, because you?re right, that?s not actually a specific thing. More concretely, I was thinking of either C++ exceptions, or Obj-C exceptions. One situation I was thinking of would be a rust library that exposes `extern ?C?` functions. Let?s say one of these functions, frob(), takes an `extern ?C?` callback and calls it. Now let?s say I?m writing an Obj-C app, and I do something like the following: static void callback() { [NSException raise:@?Foo Exception? format:@?I just felt like unwinding?]; } @try { frob(callback) } @catch (NSException *e) { NSLog(@?I caught my exception!?); } This will unwind through the Rust code, before being caught again. It?s hard to come up with a scenario where this actually results in unsafe state within the rust library, but let?s say `frob()` uses some sort of shared state (e.g. a RWArc<>), and is in the middle of modifying the shared state in a way that causes invariants to be broken temporarily. If unwinding happens when the invariants are in the broken state, then they?ll be left in the broken state and the next bit of Rust code that tries to access this shared state will likely blow up. This is obviously pretty contrived, but the question is, is this legal to do, and if so, do we need to do anything? Daniel?s response says that it?s undefined for a C++ function to throw an exception past an `extern ?C?` boundary. This is something I did not know. But what about Obj-C exceptions? I haven?t heard about any undefined behavior regarding Obj-C exceptions. It is generally recognized that throwing an Obj-C exception past a framework boundary is unsafe (i.e. throwing an exception in user code that unwinds through Foundation code), but this is because Obj-C code rarely bothers with @try/@finally and doesn?t have stack objects, so unwinding through code that doesn?t expect it will often leave data structures in invalid states. If all forms of unwinding are considered to be undefined when passing through an `extern ?C?` boundary, then I guess we can consider this issue to be covered by undefined behavior. Although this doesn?t make me particularly happy, because it means that it may be impossible to truly contain the unsafety in FFI functions. One possible way to mitigate this would be to provide a way to wrap an FFI function with a stub that catches C++/Obj-C exceptions (I think Obj-C exceptions are unified with the C++ exception machinery on all modern platforms (i.e. not 32-bit PPC, and I?m not sure about 32-bit x86)) and triggers task failure. This would mean any attempt to unwind through a Rust function (using C++ or Obj-C exceptions) would be contained, after a fashion. Though this does raise another question. What if a C++ function calls a Rust function, and the Rust function triggers task failure? Is it possible for the C++ function to catch the task failure using a catch(?) block? Furthermore, since Daniel said it?s undefined for a C++ exception to be thrown past an `extern ?C?` boundary, does this mean that it?s technically undefined for Rust to trigger task failure in any function that?s rooted in an `extern ?C?` function? -Kevin On Nov 12, 2013, at 11:35 AM, Alex Crichton wrote: > You're correct about the safeness of catching failure at a task > boundary. Rust's invariants about spawning a task involve knowing a > fair bit about what's allowable to share between a task boundary, and > that allows us to reason about the failure unwinding to the task > boundary being a safe operation (as opposed to stopping unwinding at > an arbitrary location). > > I'm not entirely sure what you mean by throwing an exception from C (I > think there are many flavors of doing this). Right now we implement > unwinding via C++ exceptions. When a task unwinds, it actually throws > a magical uint token which then triggers all the C++ machinery for > unwinding the stack. When compiling with LLVM, we using LLVM's invoke > instruction + landing pads to generate our "cleanup locations", and > LLVM will codegen the right code such that all the landing pads are > invoked during unwinding. What this means is that the C++ exception > throwing infrastructure will probably fly right past all C code > because none of it is hooked into the exception handling stuff of C++. > This may mean, however, that intermediate C++ code may have landing > pads run (not entirely sure). > > All that being said, that's just how it's currently implemented today. > I don't think that we're guaranteeing this sort of behavior to always > happen. It will probably always be the case that C stack frames are > always sailed past during unwinding, but we may implement unwinding > via precise stack tables and manual stack unwinding at some point > which wouldn't trigger C++ landing pads (or use LLVM's landing pad > infrastructure the same way that we're using it today). > > Right now it's basically the case that intermingling C with Rust stack > frames and then triggering failure will only trigger unwinding in rust > functions (what does it mean to unwind in C?), and I'm not sure I'd > recommend that as a safe strategy for implementing bindings to a C > function (all intermediate C allocations are leaked). > > Does that make sense? It may not quite answer your question, but > hopefully that clears up at least a little bit about how it's > implemented today. > > On Tue, Nov 12, 2013 at 11:07 AM, Kevin Ballard wrote: >> Right now, Rust does not support catching task failure from within a task, it only supports preventing task failure from cascading into other tasks. My understanding is that this limitation is done because of safety; if a task unwinds through a few frames of code, and then stops unwinding, data structure invariants may have been broken by the unwinding, leaving the task in an unsafe state. Is this correct? >> >> Given this assumption, my worry now is about task unwinding outside of the control of Rust. Namely, if I?m using Rust to write a library with extern ?C? functions, or I?m providing callbacks to C code from within Rust, (and my Rust code calls back into C at some point), then it?s very possible for the called C code to throw an exception that is then caught in the calling C code a few frames up. The net effect is that the thread will unwind through my Rust code, but it will then be caught before unwinding any further, potentially leaving any data structures in an invalid state (assuming that there?s still Rust code higher up on this same stack that cares). >> >> Has this been considered before? Is this actually a danger or am I just being paranoid? >> >> -Kevin >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev -------------- next part -------------- An HTML attachment was scrubbed... URL: From rusty.gates at icloud.com Tue Nov 12 19:01:40 2013 From: rusty.gates at icloud.com (Tommi) Date: Wed, 13 Nov 2013 05:01:40 +0200 Subject: [rust-dev] Could the compiler elide unused static items? In-Reply-To: References: Message-ID: Previously I replied incorrectly to the mail, so I'm replying to it anew just to show how the discussion went from here on. Still learning mailing lists, sorry. These are the missing posts: On 2013-11-12, at 21:42, Corey Richardson wrote: > On Tue, Nov 12, 2013 at 2:39 PM, Tommi wrote: >> I didn't think it would be optimized out of the library code. What I meant was: would the static item be optimized out if the end-user statically links to a library where is some 'pub static' item, which the end-user's code never directly nor indirectly uses? >> > > We do not have static linking or LTO, so not. But, once we do, there's > no reason it wouldn't be. From danielmicay at gmail.com Tue Nov 12 19:06:14 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Tue, 12 Nov 2013 22:06:14 -0500 Subject: [rust-dev] Danger of throwing exceptions through Rust code In-Reply-To: References: Message-ID: On Tue, Nov 12, 2013 at 9:42 PM, Kevin Ballard wrote: > I guess I was being too vague when I said ?C exceptions?, because you?re > right, that?s not actually a specific thing. More concretely, I was > thinking of either C++ exceptions, or Obj-C exceptions. > > One situation I was thinking of would be a rust library that exposes > `extern ?C?` functions. Let?s say one of these functions, frob(), takes an > `extern ?C?` callback and calls it. Now let?s say I?m writing an Obj-C app, > and I do something like the following: > > static void callback() { > [NSException raise:@?Foo Exception? format:@?I just felt like > unwinding?]; > } > > @try { > frob(callback) > } > @catch (NSException *e) { > NSLog(@?I caught my exception!?); > } > > This will unwind through the Rust code, before being caught again. It?s > hard to come up with a scenario where this actually results in unsafe state > within the rust library, but let?s say `frob()` uses some sort of shared > state (e.g. a RWArc<>), and is in the middle of modifying the shared state > in a way that causes invariants to be broken temporarily. If unwinding > happens when the invariants are in the broken state, then they?ll be left > in the broken state and the next bit of Rust code that tries to access this > shared state will likely blow up. > > This is obviously pretty contrived, but the question is, is this legal to > do, and if so, do we need to do anything? > > Daniel?s response says that it?s undefined for a C++ function to throw an > exception past an `extern ?C?` boundary. This is something I did not know. > But what about Obj-C exceptions? I haven?t heard about any undefined > behavior regarding Obj-C exceptions. It is generally recognized that > throwing an Obj-C exception past a framework boundary is unsafe (i.e. > throwing an exception in user code that unwinds through Foundation code), > but this is because Obj-C code rarely bothers with @try/@finally and > doesn?t have stack objects, so unwinding through code that doesn?t expect > it will often leave data structures in invalid states. > > If all forms of unwinding are considered to be undefined when passing > through an `extern ?C?` boundary, then I guess we can consider this issue > to be covered by undefined behavior. Although this doesn?t make me > particularly happy, because it means that it may be impossible to truly > contain the unsafety in FFI functions. One possible way to mitigate this > would be to provide a way to wrap an FFI function with a stub that catches > C++/Obj-C exceptions (I *think* Obj-C exceptions are unified with the C++ > exception machinery on all modern platforms (i.e. not 32-bit PPC, and I?m > not sure about 32-bit x86)) and triggers task failure. This would mean any > attempt to unwind through a Rust function (using C++ or Obj-C exceptions) > would be contained, after a fashion. > > Though this does raise another question. What if a C++ function calls a > Rust function, and the Rust function triggers task failure? Is it possible > for the C++ function to catch the task failure using a catch(?) block? > Furthermore, since Daniel said it?s undefined for a C++ exception to be > thrown past an `extern ?C?` boundary, does this mean that it?s technically > undefined for Rust to trigger task failure in any function that?s rooted in > an `extern ?C?` function? > > -Kevin > It's completely possible to write safe bindings to a C++ library. The process involves wrapping the whole thing with `extern "C"` functions using catch blocks for any function possibly throwing an exception. Keep in mind that libraries already have to do this to support usage from most other languages, so it's a sunken cost. If a library takes a callback, writing safe Rust bindings isn't going to turn out well. Rust functions can fail, so the Rust API can't pass an arbitrary function to the callback. -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Tue Nov 12 19:18:25 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Wed, 13 Nov 2013 12:18:25 +0900 Subject: [rust-dev] Danger of throwing exceptions through Rust code In-Reply-To: References: Message-ID: <5282EF81.6000207@mozilla.com> On 11/13/13 12:06 PM, Daniel Micay wrote: > It's completely possible to write safe bindings to a C++ library. The > process involves wrapping the whole thing with `extern "C"` functions > using catch blocks for any function possibly throwing an exception. Keep > in mind that libraries already have to do this to support usage from > most other languages, so it's a sunken cost. > > If a library takes a callback, writing safe Rust bindings isn't going to > turn out well. Rust functions can fail, so the Rust API can't pass an > arbitrary function to the callback. Yeah, this has been a concern for a while (years). Maybe we should have an unsafe "catch" just for this case, to allow turning a Rust failure into a C-style error code. Patrick From kevin at sb.org Tue Nov 12 19:18:23 2013 From: kevin at sb.org (Kevin Ballard) Date: Tue, 12 Nov 2013 19:18:23 -0800 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: <52829BF8.3000200@mozilla.com> References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> Message-ID: On Nov 12, 2013, at 1:22 PM, Patrick Walton wrote: > On 11/13/13 3:57 AM, Kevin Ballard wrote: >> On Nov 11, 2013, at 11:43 PM, Patrick Walton > > wrote: >> >>> We considered Go's anonymous fields but rejected them because they >>> don't support virtual methods at the same time as field embedding. >> >> I don?t follow. Why do Go?s anonymous fields not support virtual methods >> at the same time as field embedding? > > I want to write this but I can't: > > [elided for brevity] > > func main() { > myArray := []*A { > (&B { A: A { x: 1 }, y: 2 }).Upcast(), > (&C { A: A { x: 3 }, z: 4 }).Upcast(), > } > for i := 0; i < 2; i++ { > myArray[i].Foo() > } > } > > Error: > > prog.go:41: myArray[i].Foo undefined (type *A has no field or method Foo) > > You can't really write the thing you need to write inside `Upcast` to make this code work. You would need to use an interface instead, but then interfaces don't support shared fields, just like in Rust, leading to the same problem. Don?t you need a trait in Rust in order to have virtual methods anyway? So the same fundamental problem is there; the machinery to support virtual methods does not support shared fields. The trick with the proposed single inheritance model is that traits are modified so they can access shared field, by virtue of ?extending a struct?. Presumably this is rather simple with single inheritance, because you know all substructs have the super as a prefix, and thus the trait implementation can ignore all the extra fields in the substruct. But I don?t see why this can?t also be done with embedded fields. You lose the prefix property, but I don?t think it?s necessary to implement this. The virtual table would just need to store the field offset for the sub-struct that provides the method, so when you call a virtual method, you can ?slice? the parent object (to use Go?s terminology) such that the method?s receiver is the sub-struct itself. Here?s a sample: struct A { x: int } struct B { y: int } struct C { A, B, z: int } trait ATrait : A { fn foo(&self); } trait BTrait: B { fn bar(&self); } impl ATrait for A { fn foo(&self) { println!("This is A: {}", self.x); } } impl BTrait for B { fn bar(&self) { println!("This is B: {}", self.y); } } fn main() { let myAs = [A{ x: 1 } as ~ATrait, C{ A: A{ x: 2 }, B: B{ y: 3 }, z: 4 } as ~ATrait]; for a in myAs.iter() { a.foo(); } let myBs = [B{ y: 1 } as ~BTrait, C{ A: A{ x: 2 }, B: B{ y: 3 }, z: 4} as ~BTrait]; for b in myBs.iter() { b.bar(); } } In the case of calling b.bar() on the C object, this would be equivalent to b.B.bar(). I think it?s reasonable that traits could still only extend a single struct (I believe that relaxing this would require an extra deref on every field access, which is no fun). The point is that trait implementations know the type they?re being implemented on, and therefore having non-prefixed sub-structs is not a problem. The only penalty this approach has (that comes to mind) over the single-inheritance model is that, because of the loss of the prefix property, any field access on the trait object itself will require looking up the field offset in the virtual table. But trait objects already use the virtual table for everything else, and the actual trait implementations don?t require this, so I don?t think it?s problematic to require a virtual table lookup on trait object field access. -Kevin -------------- next part -------------- An HTML attachment was scrubbed... URL: From slabode at aim.com Tue Nov 12 19:36:17 2013 From: slabode at aim.com (SiegeLord) Date: Tue, 12 Nov 2013 22:36:17 -0500 Subject: [rust-dev] Danger of throwing exceptions through Rust code In-Reply-To: <5282EF81.6000207@mozilla.com> References: <5282EF81.6000207@mozilla.com> Message-ID: <5282F3B1.2080901@aim.com> On 11/12/2013 10:18 PM, Patrick Walton wrote: > On 11/13/13 12:06 PM, Daniel Micay wrote: >> If a library takes a callback, writing safe Rust bindings isn't going to >> turn out well. Rust functions can fail, so the Rust API can't pass an >> arbitrary function to the callback. > > Yeah, this has been a concern for a while (years). Maybe we should have > an unsafe "catch" just for this case, to allow turning a Rust failure > into a C-style error code. > > Patrick Is that not, essentially, just spawning a task inside the Rust callback and catching the result (via task::try)? -SL From pcwalton at mozilla.com Tue Nov 12 21:01:08 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Wed, 13 Nov 2013 14:01:08 +0900 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> Message-ID: <52830794.3070504@mozilla.com> On 11/13/13 12:18 PM, Kevin Ballard wrote: > The only penalty this approach has (that comes to mind) over the > single-inheritance model is that, because of the loss of the prefix > property, any field access on the trait object itself will require > looking up the field offset in the virtual table. But trait objects > already use the virtual table for everything else, and the actual trait > implementations don?t require this, so I don?t think it?s problematic to > require a virtual table lookup on trait object field access. I think it is. This is a performance cost over C++ that is just too risky. Note that browser reflow is very much gated on the ability to load and store fields from a constant offset. I think we stand a good chance of losing to the competition if we do this. Patrick From kevin at sb.org Tue Nov 12 22:26:17 2013 From: kevin at sb.org (Kevin Ballard) Date: Tue, 12 Nov 2013 22:26:17 -0800 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: <52830794.3070504@mozilla.com> References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> <52830794.3070504@mozilla.com> Message-ID: <129CF8DC-08FB-43B8-8A8B-985C254A5AEA@sb.org> On Nov 12, 2013, at 9:01 PM, Patrick Walton wrote: > On 11/13/13 12:18 PM, Kevin Ballard wrote: >> The only penalty this approach has (that comes to mind) over the >> single-inheritance model is that, because of the loss of the prefix >> property, any field access on the trait object itself will require >> looking up the field offset in the virtual table. But trait objects >> already use the virtual table for everything else, and the actual trait >> implementations don?t require this, so I don?t think it?s problematic to >> require a virtual table lookup on trait object field access. > > I think it is. This is a performance cost over C++ that is just too risky. Note that browser reflow is very much gated on the ability to load and store fields from a constant offset. I think we stand a good chance of losing to the competition if we do this. How does C++ multiple inheritance deal with this? I've never looked much at the actual implementation. Specifically, if I have something like #include class A { public: int x = 1; virtual ~A() = default; }; class B { public: int y = 2; virtual ~B() = default; }; class C: public A, public B { public: int z = 3; }; int main(int argc, char *argv[]) { B *someB = new C(); std::cout << "y: " << someB->y << std::endl; } I assume that `someB` really is a pointer to an instance `B`, somewhere within the enclosing instance of `C`. I also assume that the vtable for this instance of `B` contains a pointer back to the root `C` (or perhaps an offset back to the root `C`, so the vtable can be shared). This would allow field access and non-virtual methods to work exactly as they do on a non-virtual class, and virtual methods would look up the root C object before resolving (and dynamic_cast<> would use this as well). Why can't something similar be done in Rust? I assume a ~Trait right now is a pair of pointers: a pointer to the wrapped object, and a pointer to the vtable. Stick the offset from the embedded field back to its parent in the vtable, and have the value pointer in the trait point to the portion of the wrapped value that represents the struct that the trait inherits from. This obviously means that traits are then required to only inherit from a single struct, but I think that's reasonable. And even that restriction could be lifted if ~Trait objects could be represented using an array of pointers (one to each inherited struct), e.g. ([*A,*B,*C],*vtable) instead of just (*A,*vtable), though I suspect this is not worth doing. Anyway, if the trait object contains the pointer to the inherited struct, then field access would still be a constant offset, and virtual method calls could be done by looking up the "master" pointer from the vtable, just as I assume C++ multiple inheritance does. -Kevin -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/pkcs7-signature Size: 4118 bytes Desc: not available URL: From kevin at sb.org Tue Nov 12 22:30:16 2013 From: kevin at sb.org (Kevin Ballard) Date: Tue, 12 Nov 2013 22:30:16 -0800 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: <129CF8DC-08FB-43B8-8A8B-985C254A5AEA@sb.org> References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> <52830794.3070504@mozilla.com> <129CF8DC-08FB-43B8-8A8B-985C254A5AEA@sb.org> Message-ID: <9859FE7A-3F11-4317-9491-6EEB4F4157AF@sb.org> On Nov 12, 2013, at 10:26 PM, Kevin Ballard wrote: > And even that restriction could be lifted if ~Trait objects could be represented using an array of pointers (one to each inherited struct), e.g. ([*A,*B,*C],*vtable) instead of just (*A,*vtable), though I suspect this is not worth doing. Upon further reflection, this would need to be done anyway because of the ability to combine traits. If I have trait TraitA : A {} trait TraitB : B {} and I want to use ~TraitA+TraitB then I would need a "fat" trait. Although in this case the number of value pointers is equal to the number of combined traits, so it's a bit more sensible to allow for "fat" trait pointers here. -Kevin -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/pkcs7-signature Size: 4118 bytes Desc: not available URL: From oren at ben-kiki.org Tue Nov 12 23:36:50 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Wed, 13 Nov 2013 09:36:50 +0200 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: <9859FE7A-3F11-4317-9491-6EEB4F4157AF@sb.org> References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> <52830794.3070504@mozilla.com> <129CF8DC-08FB-43B8-8A8B-985C254A5AEA@sb.org> <9859FE7A-3F11-4317-9491-6EEB4F4157AF@sb.org> Message-ID: It seems the argument on single-inheritance hinges on the following use case: struct Foo { foo: int } struct Bar : Foo { bar: bar } fn main() { let myFoos = [Foo{ foo: 1 } as ~Foo, Bar{ foo: Foo{foo: 1}, bar: 2} as ~Foo]; for myFoo in myFoos.iter() { myFoo.foo; // Fixed offset access } } If I understand correctly, this member access is vital for Servo. At the same time, I (and I think others) would like to see some form of a flexible implementation reuse for traits, with the understanding the invoking trait methods incurs the cost of a virtual function anyway. I think it is "obvious" that the same mechanism can't do both. So how about a compromise? There would be two mechanisms, but we'll make them play nice with each other. Mechanism #1: Struct-traits. Mechanism #3: Anonymous fields. struct Foo { foo: int } // Note: Use "Foo" as a trait. // Any type implementing "Foo" has a publicly-reachable "Foo" member at offset 0. // The trait "Foo" allows constant-offset access to all the "Foo" data members. fn use_foo(ptr: &T) -> int { ptr.foo // Fixed offset } // By construction, Bar implements the Foo struct-trait struct Bar { Foo; bar: int; } (It is also possible to add a new syntax "struct Bar : Foo { bar int }", if this is seen as clearer, but IMO it isn't really needed). // Baz also implements Foo by construction. struct Baz { Bar; baz: int; } // Qux doesn't implement Foo. struct Qux { qux: int, Foo } As for non-struct traits, anonymous fields would provide a default implementation. That is, suppose that: impl Trait for Foo { ... } Then one would be need to write (explicitly!): impl Trait for Bar {} // Just use the default from Foo Or: impl Trait for Bar { ... override some of the methods ... }; (I think it is a bad idea to have traits be implemented implicitly just because one anonymous field implements them; IMVHO an explicit "impl Trait for Container" is a "very good idea"). This way you can have your cake and eat it 2. I think it is pretty clean - traits do arbitrary mixin things with virtual-function cost (_with_ implementation reuse); And there's a "by definition single inheritance" special access-my-data-members-at-fixed-offset trait whose existence does not impact the power of the normal mixin traits in any way. -------------- next part -------------- An HTML attachment was scrubbed... URL: From vadimcn at gmail.com Wed Nov 13 00:02:30 2013 From: vadimcn at gmail.com (Vadim) Date: Wed, 13 Nov 2013 00:02:30 -0800 Subject: [rust-dev] Greenlets in Rust (was: Abandoning segmented stacks in Rust) Message-ID: Hi, I would like to float a proposal (or three :-), regarding "greenlets" in Rust. For those unfamiliar with greenlets, they are a tool for writing concurrent code, similar to Rust's tasks, but much more light-weight in terms of memory consumption (especially now that segmented stacks are no more). I think there are some scenarios where low memory consumption per-task is still important, 64-bit address spaces notwithstanding. A typical one would be a pub-sub server, which needs to maintain a massive number of simple I/O workflows, where I/O channels are idle most of the time. So here we go (in the order of increasing craziness): 1. Recently I've learned how Python greenletsare implemented . I believe that the same approach could work in Rust: Basically, greenlets are spawned using the same stack as the parent greenlet, just like a normal function call. When a greenlet is suspended, it copies the portion of the stack used up since its' spawning to the heap. When one is re-activated, the saved memory is copied back where it came from (having first saved stack of the previous active greenlet,- if they overlap). Since greenlets don't need to save "red zone" of the stack, the amount of data per instance is precisely what is actually used. There are also downsides, of course: - greenlets are bound to the thread that spawned them, - two memcpy's are needed when switching between them. In the case of Python, though, there's one further optimization: since Python's stack frames live on the heap, in most cases, there nothing on the hardware stack that a greenlet needs saving! As a bonus, it can now be resumed at any stack position, so no saving of previous greenlet's stack is needed. The only time when a full save occurs is when there are foreign stack frames on the stack. 2. Well, can Rust do the same? What if we came up with an attribute, say, [#stackless], which causes a function to allocate it's stack frame on the heap and put all local vars there? The only things on the actual hardware stack would then be the function's arguments, the return address, the saved base pointer and the pointer to that heap-alllocated frame. With the exception of base pointers, all these things are position-independent, I believe. And base pointer chain can be easily fixed up if/when stack is moved. So if we had that, and the whole greenlet's stack consisted of such functions, and there was a way for the "switch_to_greenlet()" function to detect that, then such greenlet's stack would be relocatable and could be resumed at any position in the thread's stack (or even in another thread!) with minimal memory copying, just like in Python. Of course, the [#stackless] functions would be slower than the normal ones, but in the scenario I've outlined in the beginning, it shouldn't be a problem. 3. Unfortunately, in order for the above scheme to work, all I/O methods, (which are typically where yields happen), would need to be marked as [#stackless]... This would affect the performance of "normal" code using the same API, which is undesirable. Okay, but usually there are not *that *many things that point into the stack in a typical program. I can think of only three things: references to stack-allocated buffers, base pointer chains and references to caller-allocated return values. - The first one can be lived without - just allocate buffers on the heap. - The second one - see above. - The last one is more tricky, but for the sake of argument, let's assume that we restricted function signatures such that only register-allocated types can be returned. Let's say we came up with a way to mark up functions that may yield to another greenlet, and also with a way to prohibit taking address of stack-allocated variables for the duration of calls to yielding functions. These restrictions would be annoying, but not overly so, as long as you had to obey them only in functions that are intended to be run in a greenlet. On the plus side, the hardware stack contents would now be relocatable. In this setup, everything could proceed as usual, using the hardware stack, until execution came to a blocking I/O call. At that point, the scheduler would check if running inside a greenlet, copy greenlet's stack to the heap and switch off to another greenlet. Otherwise, it would do the same thing it does now, i.e. switch tasks. So, what do you say, rustafarians? Does any of that make any sense? Vadim On Tue, Nov 5, 2013 at 9:18 AM, Patrick Walton wrote: > On 11/5/13 8:32 AM, David Piepgrass wrote: > >> Segmented stacks aren't the only solution though. >> >> If the concern is many tasks that block for a long time, I imagine a >> mechanism to bundle a bunch of small, dormant stacks into a single page >> so that the original pages could be released to the OS. >> >> >> >> *If stacks were additionally relocatable (which requires similar >> machinery as precise moving GC, if I'm not mistaken) * > > > This is correct. It's conceivable (although I can't make any promises) > that if and when LLVM supports this, we could experiment with doing what Go > does. > > Patrick > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ecreed at cs.washington.edu Wed Nov 13 00:27:21 2013 From: ecreed at cs.washington.edu (Eric Reed) Date: Wed, 13 Nov 2013 00:27:21 -0800 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: <9859FE7A-3F11-4317-9491-6EEB4F4157AF@sb.org> References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> <52830794.3070504@mozilla.com> <129CF8DC-08FB-43B8-8A8B-985C254A5AEA@sb.org> <9859FE7A-3F11-4317-9491-6EEB4F4157AF@sb.org> Message-ID: Here's how I would do it using just existing Rust (assuming this hasn't all changed under me in the past couple months). NB: I haven't actually tried compiling this, but I'm pretty sure it (or something like it) would work. Nice properties over this solution: - Doesn't require language extensions (although syntax sugar wouldn't be unwelcome) - Doesn't require trait objects (i.e. static dispatch is possible) - Only need to implement one method for each derived type (super) in addition to overridden methods - Supports multiple inheritance in two ways (and avoids the diamond problem I think -- not a C++ expert so I may have misunderstood that) + no default parent and programmer must select which parent to use before calling + implementer-chosen default parent and programmer can chose to use a different parent if desired Neutral?: - Doesn't enforce or care about the prefix property. Not sure if that still matters so much w/o dynamic dispatch. Downsides: - Performance of delegation depends on LLVM's ability to inline (I think). - Does require repeating all the methods once (for delegating default implementations) // The base type struct Base { data : int; } // Characterize it's extensible behavior in a trait trait Trait { fn method(&self); } // Implement the base behavior impl Trait for Base { fn method(&self) { ... } } // Extension of trait that supports upcasting to existing implementations trait DerivingTrait

: Trait { // one extra method for accessing a parent's implementation. ideally this would be inlined by the compiler fn super(&self) -> P; // default implementations for all the methods in Trait let us avoid writing delegation everywhere manually fn method(&self) { self.super().method() // just delegate to parent } } // Single inheritance struct Single { parent: Base, moreData: int, } impl DerivingTrait for Single { fn super(&self) -> Base { self.parent } } // Overriding behavior struct Override { parent: Base, otherData: u8, } impl DerivingTrait for Override { fn super(&self) -> Base { self.parent } fn method(&self) { ... } } // Multiple inheritance struct Multiple { single: Single, override: Override, evenMoreData: ~str, } // must specify which parent's implementation we want (could hide wrapping inside of as_* methods impl'd on Multiple if you like) // if we want one of them as the default, then we can impl DerivingTrait on Multiple directly struct MultipleAsSingle(Multiple); struct MultipleAsOverride(Multiple); impl DerivingTrait for MultipleAsSingle { fn super(&self) -> Single { self.single } } impl DerivingTrait for MultipleAsOverride { fn super(&self) -> Override { self.override } } fn main() { let base = Base { ... }; let single = Single { ... }; let override = Override { ... }; let multiple = Multiple { ... }; base.method(); base.super(); // compile time error single.method(); // =inline delegation=> single.super().method() =inline upcast=> single.base.method() override.method(); // done! no delegating MultipleAsSingle(multiple).method(); // =delegate=> MAS(multiple).super().method() =upcast=> multiple.single.method() =delegate=> multiple.single.super().method() =upcast=> multiple.single.base.method() MutlipleAsOverride(multiple).method(); // =delegate=> MAO(multiple).super().method() =upcast=> multiple.override.method() } Thoughts? Eric On Tue, Nov 12, 2013 at 10:30 PM, Kevin Ballard wrote: > On Nov 12, 2013, at 10:26 PM, Kevin Ballard wrote: > > > And even that restriction could be lifted if ~Trait objects could be > represented using an array of pointers (one to each inherited struct), e.g. > ([*A,*B,*C],*vtable) instead of just (*A,*vtable), though I suspect this is > not worth doing. > > Upon further reflection, this would need to be done anyway because of the > ability to combine traits. If I have > > trait TraitA : A {} > trait TraitB : B {} > > and I want to use ~TraitA+TraitB then I would need a "fat" trait. Although > in this case the number of value pointers is equal to the number of > combined traits, so it's a bit more sensible to allow for "fat" trait > pointers here. > > -Kevin > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mozilla at mcpherrin.ca Wed Nov 13 00:49:49 2013 From: mozilla at mcpherrin.ca (Matthew McPherrin) Date: Wed, 13 Nov 2013 00:49:49 -0800 Subject: [rust-dev] Rust compiler running on ARM? In-Reply-To: References: Message-ID: Luqman got rustc running on ARM. Builds are maybe here: http://luqman.ca/rust-builds/ On Mon, Oct 21, 2013 at 12:42 AM, Corey Richardson wrote: > I've yet to see or hear of a rustc running native on ARM, though it > shouldn't be impossible to cross-build rustc for native ARM: we can > already target ARM just fine. > > On Mon, Oct 21, 2013 at 2:01 AM, Igor Bukanov wrote: >> What is the current status of ARM support in Rust? In particularly I >> am interested in running the compiler on an ARM Chromebook. >> _______________________________________________ >> 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 From ecreed at cs.washington.edu Wed Nov 13 01:01:22 2013 From: ecreed at cs.washington.edu (Eric Reed) Date: Wed, 13 Nov 2013 01:01:22 -0800 Subject: [rust-dev] Greenlets in Rust (was: Abandoning segmented stacks in Rust) In-Reply-To: References: Message-ID: The big issue I see right away (assuming I read this correctly and greenlets can still access the stack that existed when they were created), is that now mutable state on the stack is *shared* between greenlets and therefore can experience *data races* (impossible for tasks b/c they don't share memory), so they sound wildly unsafe to me. There may be some other issues that arise from the shared stack prefix property: - If a greenlet moves something on the stack, then other greenlets now have access to invalidated memory - You can no longer assume that you have sole access things pointed to by unique pointers, which would probably invalidate a lot of existing assumptions. Eric On Wed, Nov 13, 2013 at 12:02 AM, Vadim wrote: > Hi, > I would like to float a proposal (or three :-), regarding "greenlets" in > Rust. For those unfamiliar with greenlets, they are a tool for writing > concurrent code, similar to Rust's tasks, but much more light-weight in > terms of memory consumption (especially now that segmented stacks are no > more). > > I think there are some scenarios where low memory consumption per-task is > still important, 64-bit address spaces notwithstanding. A typical one > would be a pub-sub server, which needs to maintain a massive number of > simple I/O workflows, where I/O channels are idle most of the time. > > So here we go (in the order of increasing craziness): > > 1. Recently I've learned how Python greenletsare > implemented . I believe that the > same approach could work in Rust: > > Basically, greenlets are spawned using the same stack as the parent > greenlet, just like a normal function call. When a greenlet is suspended, > it copies the portion of the stack used up since its' spawning to the > heap. When one is re-activated, the saved memory is copied back where it > came from (having first saved stack of the previous active greenlet,- if > they overlap). > > Since greenlets don't need to save "red zone" of the stack, the amount of > data per instance is precisely what is actually used. > > There are also downsides, of course: > - greenlets are bound to the thread that spawned them, > - two memcpy's are needed when switching between them. > > In the case of Python, though, there's one further optimization: since > Python's stack frames live on the heap, in most cases, there nothing on the > hardware stack that a greenlet needs saving! As a bonus, it can now be > resumed at any stack position, so no saving of previous greenlet's stack is > needed. The only time when a full save occurs is when there are foreign > stack frames on the stack. > > > 2. Well, can Rust do the same? What if we came up with an attribute, > say, [#stackless], which causes a function to allocate it's stack frame on > the heap and put all local vars there? The only things on the actual > hardware stack would then be the function's arguments, the return address, > the saved base pointer and the pointer to that heap-alllocated frame. > With the exception of base pointers, all these things are > position-independent, I believe. And base pointer chain can be easily > fixed up if/when stack is moved. > > So if we had that, and the whole greenlet's stack consisted of such > functions, and there was a way for the "switch_to_greenlet()" function to > detect that, then such greenlet's stack would be relocatable and could be > resumed at any position in the thread's stack (or even in another thread!) > with minimal memory copying, just like in Python. > > Of course, the [#stackless] functions would be slower than the normal > ones, but in the scenario I've outlined in the beginning, it shouldn't be a > problem. > > > 3. Unfortunately, in order for the above scheme to work, all I/O methods, > (which are typically where yields happen), would need to be marked as > [#stackless]... This would affect the performance of "normal" code using > the same API, which is undesirable. > > Okay, but usually there are not *that *many things that point into the > stack in a typical program. I can think of only three things: references > to stack-allocated buffers, base pointer chains and references to > caller-allocated return values. > - The first one can be lived without - just allocate buffers on the heap. > - The second one - see above. > - The last one is more tricky, but for the sake of argument, let's assume > that we restricted function signatures such that only register-allocated > types can be returned. > > Let's say we came up with a way to mark up functions that may yield to > another greenlet, and also with a way to prohibit taking address of > stack-allocated variables for the duration of calls to yielding functions. > These restrictions would be annoying, but not overly so, as long as you > had to obey them only in functions that are intended to be run in a > greenlet. > On the plus side, the hardware stack contents would now be relocatable. > > In this setup, everything could proceed as usual, using the hardware > stack, until execution came to a blocking I/O call. At that point, the > scheduler would check if running inside a greenlet, copy greenlet's stack > to the heap and switch off to another greenlet. Otherwise, it would do the > same thing it does now, i.e. switch tasks. > > > So, what do you say, rustafarians? Does any of that make any sense? > > Vadim > > > On Tue, Nov 5, 2013 at 9:18 AM, Patrick Walton wrote: > >> On 11/5/13 8:32 AM, David Piepgrass wrote: >> >>> Segmented stacks aren't the only solution though. >>> >>> If the concern is many tasks that block for a long time, I imagine a >>> mechanism to bundle a bunch of small, dormant stacks into a single page >>> so that the original pages could be released to the OS. >>> >>> >>> >>> *If stacks were additionally relocatable (which requires similar >>> machinery as precise moving GC, if I'm not mistaken) * >> >> >> This is correct. It's conceivable (although I can't make any promises) >> that if and when LLVM supports this, we could experiment with doing what Go >> does. >> >> Patrick >> _______________________________________________ >> 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: From oren at ben-kiki.org Wed Nov 13 01:25:10 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Wed, 13 Nov 2013 11:25:10 +0200 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> <52830794.3070504@mozilla.com> <129CF8DC-08FB-43B8-8A8B-985C254A5AEA@sb.org> <9859FE7A-3F11-4317-9491-6EEB4F4157AF@sb.org> Message-ID: This is probably as good as we can get in the current system (I do something similar in my code today). I also think you probably need both "super" and "mut_super", so it would be two methods to implement instead of one (still pretty good). I wonder whether it is possible to write a macro that automates writing these boilerplate methods? The key weakness is that (I think) the compiler can't inline the accesses to "super" so that you end up with a chain of virtual function calls every time it is accessed, so performance would be pretty bad. On Wed, Nov 13, 2013 at 10:27 AM, Eric Reed wrote: > Here's how I would do it using just existing Rust (assuming this hasn't > all changed under me in the past couple months). > NB: I haven't actually tried compiling this, but I'm pretty sure it (or > something like it) would work. > > Nice properties over this solution: > - Doesn't require language extensions (although syntax sugar wouldn't be > unwelcome) > - Doesn't require trait objects (i.e. static dispatch is possible) > - Only need to implement one method for each derived type (super) in > addition to overridden methods > - Supports multiple inheritance in two ways (and avoids the diamond > problem I think -- not a C++ expert so I may have misunderstood that) > + no default parent and programmer must select which parent to use > before calling > + implementer-chosen default parent and programmer can chose to use > a different parent if desired > > Neutral?: > - Doesn't enforce or care about the prefix property. Not sure if that > still matters so much w/o dynamic dispatch. > > Downsides: > - Performance of delegation depends on LLVM's ability to inline (I think). > - Does require repeating all the methods once (for delegating default > implementations) > > // The base type > struct Base { > data : int; > } > > // Characterize it's extensible behavior in a trait > trait Trait { > fn method(&self); > } > > // Implement the base behavior > impl Trait for Base { > fn method(&self) { ... } > } > > // Extension of trait that supports upcasting to existing implementations > trait DerivingTrait

: Trait { > // one extra method for accessing a parent's implementation. ideally > this would be inlined by the compiler > fn super(&self) -> P; > // default implementations for all the methods in Trait let us avoid > writing delegation everywhere manually > fn method(&self) { > self.super().method() // just delegate to parent > } > } > > // Single inheritance > struct Single { > parent: Base, > moreData: int, > } > > impl DerivingTrait for Single { > fn super(&self) -> Base { self.parent } > } > > // Overriding behavior > struct Override { > parent: Base, > otherData: u8, > } > > impl DerivingTrait for Override { > fn super(&self) -> Base { self.parent } > fn method(&self) { ... } > } > > // Multiple inheritance > struct Multiple { > single: Single, > override: Override, > evenMoreData: ~str, > } > > // must specify which parent's implementation we want (could hide wrapping > inside of as_* methods impl'd on Multiple if you like) > // if we want one of them as the default, then we can impl DerivingTrait > on Multiple directly > struct MultipleAsSingle(Multiple); > struct MultipleAsOverride(Multiple); > > impl DerivingTrait for MultipleAsSingle { > fn super(&self) -> Single { self.single } > } > > impl DerivingTrait for MultipleAsOverride { > fn super(&self) -> Override { self.override } > } > > fn main() { > let base = Base { ... }; > let single = Single { ... }; > let override = Override { ... }; > let multiple = Multiple { ... }; > > base.method(); > base.super(); // compile time error > > single.method(); // =inline delegation=> single.super().method() > =inline upcast=> single.base.method() > override.method(); // done! no delegating > MultipleAsSingle(multiple).method(); // =delegate=> > MAS(multiple).super().method() =upcast=> multiple.single.method() > =delegate=> multiple.single.super().method() =upcast=> > multiple.single.base.method() > MutlipleAsOverride(multiple).method(); // =delegate=> > MAO(multiple).super().method() =upcast=> multiple.override.method() > } > > Thoughts? > > Eric > > > On Tue, Nov 12, 2013 at 10:30 PM, Kevin Ballard wrote: > >> On Nov 12, 2013, at 10:26 PM, Kevin Ballard wrote: >> >> > And even that restriction could be lifted if ~Trait objects could be >> represented using an array of pointers (one to each inherited struct), e.g. >> ([*A,*B,*C],*vtable) instead of just (*A,*vtable), though I suspect this is >> not worth doing. >> >> Upon further reflection, this would need to be done anyway because of >> the ability to combine traits. If I have >> >> trait TraitA : A {} >> trait TraitB : B {} >> >> and I want to use ~TraitA+TraitB then I would need a "fat" trait. >> Although in this case the number of value pointers is equal to the number >> of combined traits, so it's a bit more sensible to allow for "fat" trait >> pointers here. >> >> -Kevin >> _______________________________________________ >> 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: From ecreed at cs.washington.edu Wed Nov 13 02:21:18 2013 From: ecreed at cs.washington.edu (Eric Reed) Date: Wed, 13 Nov 2013 02:21:18 -0800 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> <52830794.3070504@mozilla.com> <129CF8DC-08FB-43B8-8A8B-985C254A5AEA@sb.org> <9859FE7A-3F11-4317-9491-6EEB4F4157AF@sb.org> Message-ID: I'm not clear on why LLVM wouldn't be able to inline super() calls. It's static dispatch, so it knows exactly what function is being called. On Wed, Nov 13, 2013 at 1:25 AM, Oren Ben-Kiki wrote: > This is probably as good as we can get in the current system (I do > something similar in my code today). > > I also think you probably need both "super" and "mut_super", so it would > be two methods to implement instead of one (still pretty good). I wonder > whether it is possible to write a macro that automates writing these > boilerplate methods? > > The key weakness is that (I think) the compiler can't inline the accesses > to "super" so that you end up with a chain of virtual function calls every > time it is accessed, so performance would be pretty bad. > > > On Wed, Nov 13, 2013 at 10:27 AM, Eric Reed wrote: > >> Here's how I would do it using just existing Rust (assuming this hasn't >> all changed under me in the past couple months). >> NB: I haven't actually tried compiling this, but I'm pretty sure it (or >> something like it) would work. >> >> Nice properties over this solution: >> - Doesn't require language extensions (although syntax sugar wouldn't be >> unwelcome) >> - Doesn't require trait objects (i.e. static dispatch is possible) >> - Only need to implement one method for each derived type (super) in >> addition to overridden methods >> - Supports multiple inheritance in two ways (and avoids the diamond >> problem I think -- not a C++ expert so I may have misunderstood that) >> + no default parent and programmer must select which parent to use >> before calling >> + implementer-chosen default parent and programmer can chose to use >> a different parent if desired >> >> Neutral?: >> - Doesn't enforce or care about the prefix property. Not sure if that >> still matters so much w/o dynamic dispatch. >> >> Downsides: >> - Performance of delegation depends on LLVM's ability to inline (I think). >> - Does require repeating all the methods once (for delegating default >> implementations) >> >> // The base type >> struct Base { >> data : int; >> } >> >> // Characterize it's extensible behavior in a trait >> trait Trait { >> fn method(&self); >> } >> >> // Implement the base behavior >> impl Trait for Base { >> fn method(&self) { ... } >> } >> >> // Extension of trait that supports upcasting to existing implementations >> trait DerivingTrait

: Trait { >> // one extra method for accessing a parent's implementation. ideally >> this would be inlined by the compiler >> fn super(&self) -> P; >> // default implementations for all the methods in Trait let us avoid >> writing delegation everywhere manually >> fn method(&self) { >> self.super().method() // just delegate to parent >> } >> } >> >> // Single inheritance >> struct Single { >> parent: Base, >> moreData: int, >> } >> >> impl DerivingTrait for Single { >> fn super(&self) -> Base { self.parent } >> } >> >> // Overriding behavior >> struct Override { >> parent: Base, >> otherData: u8, >> } >> >> impl DerivingTrait for Override { >> fn super(&self) -> Base { self.parent } >> fn method(&self) { ... } >> } >> >> // Multiple inheritance >> struct Multiple { >> single: Single, >> override: Override, >> evenMoreData: ~str, >> } >> >> // must specify which parent's implementation we want (could hide >> wrapping inside of as_* methods impl'd on Multiple if you like) >> // if we want one of them as the default, then we can impl DerivingTrait >> on Multiple directly >> struct MultipleAsSingle(Multiple); >> struct MultipleAsOverride(Multiple); >> >> impl DerivingTrait for MultipleAsSingle { >> fn super(&self) -> Single { self.single } >> } >> >> impl DerivingTrait for MultipleAsOverride { >> fn super(&self) -> Override { self.override } >> } >> >> fn main() { >> let base = Base { ... }; >> let single = Single { ... }; >> let override = Override { ... }; >> let multiple = Multiple { ... }; >> >> base.method(); >> base.super(); // compile time error >> >> single.method(); // =inline delegation=> single.super().method() >> =inline upcast=> single.base.method() >> override.method(); // done! no delegating >> MultipleAsSingle(multiple).method(); // =delegate=> >> MAS(multiple).super().method() =upcast=> multiple.single.method() >> =delegate=> multiple.single.super().method() =upcast=> >> multiple.single.base.method() >> MutlipleAsOverride(multiple).method(); // =delegate=> >> MAO(multiple).super().method() =upcast=> multiple.override.method() >> } >> >> Thoughts? >> >> Eric >> >> >> On Tue, Nov 12, 2013 at 10:30 PM, Kevin Ballard wrote: >> >>> On Nov 12, 2013, at 10:26 PM, Kevin Ballard wrote: >>> >>> > And even that restriction could be lifted if ~Trait objects could be >>> represented using an array of pointers (one to each inherited struct), e.g. >>> ([*A,*B,*C],*vtable) instead of just (*A,*vtable), though I suspect this is >>> not worth doing. >>> >>> Upon further reflection, this would need to be done anyway because of >>> the ability to combine traits. If I have >>> >>> trait TraitA : A {} >>> trait TraitB : B {} >>> >>> and I want to use ~TraitA+TraitB then I would need a "fat" trait. >>> Although in this case the number of value pointers is equal to the number >>> of combined traits, so it's a bit more sensible to allow for "fat" trait >>> pointers here. >>> >>> -Kevin >>> _______________________________________________ >>> 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: From danielmicay at gmail.com Wed Nov 13 02:45:19 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 05:45:19 -0500 Subject: [rust-dev] The future of M:N threading Message-ID: Before getting right into the gritty details about why I think we should think about a path away from M:N scheduling, I'll go over the details of the concurrency model we currently use. Rust uses a user-mode scheduler to cooperatively schedule many tasks onto OS threads. Due to the lack of preemption, tasks need to manually yield control back to the scheduler. Performing I/O with the standard library will block the *task*, but yield control back to the scheduler until the I/O is completed. The scheduler manages a thread pool where the unit of work is a task rather than a queue of closures to be executed or data to be pass to a function. A task consists of a stack, register context and task-local storage much like an OS thread. In the world of high-performance computing, this is a proven model for maximizing throughput for CPU-bound tasks. By abandoning preemption, there's zero overhead from context switches. For socket servers with only negligible server-side computations the avoidance of context switching is a boon for scalability and predictable performance. # Lightweight? Rust's tasks are often called *lightweight* but at least on Linux the only optimization is the lack of preemption. Since segmented stacks have been dropped, the resident/virtual memory usage will be identical. # Spawning performance An OS thread can actually spawn nearly as fast as a Rust task on a system with one CPU. On a multi-core system, there's a high chance of the new thread being spawned on a different CPU resulting in a performance loss. Sample C program, if you need to see it to believe it: ``` #include #include static const size_t n_thread = 100000; static void *foo(void *arg) { return arg; } int main(void) { for (size_t i = 0; i < n_thread; i++) { pthread_attr_t attr; if (pthread_attr_init(&attr) < 0) { return 1; } if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) < 0) { return 1; } pthread_t thread; if (pthread_create(&thread, &attr, foo, NULL) < 0) { return 1; } } pthread_exit(NULL); } ``` Sample Rust program: ``` fn main() { for _ in range(0, 100000) { do spawn { } } } ``` For both programs, I get around 0.9s consistently when pinned to a core. The Rust version drops to 1.1s when not pinned and the OS thread one to about 2s. It drops further when asked to allocate 8MiB stacks like C is doing, and will drop more when it has to do `mmap` and `mprotect` calls like the pthread API. # Asynchronous I/O Rust's requirements for asynchronous I/O would be filled well by direct usage of IOCP on Windows. However, Linux only has solid support for non-blocking sockets because file operations usually just retrieve a result from cache and do not truly have to block. This results in libuv being significantly slower than blocking I/O for most common cases for the sake of scalable socket servers. On modern systems with flash memory, including mobile, there is a *consistent* and relatively small worst-case latency for accessing data on the disk so blocking is essentially a non-issue. Memory mapped I/O is also an incredibly important feature for I/O performance, and there's almost no reason to use traditional I/O on 64-bit. However, it's a no-go with M:N scheduling because the page faults block the thread. # Overview Advantages: * lack of preemptive/fair scheduling, leading to higher throughput * very fast context switches to other tasks on the same scheduler thread Disadvantages: * lack of preemptive/fair scheduling (lower-level model) * poor profiler/debugger support * async I/O stack is much slower for the common case; for example stat is 35x slower when run in a loop for an mlocate-like utility * true blocking code will still block a scheduler thread * most existing libraries use blocking I/O and OS threads * cannot directly use fast and easy to use linker-supported thread-local data * many existing libraries rely on thread-local storage, so there's a need to be wary of hidden yields in Rust function calls and it's very difficult to expose a safe interface to these libraries * every level of a CPU architecture adding registers needs explicit support from Rust, and it must be selected at runtime when not targeting a specific CPU (this is currently not done correctly) # User-mode scheduling Windows 7 introduced user-mode scheduling[1] to replace fibers on 64-bit. Google implemented the same thing for Linux (perhaps even before Windows 7 was released), and plans on pushing for it upstream.[2] The linked video does a better job of covering this than I can. User-mode scheduling provides a 1:1 threading model including full support for normal thread-local data and existing debuggers/profilers. It can yield to the scheduler on system calls and page faults. The operating system is responsible for details like context switching, so a large maintenance/portability burden is dealt with. It narrows down the above disadvantage list to just the point about not having preemptive/fair scheduling and doesn't introduce any new ones. I hope this is where concurrency is headed, and I hope Rust doesn't miss this boat by concentrating too much on libuv. I think it would allow us to simply drop support for pseudo-blocking I/O in the Go style and ignore asynchronous I/O and non-blocking sockets in the standard library. It may be useful to have the scheduler use them, but it wouldn't be essential. [1] http://msdn.microsoft.com/en-us/library/windows/desktop/dd627187(v=vs.85).aspx [2] http://www.youtube.com/watch?v=KXuZi9aeGTw From danielmicay at gmail.com Wed Nov 13 02:55:16 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 05:55:16 -0500 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: > It may be useful to have the scheduler use them, but it wouldn't be essential. To clarify this, it definitely wouldn't make sense to design *fake* asynchronous APIs on top of threads anymore. On Linux, we would probably only want to use non-blocking sockets and even that might become unnecessary. From oren at ben-kiki.org Wed Nov 13 03:46:25 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Wed, 13 Nov 2013 13:46:25 +0200 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> <52830794.3070504@mozilla.com> <129CF8DC-08FB-43B8-8A8B-985C254A5AEA@sb.org> <9859FE7A-3F11-4317-9491-6EEB4F4157AF@sb.org> Message-ID: The call isn't statically dispatched when I invoke a method via a trait pointer. So it seems when I invoke any trait function, I pay double the cost of a virtual function call instead of one... I suppose it isn't _too_ bad, but it still hurts. On Wed, Nov 13, 2013 at 12:21 PM, Eric Reed wrote: > I'm not clear on why LLVM wouldn't be able to inline super() calls. It's > static dispatch, so it knows exactly what function is being called. > > > On Wed, Nov 13, 2013 at 1:25 AM, Oren Ben-Kiki wrote: > >> This is probably as good as we can get in the current system (I do >> something similar in my code today). >> >> I also think you probably need both "super" and "mut_super", so it would >> be two methods to implement instead of one (still pretty good). I wonder >> whether it is possible to write a macro that automates writing these >> boilerplate methods? >> >> The key weakness is that (I think) the compiler can't inline the accesses >> to "super" so that you end up with a chain of virtual function calls every >> time it is accessed, so performance would be pretty bad. >> >> >> On Wed, Nov 13, 2013 at 10:27 AM, Eric Reed wrote: >> >>> Here's how I would do it using just existing Rust (assuming this hasn't >>> all changed under me in the past couple months). >>> NB: I haven't actually tried compiling this, but I'm pretty sure it (or >>> something like it) would work. >>> >>> Nice properties over this solution: >>> - Doesn't require language extensions (although syntax sugar wouldn't be >>> unwelcome) >>> - Doesn't require trait objects (i.e. static dispatch is possible) >>> - Only need to implement one method for each derived type (super) in >>> addition to overridden methods >>> - Supports multiple inheritance in two ways (and avoids the diamond >>> problem I think -- not a C++ expert so I may have misunderstood that) >>> + no default parent and programmer must select which parent to use >>> before calling >>> + implementer-chosen default parent and programmer can chose to >>> use a different parent if desired >>> >>> Neutral?: >>> - Doesn't enforce or care about the prefix property. Not sure if that >>> still matters so much w/o dynamic dispatch. >>> >>> Downsides: >>> - Performance of delegation depends on LLVM's ability to inline (I >>> think). >>> - Does require repeating all the methods once (for delegating default >>> implementations) >>> >>> // The base type >>> struct Base { >>> data : int; >>> } >>> >>> // Characterize it's extensible behavior in a trait >>> trait Trait { >>> fn method(&self); >>> } >>> >>> // Implement the base behavior >>> impl Trait for Base { >>> fn method(&self) { ... } >>> } >>> >>> // Extension of trait that supports upcasting to existing implementations >>> trait DerivingTrait

: Trait { >>> // one extra method for accessing a parent's implementation. ideally >>> this would be inlined by the compiler >>> fn super(&self) -> P; >>> // default implementations for all the methods in Trait let us avoid >>> writing delegation everywhere manually >>> fn method(&self) { >>> self.super().method() // just delegate to parent >>> } >>> } >>> >>> // Single inheritance >>> struct Single { >>> parent: Base, >>> moreData: int, >>> } >>> >>> impl DerivingTrait for Single { >>> fn super(&self) -> Base { self.parent } >>> } >>> >>> // Overriding behavior >>> struct Override { >>> parent: Base, >>> otherData: u8, >>> } >>> >>> impl DerivingTrait for Override { >>> fn super(&self) -> Base { self.parent } >>> fn method(&self) { ... } >>> } >>> >>> // Multiple inheritance >>> struct Multiple { >>> single: Single, >>> override: Override, >>> evenMoreData: ~str, >>> } >>> >>> // must specify which parent's implementation we want (could hide >>> wrapping inside of as_* methods impl'd on Multiple if you like) >>> // if we want one of them as the default, then we can impl DerivingTrait >>> on Multiple directly >>> struct MultipleAsSingle(Multiple); >>> struct MultipleAsOverride(Multiple); >>> >>> impl DerivingTrait for MultipleAsSingle { >>> fn super(&self) -> Single { self.single } >>> } >>> >>> impl DerivingTrait for MultipleAsOverride { >>> fn super(&self) -> Override { self.override } >>> } >>> >>> fn main() { >>> let base = Base { ... }; >>> let single = Single { ... }; >>> let override = Override { ... }; >>> let multiple = Multiple { ... }; >>> >>> base.method(); >>> base.super(); // compile time error >>> >>> single.method(); // =inline delegation=> single.super().method() >>> =inline upcast=> single.base.method() >>> override.method(); // done! no delegating >>> MultipleAsSingle(multiple).method(); // =delegate=> >>> MAS(multiple).super().method() =upcast=> multiple.single.method() >>> =delegate=> multiple.single.super().method() =upcast=> >>> multiple.single.base.method() >>> MutlipleAsOverride(multiple).method(); // =delegate=> >>> MAO(multiple).super().method() =upcast=> multiple.override.method() >>> } >>> >>> Thoughts? >>> >>> Eric >>> >>> >>> On Tue, Nov 12, 2013 at 10:30 PM, Kevin Ballard wrote: >>> >>>> On Nov 12, 2013, at 10:26 PM, Kevin Ballard wrote: >>>> >>>> > And even that restriction could be lifted if ~Trait objects could be >>>> represented using an array of pointers (one to each inherited struct), e.g. >>>> ([*A,*B,*C],*vtable) instead of just (*A,*vtable), though I suspect this is >>>> not worth doing. >>>> >>>> Upon further reflection, this would need to be done anyway because of >>>> the ability to combine traits. If I have >>>> >>>> trait TraitA : A {} >>>> trait TraitB : B {} >>>> >>>> and I want to use ~TraitA+TraitB then I would need a "fat" trait. >>>> Although in this case the number of value pointers is equal to the number >>>> of combined traits, so it's a bit more sensible to allow for "fat" trait >>>> pointers here. >>>> >>>> -Kevin >>>> _______________________________________________ >>>> 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: From denis.spir at gmail.com Wed Nov 13 04:55:56 2013 From: denis.spir at gmail.com (spir) Date: Wed, 13 Nov 2013 13:55:56 +0100 Subject: [rust-dev] mutability cascade Message-ID: <528376DC.1060901@gmail.com> Hello, I have an error "cannot assign to immutable field". However, it is mutable as I understand according to "inherited mutability" rule exposed in the tutorial (section 'Structs'). The field in question is in a struct itself item of an array, itself field in a super-structure (lol!) which is self. All this happens in a method called on "&mut self". (And the compiler lets me change self elsewhere in the same method.) Thus, what is wrong? Or is it so that the mutability cascade is broken due to the array? How then restore it and be able to change a struct item's field? I guess arrays are mutable by default aren't they? (Or else, here it should due to inherited mutability, since it is a field of a mutable struct.) What do I miss? [Code below untested yet due to error.] fn expand (&mut self) { // A mod table expands by doubling its list bucket capacity. // Double array of lists, initially filled with NO_CELL values. let NO_CELL : uint = -1 as uint; // flag for end-of-list self.n_lists *= 2; self.lists = vec::from_elem(self.n_lists, NO_CELL); // replace cells into correct lists according to new key modulo. let mut i_list : uint; let mut i_cell : uint = 0; for cell in self.cells.iter() { // Link cell at start of correct list. i_list = cell.key % self.n_lists; cell.i_next = self.lists[i_list]; // ERROR *** self.lists[i_list] = i_cell; i_cell += 1; } } I take the opportunity to ask whether there's an (i, item) iterator for arrays. Thank you, Denis From dbau.pp at gmail.com Wed Nov 13 05:06:30 2013 From: dbau.pp at gmail.com (Huon Wilson) Date: Thu, 14 Nov 2013 00:06:30 +1100 Subject: [rust-dev] mutability cascade In-Reply-To: <528376DC.1060901@gmail.com> References: <528376DC.1060901@gmail.com> Message-ID: <52837956.3080409@gmail.com> On 13/11/13 23:55, spir wrote: > Hello, > > I have an error "cannot assign to immutable field". However, it is > mutable as I understand according to "inherited mutability" rule > exposed in the tutorial (section 'Structs'). The field in question is > in a struct itself item of an array, itself field in a super-structure > (lol!) which is self. All this happens in a method called on "&mut > self". (And the compiler lets me change self elsewhere in the same > method.) > Thus, what is wrong? Or is it so that the mutability cascade is broken > due to the array? How then restore it and be able to change a struct > item's field? I guess arrays are mutable by default aren't they? (Or > else, here it should due to inherited mutability, since it is a field > of a mutable struct.) > What do I miss? You need to use the .mut_iter() method, [T].iter() yields &T references, while the former yields &mut T references (and can only be used on vectors that have mutable contents, like ~[T] in a mutable slot, or &mut [T] or @mut [T]). http://static.rust-lang.org/doc/master/std/vec/trait.MutableVector.html#tymethod.mut_iter (Unfortunately the docs are not good with respect to built-in types. Methods can only be implemented on built-ins via traits, and the indication that the built-ins implement a trait is only shown on the page for the trait itself.) > [Code below untested yet due to error.] > > fn expand (&mut self) { > // A mod table expands by doubling its list bucket capacity. > // Double array of lists, initially filled with NO_CELL values. > let NO_CELL : uint = -1 as uint; // flag for end-of-list > self.n_lists *= 2; > self.lists = vec::from_elem(self.n_lists, NO_CELL); > > // replace cells into correct lists according to new key modulo. > let mut i_list : uint; > let mut i_cell : uint = 0; > for cell in self.cells.iter() { > // Link cell at start of correct list. > i_list = cell.key % self.n_lists; > cell.i_next = self.lists[i_list]; // ERROR *** > self.lists[i_list] = i_cell; > i_cell += 1; > } > } > > I take the opportunity to ask whether there's an (i, item) iterator > for arrays. You can use the .enumerate() method on iterators, so for (i, cell) in self.mut_iter().enumerate() { ... } http://static.rust-lang.org/doc/master/std/iter/trait.Iterator.html#method.enumerate (Also, you will possibly meet with mutable borrow complaints (I'm not 100% sure of this), which you can address by destructuring self, so that the compiler knows all the borrows are disjoint: let StructName { lists: ref mut lists, cells: ref mut cells, n_lists: ref mut n_lists } = *self; and then use `lists`, `cells` and `n_lists` (they are just &mut references pointing to the corresponding fields of self).) Huon From redbrain at gcc.gnu.org Wed Nov 13 07:53:06 2013 From: redbrain at gcc.gnu.org (Philip Herron) Date: Wed, 13 Nov 2013 15:53:06 +0000 Subject: [rust-dev] typing in rust Message-ID: Hey all I am still learning but i just tried something which i expected to give an error but works: fn test () -> int { 1 } fn main () { let test = test (); println (format! ("{}", test)); } I guess on compilation the names are mangled against their types or something so you can differentiate between test the function and test the variable. Not sure would be nice to get some clarification what this behavior is. Thanks --Phil -------------- next part -------------- An HTML attachment was scrubbed... URL: From bytbox at gmail.com Wed Nov 13 07:54:20 2013 From: bytbox at gmail.com (Scott Lawrence) Date: Wed, 13 Nov 2013 10:54:20 -0500 (EST) Subject: [rust-dev] typing in rust In-Reply-To: References: Message-ID: I would think that `test()` (the function) is in scope for the duration of `let test =`, and then the new definition masks the old one. Similarly, let x = 2; let x = x + 2; If you change the last line to /call/ test(), you should get an error. On Wed, 13 Nov 2013, Philip Herron wrote: > Hey all > > I am still learning but i just tried something which i expected to give an > error but works: > > fn test () -> int { > 1 > } > > fn main () { > let test = test (); > println (format! ("{}", test)); > } > > I guess on compilation the names are mangled against their types or > something so you can differentiate between test the function and test the > variable. Not sure would be nice to get some clarification what this > behavior is. > > Thanks > > --Phil > -- Scott Lawrence From redbrain at gcc.gnu.org Wed Nov 13 08:03:46 2013 From: redbrain at gcc.gnu.org (Philip Herron) Date: Wed, 13 Nov 2013 16:03:46 +0000 Subject: [rust-dev] typing in rust In-Reply-To: References: Message-ID: Hey Ahh that makes sense! Thanks On 13 November 2013 15:54, Scott Lawrence wrote: > I would think that `test()` (the function) is in scope for the duration of > `let test =`, and then the new definition masks the old one. Similarly, > > let x = 2; > let x = x + 2; > > If you change the last line to /call/ test(), you should get an error. > > > On Wed, 13 Nov 2013, Philip Herron wrote: > > Hey all >> >> I am still learning but i just tried something which i expected to give an >> error but works: >> >> fn test () -> int { >> 1 >> } >> >> fn main () { >> let test = test (); >> println (format! ("{}", test)); >> } >> >> I guess on compilation the names are mangled against their types or >> something so you can differentiate between test the function and test the >> variable. Not sure would be nice to get some clarification what this >> behavior is. >> >> Thanks >> >> --Phil >> >> > -- > Scott Lawrence > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From niko at alum.mit.edu Wed Nov 13 08:06:11 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Wed, 13 Nov 2013 11:06:11 -0500 Subject: [rust-dev] linking to cells inside a data structure In-Reply-To: References: <52821E14.5010509@gmail.com> Message-ID: <20131113160611.GB17283@Mr-Bennet> On Tue, Nov 12, 2013 at 02:51:53PM +0200, Oren Ben-Kiki wrote: > First, if the array holds values (as opposed to pointers to values), then > pretty much your only option is to replace your pointers with indices to > the array. You'd need access to the container to access the values, of > course. But this is the only safe way because adding into the array may > relocate it, invalidating all pointers. Using newtype'd indices is my personal preference at the moment. I find it works out quite elegantly in practice for self-contained data structures. > I wish there was a way to say "this borrowed pointer lives only as > long as its container". That doesn't seem to be in the cards though > :-( I wouldn't go that far. I do hope for us to solve this elegantly in the future. But it's true that there is enough on our plate and I don't want to think it right now. But we basically covered this in prior threads, iirc. [1, 2] The idea of a lifetime that means "as long as the struct it is attached to" is a solid one, but I don't think we can do that AND permit the struct to be moved without something like the `Message` [1] type I sketched out. Otherwise I don't know how we could guarantee that there are no outstanding borrowed pointers at the time of move -- well, I take that back: we could possibly permit `return` statements that exit the struct's current scope, but that's it. Niko [1] https://mail.mozilla.org/pipermail/rust-dev/2013-November/006304.html [2] https://mail.mozilla.org/pipermail/rust-dev/2013-October/006172.html For some reason, I can't find a link in the archives to the message that I sent, only Oren's reply, but you can see it quoted below. From niko at alum.mit.edu Wed Nov 13 08:08:49 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Wed, 13 Nov 2013 11:08:49 -0500 Subject: [rust-dev] linking to cells inside a data structure In-Reply-To: <52822965.7090004@mozilla.com> References: <52821E14.5010509@gmail.com> <52822965.7090004@mozilla.com> Message-ID: <20131113160849.GC17283@Mr-Bennet> > I don't know how to make that sound, unfortunately, other than using > an arena and allocating all the nodes into it (losing the ability to > deallocate individual nodes). Arenas don't require that you lose the ability to deallocate individual nodes. See my thoughts in #10444. Briefly, the idea is that the arena allocation returns an affine type like `ArenaAlloc<'self>`. You can then have a free method that consumes this instance and adds it to a free list to be reused for future allocation. Niko From oren at ben-kiki.org Wed Nov 13 08:10:53 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Wed, 13 Nov 2013 18:10:53 +0200 Subject: [rust-dev] linking to cells inside a data structure In-Reply-To: <20131113160849.GC17283@Mr-Bennet> References: <52821E14.5010509@gmail.com> <52822965.7090004@mozilla.com> <20131113160849.GC17283@Mr-Bennet> Message-ID: You are right that the compiler needs to ensure no pointers escape the struct itself, so it is OK to move it (and all the pointers it includes). Intuitively this would require another level of static type checking (whether there are existing outside-the-struct borrowed pointers at any point), probably not easy to do. On Wed, Nov 13, 2013 at 6:08 PM, Niko Matsakis wrote: > > I don't know how to make that sound, unfortunately, other than using > > an arena and allocating all the nodes into it (losing the ability to > > deallocate individual nodes). > > Arenas don't require that you lose the ability to deallocate > individual nodes. See my thoughts in #10444. Briefly, the idea is that > the arena allocation returns an affine type like `ArenaAlloc<'self>`. > You can then have a free method that consumes this instance and adds > it to a free list to be reused for future allocation. > > > > > Niko > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From bytemr at gmail.com Wed Nov 13 08:25:31 2013 From: bytemr at gmail.com (Joshua Rodgers) Date: Wed, 13 Nov 2013 09:25:31 -0700 Subject: [rust-dev] typing in rust In-Reply-To: References: Message-ID: I'm curious as to why this is valid, though? This makes sense if you're inside a new or nested scope, but why is it valid inside the same scope as illustrated in the code example? I can understand it from the perspective that I need to mask a function name (but that's a nested scope to me, at that point). On Wed, Nov 13, 2013 at 8:54 AM, Scott Lawrence wrote: > I would think that `test()` (the function) is in scope for the duration of > `let test =`, and then the new definition masks the old one. Similarly, > > let x = 2; > let x = x + 2; > > If you change the last line to /call/ test(), you should get an error. > > > On Wed, 13 Nov 2013, Philip Herron wrote: > > Hey all >> >> I am still learning but i just tried something which i expected to give an >> error but works: >> >> fn test () -> int { >> 1 >> } >> >> fn main () { >> let test = test (); >> println (format! ("{}", test)); >> } >> >> I guess on compilation the names are mangled against their types or >> something so you can differentiate between test the function and test the >> variable. Not sure would be nice to get some clarification what this >> behavior is. >> >> Thanks >> >> --Phil >> >> > -- > Scott Lawrence > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rusty.gates at icloud.com Wed Nov 13 08:28:50 2013 From: rusty.gates at icloud.com (Tommi) Date: Wed, 13 Nov 2013 18:28:50 +0200 Subject: [rust-dev] UFCS / Pseudo-members Message-ID: <9070A8BB-B007-4FBE-9F99-AFEEA38A1A09@icloud.com> There's been talk about Uniform Function (Call) Syntax (sometimes called pseudo-members, which I think is a more informative term) and I just wanted chime in too. There are two completely different goals UFCS tries to help to achieve: 1) Better encapsulation http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197 2) The dream of highly reusable code (through "component programming") http://www.drdobbs.com/architecture-and-design/component-programming-in-d/240008321 Although, I think this video explains "component programming" better and it's a pretty entertaining talk too: http://www.youtube.com/watch?v=0cX1f41Fnkc -Tommi -------------- next part -------------- An HTML attachment was scrubbed... URL: From niko at alum.mit.edu Wed Nov 13 08:30:00 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Wed, 13 Nov 2013 11:30:00 -0500 Subject: [rust-dev] Danger of throwing exceptions through Rust code In-Reply-To: References: Message-ID: <20131113163000.GD17283@Mr-Bennet> The interplay between exceptions and foreign code is a complicated topic. Here are some miscellaneous thoughts. 1. I don't believe there is any memory safety reason we could not support catchable exceptions in Rust. The main concern is more one of good design; it's difficult to recover meaningfully and correctly from an exception. Generally the best thing to do, particularly in an interactive application, is to catch the exception up at a high level (an event loop, say) and try to throw away all the affected state and start over. Tasks provide a wonderful abstraction for doing this, of course. 2. Now, that said, some exceptions are expected and should be caught. File not found and so forth. Java recognized this distinction and called those checked exceptions; for various reasons, this is a pain in the neck to work with. But erasing the distinction, as many other languages chose to do, has its downsides. Currently the Rust path seems to be the same as Haskell -- use the return type, specifically `Result<>` or something similar, to indicate common error conditions. If you think about it, this is very analogous to what Java does, but because we are using types, we support parameteric error handling -- that is, you can have generic wrappers that return a `Result` iff the thing they are wrapping returns a `Result` (which Java can't do). 3. Presuming we want to keep the above philosophy (which I personally like, I find exception handlers to be awkward at the best of times), there is still the question of what to do when a C library fails. The C library will (typically) indicate this by returning an error code in some fashion. Ideally, the Rust task would observe this error code and then fail in response. OK, so far so good. (If the callee does not signal errors by returning a result code, then Rust probably won't be able to respond to it. We can't generate cleanup code for every possible exception scheme. So I think the best thing here would be for the author to insert a shim that intercepts exceptions and translates them to a return code.) 4. Problems start to occur though when you have interleaved C and Rust code, such as Rust1 -> C -> Rust2. Now what happens if the Rust task fails? A well-designed C callback API will include a way for the Rust task to indicate failure, probably a return code. So, in an ideal world, the Rust code would return this error code when failing. Of course, we can't know in advance what error code would be needed, so that implies that Rust2 must have some way to catch the failure and translate it into the C error code. Hopefully this will cause the C code to unwind and return an error to Rust1, which can then fail! again. This process can be repeated as needed. 5. But what do we do if some C library doens't include error return codes, or doesn't (necessarily) unwind in response to an error? This is a hard question and I think there is no single right answer, instead the person wrapping the library will have to find the right answer for their particular case. For example, Rust1 and Rust2 could communicate using TLS, so that an exception occurring in Rust2 can (eventually) be re-raised in Rust1, even if the C code doesn't consider the possibility of failure. Or maybe the author just doesn't really care if Rust2 fails and they just swallow the failure, violating Rust's failure semantics (because they know better than us for their particular case anyhow). 6. Some would argue that based on that last point, we might as well just permit catch anywhere, and discourage its use. I am sympathetic to this as well though I think Rust's general approach to error handling (which we stole from Erlang) is really the more robust one: when things go wrong, tear it all up, then build it back up again. Still, perhaps community norms are enough here. Niko On Tue, Nov 12, 2013 at 11:07:50AM -0800, Kevin Ballard wrote: > Right now, Rust does not support catching task failure from within a task, it only supports preventing task failure from cascading into other tasks. My understanding is that this limitation is done because of safety; if a task unwinds through a few frames of code, and then stops unwinding, data structure invariants may have been broken by the unwinding, leaving the task in an unsafe state. Is this correct? > > Given this assumption, my worry now is about task unwinding outside of the control of Rust. Namely, if I?m using Rust to write a library with extern ?C? functions, or I?m providing callbacks to C code from within Rust, (and my Rust code calls back into C at some point), then it?s very possible for the called C code to throw an exception that is then caught in the calling C code a few frames up. The net effect is that the thread will unwind through my Rust code, but it will then be caught before unwinding any further, potentially leaving any data structures in an invalid state (assuming that there?s still Rust code higher up on this same stack that cares). > > Has this been considered before? Is this actually a danger or am I just being paranoid? > > -Kevin > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From denis.spir at gmail.com Wed Nov 13 08:35:52 2013 From: denis.spir at gmail.com (spir) Date: Wed, 13 Nov 2013 17:35:52 +0100 Subject: [rust-dev] mutability cascade In-Reply-To: <52837956.3080409@gmail.com> References: <528376DC.1060901@gmail.com> <52837956.3080409@gmail.com> Message-ID: <5283AA68.8080800@gmail.com> On 11/13/2013 02:06 PM, Huon Wilson wrote: > On 13/11/13 23:55, spir wrote: >> Hello, >> >> I have an error "cannot assign to immutable field". [...] > > You need to use the .mut_iter() method, [T].iter() yields &T references, while > the former yields &mut T references (and can only be used on vectors that have > mutable contents, like ~[T] in a mutable slot, or &mut [T] or @mut [T]). > > http://static.rust-lang.org/doc/master/std/vec/trait.MutableVector.html#tymethod.mut_iter Right, that's it, i guess. PS: tested: works fine! > (Unfortunately the docs are not good with respect to built-in types. Methods can > only be implemented on built-ins via traits, and the indication that the > built-ins implement a trait is only shown on the page for the trait itself.) Actually, the vec module's doc tells which traits are implemented [http://static.rust-lang.org/doc/0.8/std/vec/index.html]. However, it's just too much at once for newcomers, in my opinion. There may be a subset of simple, base functionality for vectors (but as someone said, the vec module needs reorganisation). >> I take the opportunity to ask whether there's an (i, item) iterator for arrays. > > You can use the .enumerate() method on iterators, so > > for (i, cell) in self.mut_iter().enumerate() { > ... > } > > http://static.rust-lang.org/doc/master/std/iter/trait.Iterator.html#method.enumerate Right what I needed! PS: tested: works fine! > (Also, you will possibly meet with mutable borrow complaints (I'm not 100% sure > of this), which you can address by destructuring self, so that the compiler > knows all the borrows are disjoint: > > let StructName { lists: ref mut lists, cells: ref mut cells, n_lists: ref > mut n_lists } = *self; > > and then use `lists`, `cells` and `n_lists` (they are just &mut references > pointing to the corresponding fields of self).) > > Huon Haven't met this issue yet, but I keep the pattern under the pillow for later usage. Thank you very much, Huon, for all this clear information. Denis From ben.striegel at gmail.com Wed Nov 13 08:50:08 2013 From: ben.striegel at gmail.com (Benjamin Striegel) Date: Wed, 13 Nov 2013 11:50:08 -0500 Subject: [rust-dev] typing in rust In-Reply-To: References: Message-ID: > but why is it valid inside the same scope as illustrated in the code example? One use is to allow you to alter the mutability of variables as needed (often referred to as "freezing" and "thawing"): let x = 2; // this is immutable ... // do stuff that requires x to be immutable let mut x = x; // make x mutable ... // do stuff that requires x to be mutable let x = x; // make x immutable again And yes, the fact that that last line isn't a no-op is definitely something to watch out for. :) On Wed, Nov 13, 2013 at 11:25 AM, Joshua Rodgers wrote: > I'm curious as to why this is valid, though? This makes sense if you're > inside a new or nested scope, but why is it valid inside the same scope as > illustrated in the code example? > > I can understand it from the perspective that I need to mask a function > name (but that's a nested scope to me, at that point). > > > On Wed, Nov 13, 2013 at 8:54 AM, Scott Lawrence wrote: > >> I would think that `test()` (the function) is in scope for the duration >> of `let test =`, and then the new definition masks the old one. Similarly, >> >> let x = 2; >> let x = x + 2; >> >> If you change the last line to /call/ test(), you should get an error. >> >> >> On Wed, 13 Nov 2013, Philip Herron wrote: >> >> Hey all >>> >>> I am still learning but i just tried something which i expected to give >>> an >>> error but works: >>> >>> fn test () -> int { >>> 1 >>> } >>> >>> fn main () { >>> let test = test (); >>> println (format! ("{}", test)); >>> } >>> >>> I guess on compilation the names are mangled against their types or >>> something so you can differentiate between test the function and test the >>> variable. Not sure would be nice to get some clarification what this >>> behavior is. >>> >>> Thanks >>> >>> --Phil >>> >>> >> -- >> Scott Lawrence >> _______________________________________________ >> 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: From vadimcn at gmail.com Wed Nov 13 09:06:14 2013 From: vadimcn at gmail.com (Vadim) Date: Wed, 13 Nov 2013 09:06:14 -0800 Subject: [rust-dev] Greenlets in Rust (was: Abandoning segmented stacks in Rust) In-Reply-To: References: Message-ID: They don't share state. The language-level semantics of greenlets is the same as that of tasks, except that they are scheduled cooperatively. All these games with the stack should be unobservable on Rust level. On Wed, Nov 13, 2013 at 1:01 AM, Eric Reed wrote: > The big issue I see right away (assuming I read this correctly and > greenlets can still access the stack that existed when they were created), > is that now mutable state on the stack is *shared* between greenlets and > therefore can experience *data races* (impossible for tasks b/c they > don't share memory), so they sound wildly unsafe to me. > > There may be some other issues that arise from the shared stack prefix > property: > - If a greenlet moves something on the stack, then other greenlets now > have access to invalidated memory > - You can no longer assume that you have sole access things pointed to by > unique pointers, which would probably invalidate a lot of existing > assumptions. > > Eric > > > On Wed, Nov 13, 2013 at 12:02 AM, Vadim wrote: > >> Hi, >> I would like to float a proposal (or three :-), regarding "greenlets" in >> Rust. For those unfamiliar with greenlets, they are a tool for writing >> concurrent code, similar to Rust's tasks, but much more light-weight in >> terms of memory consumption (especially now that segmented stacks are no >> more). >> >> I think there are some scenarios where low memory consumption per-task is >> still important, 64-bit address spaces notwithstanding. A typical one >> would be a pub-sub server, which needs to maintain a massive number of >> simple I/O workflows, where I/O channels are idle most of the time. >> >> So here we go (in the order of increasing craziness): >> >> 1. Recently I've learned how Python greenletsare >> implemented . I believe that the >> same approach could work in Rust: >> >> Basically, greenlets are spawned using the same stack as the parent >> greenlet, just like a normal function call. When a greenlet is suspended, >> it copies the portion of the stack used up since its' spawning to the >> heap. When one is re-activated, the saved memory is copied back where it >> came from (having first saved stack of the previous active greenlet,- if >> they overlap). >> >> Since greenlets don't need to save "red zone" of the stack, the amount of >> data per instance is precisely what is actually used. >> >> There are also downsides, of course: >> - greenlets are bound to the thread that spawned them, >> - two memcpy's are needed when switching between them. >> >> In the case of Python, though, there's one further optimization: since >> Python's stack frames live on the heap, in most cases, there nothing on the >> hardware stack that a greenlet needs saving! As a bonus, it can now be >> resumed at any stack position, so no saving of previous greenlet's stack is >> needed. The only time when a full save occurs is when there are foreign >> stack frames on the stack. >> >> >> 2. Well, can Rust do the same? What if we came up with an attribute, >> say, [#stackless], which causes a function to allocate it's stack frame on >> the heap and put all local vars there? The only things on the actual >> hardware stack would then be the function's arguments, the return address, >> the saved base pointer and the pointer to that heap-alllocated frame. >> With the exception of base pointers, all these things are >> position-independent, I believe. And base pointer chain can be easily >> fixed up if/when stack is moved. >> >> So if we had that, and the whole greenlet's stack consisted of such >> functions, and there was a way for the "switch_to_greenlet()" function to >> detect that, then such greenlet's stack would be relocatable and could be >> resumed at any position in the thread's stack (or even in another thread!) >> with minimal memory copying, just like in Python. >> >> Of course, the [#stackless] functions would be slower than the normal >> ones, but in the scenario I've outlined in the beginning, it shouldn't be a >> problem. >> >> >> 3. Unfortunately, in order for the above scheme to work, all I/O >> methods, (which are typically where yields happen), would need to be marked >> as [#stackless]... This would affect the performance of "normal" code >> using the same API, which is undesirable. >> >> Okay, but usually there are not *that *many things that point into the >> stack in a typical program. I can think of only three things: references >> to stack-allocated buffers, base pointer chains and references to >> caller-allocated return values. >> - The first one can be lived without - just allocate buffers on the heap. >> - The second one - see above. >> - The last one is more tricky, but for the sake of argument, let's assume >> that we restricted function signatures such that only register-allocated >> types can be returned. >> >> Let's say we came up with a way to mark up functions that may yield to >> another greenlet, and also with a way to prohibit taking address of >> stack-allocated variables for the duration of calls to yielding functions. >> These restrictions would be annoying, but not overly so, as long as you >> had to obey them only in functions that are intended to be run in a >> greenlet. >> On the plus side, the hardware stack contents would now be relocatable. >> >> In this setup, everything could proceed as usual, using the hardware >> stack, until execution came to a blocking I/O call. At that point, the >> scheduler would check if running inside a greenlet, copy greenlet's stack >> to the heap and switch off to another greenlet. Otherwise, it would do the >> same thing it does now, i.e. switch tasks. >> >> >> So, what do you say, rustafarians? Does any of that make any sense? >> >> Vadim >> >> >> On Tue, Nov 5, 2013 at 9:18 AM, Patrick Walton wrote: >> >>> On 11/5/13 8:32 AM, David Piepgrass wrote: >>> >>>> Segmented stacks aren't the only solution though. >>>> >>>> If the concern is many tasks that block for a long time, I imagine a >>>> mechanism to bundle a bunch of small, dormant stacks into a single page >>>> so that the original pages could be released to the OS. >>>> >>>> >>>> >>>> *If stacks were additionally relocatable (which requires similar >>>> machinery as precise moving GC, if I'm not mistaken) * >>> >>> >>> This is correct. It's conceivable (although I can't make any promises) >>> that if and when LLVM supports this, we could experiment with doing what Go >>> does. >>> >>> Patrick >>> _______________________________________________ >>> 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 >> >> > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From me at kevincantu.org Wed Nov 13 09:09:06 2013 From: me at kevincantu.org (Kevin Cantu) Date: Wed, 13 Nov 2013 09:09:06 -0800 Subject: [rust-dev] Greenlets in Rust (was: Abandoning segmented stacks in Rust) In-Reply-To: References: Message-ID: I thought tasks were a type of greenlet, or vice versa. What's your proposal, exactly? Kevin On Nov 13, 2013 9:06 AM, "Vadim" wrote: > They don't share state. The language-level semantics of greenlets is the > same as that of tasks, except that they are scheduled cooperatively. All > these games with the stack should be unobservable on Rust level. > > > On Wed, Nov 13, 2013 at 1:01 AM, Eric Reed wrote: > >> The big issue I see right away (assuming I read this correctly and >> greenlets can still access the stack that existed when they were created), >> is that now mutable state on the stack is *shared* between greenlets and >> therefore can experience *data races* (impossible for tasks b/c they >> don't share memory), so they sound wildly unsafe to me. >> >> There may be some other issues that arise from the shared stack prefix >> property: >> - If a greenlet moves something on the stack, then other greenlets now >> have access to invalidated memory >> - You can no longer assume that you have sole access things pointed to by >> unique pointers, which would probably invalidate a lot of existing >> assumptions. >> >> Eric >> >> >> On Wed, Nov 13, 2013 at 12:02 AM, Vadim wrote: >> >>> Hi, >>> I would like to float a proposal (or three :-), regarding "greenlets" in >>> Rust. For those unfamiliar with greenlets, they are a tool for writing >>> concurrent code, similar to Rust's tasks, but much more light-weight in >>> terms of memory consumption (especially now that segmented stacks are no >>> more). >>> >>> I think there are some scenarios where low memory consumption per-task >>> is still important, 64-bit address spaces notwithstanding. A typical one >>> would be a pub-sub server, which needs to maintain a massive number of >>> simple I/O workflows, where I/O channels are idle most of the time. >>> >>> So here we go (in the order of increasing craziness): >>> >>> 1. Recently I've learned how Python greenletsare >>> implemented . I believe that the >>> same approach could work in Rust: >>> >>> Basically, greenlets are spawned using the same stack as the parent >>> greenlet, just like a normal function call. When a greenlet is suspended, >>> it copies the portion of the stack used up since its' spawning to the >>> heap. When one is re-activated, the saved memory is copied back where it >>> came from (having first saved stack of the previous active greenlet,- if >>> they overlap). >>> >>> Since greenlets don't need to save "red zone" of the stack, the amount >>> of data per instance is precisely what is actually used. >>> >>> There are also downsides, of course: >>> - greenlets are bound to the thread that spawned them, >>> - two memcpy's are needed when switching between them. >>> >>> In the case of Python, though, there's one further optimization: since >>> Python's stack frames live on the heap, in most cases, there nothing on the >>> hardware stack that a greenlet needs saving! As a bonus, it can now be >>> resumed at any stack position, so no saving of previous greenlet's stack is >>> needed. The only time when a full save occurs is when there are foreign >>> stack frames on the stack. >>> >>> >>> 2. Well, can Rust do the same? What if we came up with an attribute, >>> say, [#stackless], which causes a function to allocate it's stack frame on >>> the heap and put all local vars there? The only things on the actual >>> hardware stack would then be the function's arguments, the return address, >>> the saved base pointer and the pointer to that heap-alllocated frame. >>> With the exception of base pointers, all these things are >>> position-independent, I believe. And base pointer chain can be easily >>> fixed up if/when stack is moved. >>> >>> So if we had that, and the whole greenlet's stack consisted of such >>> functions, and there was a way for the "switch_to_greenlet()" function to >>> detect that, then such greenlet's stack would be relocatable and could be >>> resumed at any position in the thread's stack (or even in another thread!) >>> with minimal memory copying, just like in Python. >>> >>> Of course, the [#stackless] functions would be slower than the normal >>> ones, but in the scenario I've outlined in the beginning, it shouldn't be a >>> problem. >>> >>> >>> 3. Unfortunately, in order for the above scheme to work, all I/O >>> methods, (which are typically where yields happen), would need to be marked >>> as [#stackless]... This would affect the performance of "normal" code >>> using the same API, which is undesirable. >>> >>> Okay, but usually there are not *that *many things that point into the >>> stack in a typical program. I can think of only three things: references >>> to stack-allocated buffers, base pointer chains and references to >>> caller-allocated return values. >>> - The first one can be lived without - just allocate buffers on the heap. >>> - The second one - see above. >>> - The last one is more tricky, but for the sake of argument, let's >>> assume that we restricted function signatures such that only >>> register-allocated types can be returned. >>> >>> Let's say we came up with a way to mark up functions that may yield to >>> another greenlet, and also with a way to prohibit taking address of >>> stack-allocated variables for the duration of calls to yielding functions. >>> These restrictions would be annoying, but not overly so, as long as you >>> had to obey them only in functions that are intended to be run in a >>> greenlet. >>> On the plus side, the hardware stack contents would now be relocatable. >>> >>> In this setup, everything could proceed as usual, using the hardware >>> stack, until execution came to a blocking I/O call. At that point, the >>> scheduler would check if running inside a greenlet, copy greenlet's stack >>> to the heap and switch off to another greenlet. Otherwise, it would do the >>> same thing it does now, i.e. switch tasks. >>> >>> >>> So, what do you say, rustafarians? Does any of that make any sense? >>> >>> Vadim >>> >>> >>> On Tue, Nov 5, 2013 at 9:18 AM, Patrick Walton wrote: >>> >>>> On 11/5/13 8:32 AM, David Piepgrass wrote: >>>> >>>>> Segmented stacks aren't the only solution though. >>>>> >>>>> If the concern is many tasks that block for a long time, I imagine a >>>>> mechanism to bundle a bunch of small, dormant stacks into a single page >>>>> so that the original pages could be released to the OS. >>>>> >>>>> >>>>> >>>>> *If stacks were additionally relocatable (which requires similar >>>>> machinery as precise moving GC, if I'm not mistaken) * >>>> >>>> >>>> This is correct. It's conceivable (although I can't make any promises) >>>> that if and when LLVM supports this, we could experiment with doing what Go >>>> does. >>>> >>>> Patrick >>>> _______________________________________________ >>>> 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 >>> >>> >> >> _______________________________________________ >> 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: From nicolas at boulay.name Wed Nov 13 08:35:36 2013 From: nicolas at boulay.name (Nicolas Boulay) Date: Wed, 13 Nov 2013 17:35:36 +0100 Subject: [rust-dev] about Rust and static memory allocation Message-ID: Hello, I?m an hardware scientist, working for a software compagny. I had follow some open cpu design like F-cpu, and the langage design of Lisaac. I?m an expert in C programming, and have some skills in ocaml, perl, c++, java. In synchrone langage (Lustre/Scade), there is no dynamic memory allocation. This kind of langage have the data inside function (or ?block?), the opposite way of object langage with method beside the data. It?s like having ?static? variable in the C sens, but a different one for each call site. There is no loops in Lustre, only high order function like map and fold operation, that duplicate the variable for each call. Having such feature, reduce the need a dynamic allocation and garbage collector. I think this looks new and strange, but Lustre are used since 10 years in real time safety critical software. This kind of (static, compile time) memory allocation could be a great help for long running, fast and responsive system. I know you target a 1.0 release but this could ease the write of software without any dynamic memory allocation. Do you think, this could be implemented in rust ? Regards, Nicolas Boulay -------------- next part -------------- An HTML attachment was scrubbed... URL: From ecreed at cs.washington.edu Wed Nov 13 10:08:05 2013 From: ecreed at cs.washington.edu (Eric Reed) Date: Wed, 13 Nov 2013 10:08:05 -0800 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> <52830794.3070504@mozilla.com> <129CF8DC-08FB-43B8-8A8B-985C254A5AEA@sb.org> <9859FE7A-3F11-4317-9491-6EEB4F4157AF@sb.org> Message-ID: I'm not sure I follow. My implementation doesn't use any trait pointers, so the only time there were would be a trait pointer is if you casted to ~Trait yourself. In that case, only the original method call would be dynamic dispatch; all the internal calls (delegating and upcasting) are still static dispatch. So my version doesn't pay for any dynamic dispatch over what the programmer is already paying for. On Wed, Nov 13, 2013 at 3:46 AM, Oren Ben-Kiki wrote: > The call isn't statically dispatched when I invoke a method via a trait > pointer. So it seems when I invoke any trait function, I pay double the > cost of a virtual function call instead of one... I suppose it isn't _too_ > bad, but it still hurts. > > > > On Wed, Nov 13, 2013 at 12:21 PM, Eric Reed wrote: > >> I'm not clear on why LLVM wouldn't be able to inline super() calls. It's >> static dispatch, so it knows exactly what function is being called. >> >> >> On Wed, Nov 13, 2013 at 1:25 AM, Oren Ben-Kiki wrote: >> >>> This is probably as good as we can get in the current system (I do >>> something similar in my code today). >>> >>> I also think you probably need both "super" and "mut_super", so it would >>> be two methods to implement instead of one (still pretty good). I wonder >>> whether it is possible to write a macro that automates writing these >>> boilerplate methods? >>> >>> The key weakness is that (I think) the compiler can't inline the >>> accesses to "super" so that you end up with a chain of virtual function >>> calls every time it is accessed, so performance would be pretty bad. >>> >>> >>> On Wed, Nov 13, 2013 at 10:27 AM, Eric Reed wrote: >>> >>>> Here's how I would do it using just existing Rust (assuming this hasn't >>>> all changed under me in the past couple months). >>>> NB: I haven't actually tried compiling this, but I'm pretty sure it (or >>>> something like it) would work. >>>> >>>> Nice properties over this solution: >>>> - Doesn't require language extensions (although syntax sugar wouldn't >>>> be unwelcome) >>>> - Doesn't require trait objects (i.e. static dispatch is possible) >>>> - Only need to implement one method for each derived type (super) in >>>> addition to overridden methods >>>> - Supports multiple inheritance in two ways (and avoids the diamond >>>> problem I think -- not a C++ expert so I may have misunderstood that) >>>> + no default parent and programmer must select which parent to >>>> use before calling >>>> + implementer-chosen default parent and programmer can chose to >>>> use a different parent if desired >>>> >>>> Neutral?: >>>> - Doesn't enforce or care about the prefix property. Not sure if that >>>> still matters so much w/o dynamic dispatch. >>>> >>>> Downsides: >>>> - Performance of delegation depends on LLVM's ability to inline (I >>>> think). >>>> - Does require repeating all the methods once (for delegating default >>>> implementations) >>>> >>>> // The base type >>>> struct Base { >>>> data : int; >>>> } >>>> >>>> // Characterize it's extensible behavior in a trait >>>> trait Trait { >>>> fn method(&self); >>>> } >>>> >>>> // Implement the base behavior >>>> impl Trait for Base { >>>> fn method(&self) { ... } >>>> } >>>> >>>> // Extension of trait that supports upcasting to existing >>>> implementations >>>> trait DerivingTrait

: Trait { >>>> // one extra method for accessing a parent's implementation. >>>> ideally this would be inlined by the compiler >>>> fn super(&self) -> P; >>>> // default implementations for all the methods in Trait let us >>>> avoid writing delegation everywhere manually >>>> fn method(&self) { >>>> self.super().method() // just delegate to parent >>>> } >>>> } >>>> >>>> // Single inheritance >>>> struct Single { >>>> parent: Base, >>>> moreData: int, >>>> } >>>> >>>> impl DerivingTrait for Single { >>>> fn super(&self) -> Base { self.parent } >>>> } >>>> >>>> // Overriding behavior >>>> struct Override { >>>> parent: Base, >>>> otherData: u8, >>>> } >>>> >>>> impl DerivingTrait for Override { >>>> fn super(&self) -> Base { self.parent } >>>> fn method(&self) { ... } >>>> } >>>> >>>> // Multiple inheritance >>>> struct Multiple { >>>> single: Single, >>>> override: Override, >>>> evenMoreData: ~str, >>>> } >>>> >>>> // must specify which parent's implementation we want (could hide >>>> wrapping inside of as_* methods impl'd on Multiple if you like) >>>> // if we want one of them as the default, then we can impl >>>> DerivingTrait on Multiple directly >>>> struct MultipleAsSingle(Multiple); >>>> struct MultipleAsOverride(Multiple); >>>> >>>> impl DerivingTrait for MultipleAsSingle { >>>> fn super(&self) -> Single { self.single } >>>> } >>>> >>>> impl DerivingTrait for MultipleAsOverride { >>>> fn super(&self) -> Override { self.override } >>>> } >>>> >>>> fn main() { >>>> let base = Base { ... }; >>>> let single = Single { ... }; >>>> let override = Override { ... }; >>>> let multiple = Multiple { ... }; >>>> >>>> base.method(); >>>> base.super(); // compile time error >>>> >>>> single.method(); // =inline delegation=> single.super().method() >>>> =inline upcast=> single.base.method() >>>> override.method(); // done! no delegating >>>> MultipleAsSingle(multiple).method(); // =delegate=> >>>> MAS(multiple).super().method() =upcast=> multiple.single.method() >>>> =delegate=> multiple.single.super().method() =upcast=> >>>> multiple.single.base.method() >>>> MutlipleAsOverride(multiple).method(); // =delegate=> >>>> MAO(multiple).super().method() =upcast=> multiple.override.method() >>>> } >>>> >>>> Thoughts? >>>> >>>> Eric >>>> >>>> >>>> On Tue, Nov 12, 2013 at 10:30 PM, Kevin Ballard wrote: >>>> >>>>> On Nov 12, 2013, at 10:26 PM, Kevin Ballard wrote: >>>>> >>>>> > And even that restriction could be lifted if ~Trait objects could be >>>>> represented using an array of pointers (one to each inherited struct), e.g. >>>>> ([*A,*B,*C],*vtable) instead of just (*A,*vtable), though I suspect this is >>>>> not worth doing. >>>>> >>>>> Upon further reflection, this would need to be done anyway because of >>>>> the ability to combine traits. If I have >>>>> >>>>> trait TraitA : A {} >>>>> trait TraitB : B {} >>>>> >>>>> and I want to use ~TraitA+TraitB then I would need a "fat" trait. >>>>> Although in this case the number of value pointers is equal to the number >>>>> of combined traits, so it's a bit more sensible to allow for "fat" trait >>>>> pointers here. >>>>> >>>>> -Kevin >>>>> _______________________________________________ >>>>> 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: From bjzaba at yahoo.com.au Wed Nov 13 10:13:25 2013 From: bjzaba at yahoo.com.au (Brendan Zabarauskas) Date: Thu, 14 Nov 2013 05:13:25 +1100 Subject: [rust-dev] typing in rust In-Reply-To: References: Message-ID: SML also shares these semantics when it comes to bindings. That is, a subsequent binding to the same identifier can ?mask? those that proceed it, even if they are in the same scope and the bound values are of different types. Once a value has had its identifier masked, it can no longer be accessed. I assume this behaviour was passed on to Ocaml, and Rust inherited it from there. Rust was originally written in Ocaml, and has drawn many influences from there. I personally find it useful from time to time. ~Brendan On 14 Nov 2013, at 3:25 am, Joshua Rodgers wrote: > I'm curious as to why this is valid, though? This makes sense if you're inside a new or nested scope, but why is it valid inside the same scope as illustrated in the code example? > > I can understand it from the perspective that I need to mask a function name (but that's a nested scope to me, at that point). > > > On Wed, Nov 13, 2013 at 8:54 AM, Scott Lawrence wrote: > I would think that `test()` (the function) is in scope for the duration of `let test =`, and then the new definition masks the old one. Similarly, > > let x = 2; > let x = x + 2; > > If you change the last line to /call/ test(), you should get an error. > > > On Wed, 13 Nov 2013, Philip Herron wrote: > > Hey all > > I am still learning but i just tried something which i expected to give an > error but works: > > fn test () -> int { > 1 > } > > fn main () { > let test = test (); > println (format! ("{}", test)); > } > > I guess on compilation the names are mangled against their types or > something so you can differentiate between test the function and test the > variable. Not sure would be nice to get some clarification what this > behavior is. > > Thanks > > --Phil > > > -- > Scott Lawrence > _______________________________________________ > 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 From danielmicay at gmail.com Wed Nov 13 10:20:10 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 13:20:10 -0500 Subject: [rust-dev] Greenlets in Rust (was: Abandoning segmented stacks in Rust) In-Reply-To: References: Message-ID: On Wed, Nov 13, 2013 at 3:02 AM, Vadim wrote: > Hi, > I would like to float a proposal (or three :-), regarding "greenlets" in > Rust. For those unfamiliar with greenlets, they are a tool for writing > concurrent code, similar to Rust's tasks, but much more light-weight in > terms of memory consumption (especially now that segmented stacks are no > more). > > I think there are some scenarios where low memory consumption per-task is > still important, 64-bit address spaces notwithstanding. A typical one > would be a pub-sub server, which needs to maintain a massive number of > simple I/O workflows, where I/O channels are idle most of the time. > > So here we go (in the order of increasing craziness): > > 1. Recently I've learned how Python greenlets are implemented. I believe > that the same approach could work in Rust: > > Basically, greenlets are spawned using the same stack as the parent > greenlet, just like a normal function call. When a greenlet is suspended, > it copies the portion of the stack used up since its' spawning to the heap. > When one is re-activated, the saved memory is copied back where it came from > (having first saved stack of the previous active greenlet,- if they > overlap). > > Since greenlets don't need to save "red zone" of the stack, the amount of > data per instance is precisely what is actually used. > > There are also downsides, of course: > - greenlets are bound to the thread that spawned them, > - two memcpy's are needed when switching between them. > > In the case of Python, though, there's one further optimization: since > Python's stack frames live on the heap, in most cases, there nothing on the > hardware stack that a greenlet needs saving! As a bonus, it can now be > resumed at any stack position, so no saving of previous greenlet's stack is > needed. The only time when a full save occurs is when there are foreign > stack frames on the stack. > > > 2. Well, can Rust do the same? What if we came up with an attribute, say, > [#stackless], which causes a function to allocate it's stack frame on the > heap and put all local vars there? The only things on the actual hardware > stack would then be the function's arguments, the return address, the saved > base pointer and the pointer to that heap-alllocated frame. With the > exception of base pointers, all these things are position-independent, I > believe. And base pointer chain can be easily fixed up if/when stack is > moved. > > So if we had that, and the whole greenlet's stack consisted of such > functions, and there was a way for the "switch_to_greenlet()" function to > detect that, then such greenlet's stack would be relocatable and could be > resumed at any position in the thread's stack (or even in another thread!) > with minimal memory copying, just like in Python. > > Of course, the [#stackless] functions would be slower than the normal ones, > but in the scenario I've outlined in the beginning, it shouldn't be a > problem. > > > 3. Unfortunately, in order for the above scheme to work, all I/O methods, > (which are typically where yields happen), would need to be marked as > [#stackless]... This would affect the performance of "normal" code using > the same API, which is undesirable. > > Okay, but usually there are not that many things that point into the stack > in a typical program. I can think of only three things: references to > stack-allocated buffers, base pointer chains and references to > caller-allocated return values. > - The first one can be lived without - just allocate buffers on the heap. > - The second one - see above. > - The last one is more tricky, but for the sake of argument, let's assume > that we restricted function signatures such that only register-allocated > types can be returned. > > Let's say we came up with a way to mark up functions that may yield to > another greenlet, and also with a way to prohibit taking address of > stack-allocated variables for the duration of calls to yielding functions. > These restrictions would be annoying, but not overly so, as long as you had > to obey them only in functions that are intended to be run in a greenlet. > On the plus side, the hardware stack contents would now be relocatable. > > In this setup, everything could proceed as usual, using the hardware stack, > until execution came to a blocking I/O call. At that point, the scheduler > would check if running inside a greenlet, copy greenlet's stack to the heap > and switch off to another greenlet. Otherwise, it would do the same thing > it does now, i.e. switch tasks. > > > So, what do you say, rustafarians? Does any of that make any sense? > > Vadim Rust has no way to move a stack/value and update the pointers to it. A fundamental property of borrowed pointers is that they're just integers in memory at runtime without any boxing or type information. From oren at ben-kiki.org Wed Nov 13 10:28:17 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Wed, 13 Nov 2013 20:28:17 +0200 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> <52830794.3070504@mozilla.com> <129CF8DC-08FB-43B8-8A8B-985C254A5AEA@sb.org> <9859FE7A-3F11-4317-9491-6EEB4F4157AF@sb.org> Message-ID: Hmmm. Perhaps I was too hasty. It would be interesting to look at the generated binary code and see if it actually work this way... On Wed, Nov 13, 2013 at 8:08 PM, Eric Reed wrote: > I'm not sure I follow. > My implementation doesn't use any trait pointers, so the only time there > were would be a trait pointer is if you casted to ~Trait yourself. > In that case, only the original method call would be dynamic dispatch; all > the internal calls (delegating and upcasting) are still static dispatch. > So my version doesn't pay for any dynamic dispatch over what the > programmer is already paying for. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From alex at crichton.co Wed Nov 13 10:32:11 2013 From: alex at crichton.co (Alex Crichton) Date: Wed, 13 Nov 2013 10:32:11 -0800 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: The situation may not be as dire as you think. The runtime is still in a state of flux, and don't forget that in one summer the entire runtime was rewritten in rust and was entirely redesigned. I personally still think that M:N is a viable model for various applications, and it seems especially unfortunate to just remove everything because it's not tailored for all use cases. Rust made an explicit design decision early on to pursue lightweight/green tasks, and it was made with the understanding that there were drawbacks to the strategy. Using libuv as a backend for driving I/O was also an explicit decision with known drawbacks. That being said, I do not believe that all is lost. I don't believe that the rust standard library as-is today can support *every* use case, but it's getting to a point where it can get pretty close. In the recent redesign of the I/O implementation, all I/O was abstracted behind trait objects that are synchronous in their interface. This I/O interface is all implemented in librustuv by talking to the rust scheduler under the hood. Additionally, in pull #10457, I'm starting to add support for a native implementation of this I/O interface. The great boon of this strategy is that all std::io primitives have no idea if their underlying interface is native and blocking or libuv and asynchronous. The exact same rust code works for one as it does for the other. I personally don't see why the same strategy shouldn't work for the task model as well. When you link a program to the librustuv crate, then you're choosing to have a runtime with M:N scheduling and asynchronous I/O. Perhaps, though, if you didn't link to librustuv, you would get 1:1 scheduling with blocking I/O. You would still have all the benefits of the standard library's communication primitives, spawning primitives, I/O, task-local-storage etc. The only difference is that everything would be powered by OS-level threads instead of rust-level green tasks. I would very much like to see a standard library which supports this abstraction, and I believe that it is very realistically possible. Right now we have an EventLoop interface which defines interacting with I/O that is the abstraction between asynchronous I/O and blocking I/O. This sounds like we need a more formalized Scheduler interface which abstracts M:N scheduling vs 1:1 scheduling. The main goal of all of this would be to allow the same exact rust code to work in both M:N and 1:1 environments. This ability would allow authors to specialize their code for their task at-hand. Those writing web servers would be sure to link to librustuv, but those writing command-line utilities would simply just omit librustuv. Additionally, as a library author, I don't really care which implementation you're using. I can write a mysql database driver and then you as a consumer of my library decided whether my network calls are blocking or not. This is a fairly new concept to me (I haven't thought much about it before), but this sounds like it may be the right way forward to addressing your concerns without compromising too much existing functionality. There would certainly be plenty of work to do in this realm, and I'm not sure if this goal would block the 1.0 milestone or not. Ideally, this would be a completely backwards-compatible change, but there would perhaps be unintended consequences. As always, this would need plenty of discussion to see whether this is even a reasonable strategy to take. On Wed, Nov 13, 2013 at 2:45 AM, Daniel Micay wrote: > Before getting right into the gritty details about why I think we should think > about a path away from M:N scheduling, I'll go over the details of the > concurrency model we currently use. > > Rust uses a user-mode scheduler to cooperatively schedule many tasks onto OS > threads. Due to the lack of preemption, tasks need to manually yield control > back to the scheduler. Performing I/O with the standard library will block the > *task*, but yield control back to the scheduler until the I/O is completed. > > The scheduler manages a thread pool where the unit of work is a task rather > than a queue of closures to be executed or data to be pass to a function. A > task consists of a stack, register context and task-local storage much like an > OS thread. > > In the world of high-performance computing, this is a proven model for > maximizing throughput for CPU-bound tasks. By abandoning preemption, there's > zero overhead from context switches. For socket servers with only negligible > server-side computations the avoidance of context switching is a boon for > scalability and predictable performance. > > # Lightweight? > > Rust's tasks are often called *lightweight* but at least on Linux the only > optimization is the lack of preemption. Since segmented stacks have been > dropped, the resident/virtual memory usage will be identical. > > # Spawning performance > > An OS thread can actually spawn nearly as fast as a Rust task on a system with > one CPU. On a multi-core system, there's a high chance of the new thread being > spawned on a different CPU resulting in a performance loss. > > Sample C program, if you need to see it to believe it: > > ``` > #include > #include > > static const size_t n_thread = 100000; > > static void *foo(void *arg) { > return arg; > } > > int main(void) { > for (size_t i = 0; i < n_thread; i++) { > pthread_attr_t attr; > if (pthread_attr_init(&attr) < 0) { > return 1; > } > if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) < 0) { > return 1; > } > pthread_t thread; > if (pthread_create(&thread, &attr, foo, NULL) < 0) { > return 1; > } > } > pthread_exit(NULL); > } > ``` > > Sample Rust program: > > ``` > fn main() { > for _ in range(0, 100000) { > do spawn { > } > } > } > ``` > > For both programs, I get around 0.9s consistently when pinned to a core. The > Rust version drops to 1.1s when not pinned and the OS thread one to about 2s. > It drops further when asked to allocate 8MiB stacks like C is doing, and will > drop more when it has to do `mmap` and `mprotect` calls like the pthread API. > > # Asynchronous I/O > > Rust's requirements for asynchronous I/O would be filled well by direct usage > of IOCP on Windows. However, Linux only has solid support for non-blocking > sockets because file operations usually just retrieve a result from cache and > do not truly have to block. This results in libuv being significantly slower > than blocking I/O for most common cases for the sake of scalable socket > servers. > > On modern systems with flash memory, including mobile, there is a *consistent* > and relatively small worst-case latency for accessing data on the disk so > blocking is essentially a non-issue. Memory mapped I/O is also an incredibly > important feature for I/O performance, and there's almost no reason to use > traditional I/O on 64-bit. However, it's a no-go with M:N scheduling because > the page faults block the thread. > > # Overview > > Advantages: > > * lack of preemptive/fair scheduling, leading to higher throughput > * very fast context switches to other tasks on the same scheduler thread > > Disadvantages: > > * lack of preemptive/fair scheduling (lower-level model) > * poor profiler/debugger support > * async I/O stack is much slower for the common case; for example stat is 35x > slower when run in a loop for an mlocate-like utility > * true blocking code will still block a scheduler thread > * most existing libraries use blocking I/O and OS threads > * cannot directly use fast and easy to use linker-supported thread-local data > * many existing libraries rely on thread-local storage, so there's a need to be > wary of hidden yields in Rust function calls and it's very difficult to > expose a safe interface to these libraries > * every level of a CPU architecture adding registers needs explicit support > from Rust, and it must be selected at runtime when not targeting a specific > CPU (this is currently not done correctly) > > # User-mode scheduling > > Windows 7 introduced user-mode scheduling[1] to replace fibers on 64-bit. > Google implemented the same thing for Linux (perhaps even before Windows 7 was > released), and plans on pushing for it upstream.[2] The linked video does a > better job of covering this than I can. > > User-mode scheduling provides a 1:1 threading model including full support for > normal thread-local data and existing debuggers/profilers. It can yield to the > scheduler on system calls and page faults. The operating system is responsible > for details like context switching, so a large maintenance/portability burden > is dealt with. It narrows down the above disadvantage list to just the point > about not having preemptive/fair scheduling and doesn't introduce any new ones. > > I hope this is where concurrency is headed, and I hope Rust doesn't miss this > boat by concentrating too much on libuv. I think it would allow us to simply > drop support for pseudo-blocking I/O in the Go style and ignore asynchronous > I/O and non-blocking sockets in the standard library. It may be useful to have > the scheduler use them, but it wouldn't be essential. > > [1] http://msdn.microsoft.com/en-us/library/windows/desktop/dd627187(v=vs.85).aspx > [2] http://www.youtube.com/watch?v=KXuZi9aeGTw > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From ecreed at cs.washington.edu Wed Nov 13 10:35:45 2013 From: ecreed at cs.washington.edu (Eric Reed) Date: Wed, 13 Nov 2013 10:35:45 -0800 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> <52830794.3070504@mozilla.com> <129CF8DC-08FB-43B8-8A8B-985C254A5AEA@sb.org> <9859FE7A-3F11-4317-9491-6EEB4F4157AF@sb.org> Message-ID: Indeed. I haven't looked at what it would generate at all. I'm just working off my understanding of the semantics. What LLVM actually does is an entirely different question. On Wed, Nov 13, 2013 at 10:28 AM, Oren Ben-Kiki wrote: > Hmmm. Perhaps I was too hasty. It would be interesting to look at the > generated binary code and see if it actually work this way... > > On Wed, Nov 13, 2013 at 8:08 PM, Eric Reed wrote: > >> I'm not sure I follow. >> My implementation doesn't use any trait pointers, so the only time there >> were would be a trait pointer is if you casted to ~Trait yourself. >> In that case, only the original method call would be dynamic dispatch; >> all the internal calls (delegating and upcasting) are still static dispatch. >> So my version doesn't pay for any dynamic dispatch over what the >> programmer is already paying for. >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From erick.tryzelaar at gmail.com Wed Nov 13 10:44:57 2013 From: erick.tryzelaar at gmail.com (Erick Tryzelaar) Date: Wed, 13 Nov 2013 10:44:57 -0800 Subject: [rust-dev] Greenlets in Rust (was: Abandoning segmented stacks in Rust) In-Reply-To: References: Message-ID: This approach is not all that different different from my plan to implement generators: https://github.com/mozilla/rust/issues/7746 My current thinking is that a generator is really the combination between storing the local variables in a structure instead of on the stack, and a state machine to jump between each of the generator steps. Without thinking too deeply into it, I suspect that the main difference between a generator and a coroutine/greenlet is whether or not that structure is stored on the stack or on the heap. I'm not quite sure how we'll handle passing data into a coroutine, maybe we can reserve a slot in the environment structure for passed in values, and the compiler can guarantee no one accesses that value until it's been set. Unfortunately this'll requires a bunch of scary compiler magic to get it all to work. But I don't think it's impossible. On Wed, Nov 13, 2013 at 10:20 AM, Daniel Micay wrote: > On Wed, Nov 13, 2013 at 3:02 AM, Vadim wrote: > > Hi, > > I would like to float a proposal (or three :-), regarding "greenlets" in > > Rust. For those unfamiliar with greenlets, they are a tool for writing > > concurrent code, similar to Rust's tasks, but much more light-weight in > > terms of memory consumption (especially now that segmented stacks are no > > more). > > > > I think there are some scenarios where low memory consumption per-task is > > still important, 64-bit address spaces notwithstanding. A typical one > > would be a pub-sub server, which needs to maintain a massive number of > > simple I/O workflows, where I/O channels are idle most of the time. > > > > So here we go (in the order of increasing craziness): > > > > 1. Recently I've learned how Python greenlets are implemented. I believe > > that the same approach could work in Rust: > > > > Basically, greenlets are spawned using the same stack as the parent > > greenlet, just like a normal function call. When a greenlet is > suspended, > > it copies the portion of the stack used up since its' spawning to the > heap. > > When one is re-activated, the saved memory is copied back where it came > from > > (having first saved stack of the previous active greenlet,- if they > > overlap). > > > > Since greenlets don't need to save "red zone" of the stack, the amount of > > data per instance is precisely what is actually used. > > > > There are also downsides, of course: > > - greenlets are bound to the thread that spawned them, > > - two memcpy's are needed when switching between them. > > > > In the case of Python, though, there's one further optimization: since > > Python's stack frames live on the heap, in most cases, there nothing on > the > > hardware stack that a greenlet needs saving! As a bonus, it can now be > > resumed at any stack position, so no saving of previous greenlet's stack > is > > needed. The only time when a full save occurs is when there are foreign > > stack frames on the stack. > > > > > > 2. Well, can Rust do the same? What if we came up with an attribute, > say, > > [#stackless], which causes a function to allocate it's stack frame on the > > heap and put all local vars there? The only things on the actual > hardware > > stack would then be the function's arguments, the return address, the > saved > > base pointer and the pointer to that heap-alllocated frame. With the > > exception of base pointers, all these things are position-independent, I > > believe. And base pointer chain can be easily fixed up if/when stack is > > moved. > > > > So if we had that, and the whole greenlet's stack consisted of such > > functions, and there was a way for the "switch_to_greenlet()" function to > > detect that, then such greenlet's stack would be relocatable and could be > > resumed at any position in the thread's stack (or even in another > thread!) > > with minimal memory copying, just like in Python. > > > > Of course, the [#stackless] functions would be slower than the normal > ones, > > but in the scenario I've outlined in the beginning, it shouldn't be a > > problem. > > > > > > 3. Unfortunately, in order for the above scheme to work, all I/O > methods, > > (which are typically where yields happen), would need to be marked as > > [#stackless]... This would affect the performance of "normal" code using > > the same API, which is undesirable. > > > > Okay, but usually there are not that many things that point into the > stack > > in a typical program. I can think of only three things: references to > > stack-allocated buffers, base pointer chains and references to > > caller-allocated return values. > > - The first one can be lived without - just allocate buffers on the heap. > > - The second one - see above. > > - The last one is more tricky, but for the sake of argument, let's assume > > that we restricted function signatures such that only register-allocated > > types can be returned. > > > > Let's say we came up with a way to mark up functions that may yield to > > another greenlet, and also with a way to prohibit taking address of > > stack-allocated variables for the duration of calls to yielding > functions. > > These restrictions would be annoying, but not overly so, as long as you > had > > to obey them only in functions that are intended to be run in a greenlet. > > On the plus side, the hardware stack contents would now be relocatable. > > > > In this setup, everything could proceed as usual, using the hardware > stack, > > until execution came to a blocking I/O call. At that point, the > scheduler > > would check if running inside a greenlet, copy greenlet's stack to the > heap > > and switch off to another greenlet. Otherwise, it would do the same > thing > > it does now, i.e. switch tasks. > > > > > > So, what do you say, rustafarians? Does any of that make any sense? > > > > Vadim > > Rust has no way to move a stack/value and update the pointers to it. A > fundamental property of borrowed pointers is that they're just > integers in memory at runtime without any boxing or type information. > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From spam at scientician.net Wed Nov 13 10:48:05 2013 From: spam at scientician.net (Bardur Arantsson) Date: Wed, 13 Nov 2013 19:48:05 +0100 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: On 2013-11-13 11:45, Daniel Micay wrote: > Before getting right into the gritty details about why I think we should think [--snip--] Very interesting video about the kernel (in future) perhaps interacting more closesly with user-space about scheduling decisions and threads, thus reducing overhead and perhaps eliminating the *need* for M:N. Having said that, M:N seems to work for Haskell where they recently showed near-perfect scalability to 42 cores for a web server (beating out nginx and apache handily, even on absolute numbers). For the life of me I can't find the PDF/paper reference right now, but I'll try to follow up with a proper reference. Perhaps there's some magical properties of Haskell with make that less problematic than for Rust, but... Anyway, of course we all *hope* that tricks like M:N won't be necessary in the future, but how soon can we hope that the future arrives? ;) Regards, From bill_myers at outlook.com Wed Nov 13 10:49:28 2013 From: bill_myers at outlook.com (Bill Myers) Date: Wed, 13 Nov 2013 18:49:28 +0000 Subject: [rust-dev] C# async for Rust Message-ID: I see several proposals for the future of Rust tasks, and I think one of the best approaches is being overlooked, and that is something similar to async in C# (http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx). In C#, the "async" keyword can be applied to functions and it causes the compiler to transform a function that returns T into a function that returns a Task (which is C#'s name for a future of type T) representing the potentially asynchronous computation. Blocking is representing by using the "await" keyword on a future (typically returned by a call to another "async" function), and it causes the compiler to perform a Continuation-Passing Style transformation, and attach the continuation to the future, returning another future representing the composed computation. I/O functions are designed to return futures, so in this system blocking causes all calling "async" functions to return, building up a chain of continuations on the heap, which is equivalent to the machine stack in a current-Rust task, but which is as small as needed, and is only used for call chains that block. In Rust, this transformation is much more delicate, because the resulting return value futures must have a lifetime that is the smallest among all the arguments to the function, if those arguments are needed by the continuation, and the argument types must be "shareable" between parallel forks (e.g. std::rc::Rc is not shareable because RC manipulation is non-atomic). However, it is possible to restrict the system to use non-delimited continuations instead of the delimited continuations and futures, which would avoid this problem, since futures cannot be used explicitly anymore (at the cost of making flexible parallelism impossible). In this latter case, it would be equivalent to the current task system, except for requiring blocking functions to be marked "async"; the "await" keyword would not be required, since it would effectively become compulsory if there are no first-class futures returned for async functions. Advantages: - Functions and interfaces that can perform I/O or can block are clearly marked by a keyword - Can have billions of blocked tasks (with hundreds of gigabytes of RAM) since the memory used by each blocked task is truly minimized because it's on the heap Disadvantages: - Requires an heap allocation for every function call to an async function (to hold the continuation data) - Non-"async" functions cannot call "async" functions, so interfaces must be explicitly marked as async or not - Requires to implement the transform in the compiler Microsoft switched to this paradigm in the latest version of C# and in the Windows RT API, and it might be an appropriate choice for Rust too. -------------- next part -------------- An HTML attachment was scrubbed... URL: From vadimcn at gmail.com Wed Nov 13 10:50:52 2013 From: vadimcn at gmail.com (Vadim) Date: Wed, 13 Nov 2013 10:50:52 -0800 Subject: [rust-dev] Greenlets in Rust (was: Abandoning segmented stacks in Rust) In-Reply-To: References: Message-ID: I do realize that. What I am proposing does not require updating pointers to the moved stack, because there would be none (I believe). On Wed, Nov 13, 2013 at 10:20 AM, Daniel Micay wrote: > On Wed, Nov 13, 2013 at 3:02 AM, Vadim wrote: > > Hi, > > I would like to float a proposal (or three :-), regarding "greenlets" in > > Rust. For those unfamiliar with greenlets, they are a tool for writing > > concurrent code, similar to Rust's tasks, but much more light-weight in > > terms of memory consumption (especially now that segmented stacks are no > > more). > > > > I think there are some scenarios where low memory consumption per-task is > > still important, 64-bit address spaces notwithstanding. A typical one > > would be a pub-sub server, which needs to maintain a massive number of > > simple I/O workflows, where I/O channels are idle most of the time. > > > > So here we go (in the order of increasing craziness): > > > > 1. Recently I've learned how Python greenlets are implemented. I believe > > that the same approach could work in Rust: > > > > Basically, greenlets are spawned using the same stack as the parent > > greenlet, just like a normal function call. When a greenlet is > suspended, > > it copies the portion of the stack used up since its' spawning to the > heap. > > When one is re-activated, the saved memory is copied back where it came > from > > (having first saved stack of the previous active greenlet,- if they > > overlap). > > > > Since greenlets don't need to save "red zone" of the stack, the amount of > > data per instance is precisely what is actually used. > > > > There are also downsides, of course: > > - greenlets are bound to the thread that spawned them, > > - two memcpy's are needed when switching between them. > > > > In the case of Python, though, there's one further optimization: since > > Python's stack frames live on the heap, in most cases, there nothing on > the > > hardware stack that a greenlet needs saving! As a bonus, it can now be > > resumed at any stack position, so no saving of previous greenlet's stack > is > > needed. The only time when a full save occurs is when there are foreign > > stack frames on the stack. > > > > > > 2. Well, can Rust do the same? What if we came up with an attribute, > say, > > [#stackless], which causes a function to allocate it's stack frame on the > > heap and put all local vars there? The only things on the actual > hardware > > stack would then be the function's arguments, the return address, the > saved > > base pointer and the pointer to that heap-alllocated frame. With the > > exception of base pointers, all these things are position-independent, I > > believe. And base pointer chain can be easily fixed up if/when stack is > > moved. > > > > So if we had that, and the whole greenlet's stack consisted of such > > functions, and there was a way for the "switch_to_greenlet()" function to > > detect that, then such greenlet's stack would be relocatable and could be > > resumed at any position in the thread's stack (or even in another > thread!) > > with minimal memory copying, just like in Python. > > > > Of course, the [#stackless] functions would be slower than the normal > ones, > > but in the scenario I've outlined in the beginning, it shouldn't be a > > problem. > > > > > > 3. Unfortunately, in order for the above scheme to work, all I/O > methods, > > (which are typically where yields happen), would need to be marked as > > [#stackless]... This would affect the performance of "normal" code using > > the same API, which is undesirable. > > > > Okay, but usually there are not that many things that point into the > stack > > in a typical program. I can think of only three things: references to > > stack-allocated buffers, base pointer chains and references to > > caller-allocated return values. > > - The first one can be lived without - just allocate buffers on the heap. > > - The second one - see above. > > - The last one is more tricky, but for the sake of argument, let's assume > > that we restricted function signatures such that only register-allocated > > types can be returned. > > > > Let's say we came up with a way to mark up functions that may yield to > > another greenlet, and also with a way to prohibit taking address of > > stack-allocated variables for the duration of calls to yielding > functions. > > These restrictions would be annoying, but not overly so, as long as you > had > > to obey them only in functions that are intended to be run in a greenlet. > > On the plus side, the hardware stack contents would now be relocatable. > > > > In this setup, everything could proceed as usual, using the hardware > stack, > > until execution came to a blocking I/O call. At that point, the > scheduler > > would check if running inside a greenlet, copy greenlet's stack to the > heap > > and switch off to another greenlet. Otherwise, it would do the same > thing > > it does now, i.e. switch tasks. > > > > > > So, what do you say, rustafarians? Does any of that make any sense? > > > > Vadim > > Rust has no way to move a stack/value and update the pointers to it. A > fundamental property of borrowed pointers is that they're just > integers in memory at runtime without any boxing or type information. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From spam at scientician.net Wed Nov 13 10:57:31 2013 From: spam at scientician.net (Bardur Arantsson) Date: Wed, 13 Nov 2013 19:57:31 +0100 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: On 2013-11-13 19:48, Bardur Arantsson wrote: > Having said that, M:N seems to work for Haskell where they recently > showed near-perfect scalability to 42 cores for a web server (beating > out nginx and apache handily, even on absolute numbers). For the life of > me I can't find the PDF/paper reference right now, but I'll try to > follow up with a proper reference. Oh, I think this is it: http://www.reddit.com/r/haskell/comments/1k6fsl/mio_a_highperformance_multicore_io_manager_for/ From fw at deneb.enyo.de Wed Nov 13 11:24:56 2013 From: fw at deneb.enyo.de (Florian Weimer) Date: Wed, 13 Nov 2013 20:24:56 +0100 Subject: [rust-dev] The future of M:N threading In-Reply-To: (Daniel Micay's message of "Wed, 13 Nov 2013 05:45:19 -0500") References: Message-ID: <871u2k85pz.fsf@mid.deneb.enyo.de> * Daniel Micay: > Rust's tasks are often called *lightweight* but at least on Linux the only > optimization is the lack of preemption. Since segmented stacks have been > dropped, the resident/virtual memory usage will be identical. Doesn't the lack of a corresponding kernel thread save something on the kernel side? In the C benchmark, the thread attribute should be created outside the loop. From vadimcn at gmail.com Wed Nov 13 11:29:31 2013 From: vadimcn at gmail.com (Vadim) Date: Wed, 13 Nov 2013 11:29:31 -0800 Subject: [rust-dev] Greenlets in Rust (was: Abandoning segmented stacks in Rust) In-Reply-To: References: Message-ID: Yes and no: - State machine generators are not "true" coroutines in that they are single-level only. Yes, you can nest them, but it's rather tricky to do that efficiently and transparently to the programmer. - In order to use a generator, the caller has to be aware that he is dealing with one. Generators tend to "infect" the whole callstack. I mean look at C# - once you have async function at the leaf level, you need to make its' callers async as well, at least up to the level where you spawn a bunch of them and then can afford to block your thread. - Async I/O using generators requires different API than blocking I/O. With greenlets this *might *be avoidable. - Greenlets can accommodate even foreign frames being on the stack (say, a call into C library, which calls back into Rust), event though this is not optimal for greenlet switching performance. That said, generators also have their uses. For example, greenlets would be too heavy to implement container iterators on top of them - because of the context switch overhead. Perhaps Rust needs both. I would like to hear what others think. PS: Incidentally, I am also brewing a proposal for how that Python-style generators could be done in Rust, but it isn't quite ready yet... On Wed, Nov 13, 2013 at 10:44 AM, Erick Tryzelaar wrote: > This approach is not all that different different from my plan to > implement generators: > > https://github.com/mozilla/rust/issues/7746 > > My current thinking is that a generator is really the combination between > storing the local variables in a structure instead of on the stack, and a > state machine to jump between each of the generator steps. Without thinking > too deeply into it, I suspect that the main difference between a generator > and a coroutine/greenlet is whether or not that structure is stored on the > stack or on the heap. I'm not quite sure how we'll handle passing data into > a coroutine, maybe we can reserve a slot in the environment structure for > passed in values, and the compiler can guarantee no one accesses that value > until it's been set. Unfortunately this'll requires a bunch of scary > compiler magic to get it all to work. But I don't think it's impossible. > > > > On Wed, Nov 13, 2013 at 10:20 AM, Daniel Micay wrote: > >> On Wed, Nov 13, 2013 at 3:02 AM, Vadim wrote: >> > Hi, >> > I would like to float a proposal (or three :-), regarding "greenlets" in >> > Rust. For those unfamiliar with greenlets, they are a tool for writing >> > concurrent code, similar to Rust's tasks, but much more light-weight in >> > terms of memory consumption (especially now that segmented stacks are no >> > more). >> > >> > I think there are some scenarios where low memory consumption per-task >> is >> > still important, 64-bit address spaces notwithstanding. A typical one >> > would be a pub-sub server, which needs to maintain a massive number of >> > simple I/O workflows, where I/O channels are idle most of the time. >> > >> > So here we go (in the order of increasing craziness): >> > >> > 1. Recently I've learned how Python greenlets are implemented. I >> believe >> > that the same approach could work in Rust: >> > >> > Basically, greenlets are spawned using the same stack as the parent >> > greenlet, just like a normal function call. When a greenlet is >> suspended, >> > it copies the portion of the stack used up since its' spawning to the >> heap. >> > When one is re-activated, the saved memory is copied back where it came >> from >> > (having first saved stack of the previous active greenlet,- if they >> > overlap). >> > >> > Since greenlets don't need to save "red zone" of the stack, the amount >> of >> > data per instance is precisely what is actually used. >> > >> > There are also downsides, of course: >> > - greenlets are bound to the thread that spawned them, >> > - two memcpy's are needed when switching between them. >> > >> > In the case of Python, though, there's one further optimization: since >> > Python's stack frames live on the heap, in most cases, there nothing on >> the >> > hardware stack that a greenlet needs saving! As a bonus, it can now be >> > resumed at any stack position, so no saving of previous greenlet's >> stack is >> > needed. The only time when a full save occurs is when there are foreign >> > stack frames on the stack. >> > >> > >> > 2. Well, can Rust do the same? What if we came up with an attribute, >> say, >> > [#stackless], which causes a function to allocate it's stack frame on >> the >> > heap and put all local vars there? The only things on the actual >> hardware >> > stack would then be the function's arguments, the return address, the >> saved >> > base pointer and the pointer to that heap-alllocated frame. With the >> > exception of base pointers, all these things are position-independent, I >> > believe. And base pointer chain can be easily fixed up if/when stack >> is >> > moved. >> > >> > So if we had that, and the whole greenlet's stack consisted of such >> > functions, and there was a way for the "switch_to_greenlet()" function >> to >> > detect that, then such greenlet's stack would be relocatable and could >> be >> > resumed at any position in the thread's stack (or even in another >> thread!) >> > with minimal memory copying, just like in Python. >> > >> > Of course, the [#stackless] functions would be slower than the normal >> ones, >> > but in the scenario I've outlined in the beginning, it shouldn't be a >> > problem. >> > >> > >> > 3. Unfortunately, in order for the above scheme to work, all I/O >> methods, >> > (which are typically where yields happen), would need to be marked as >> > [#stackless]... This would affect the performance of "normal" code >> using >> > the same API, which is undesirable. >> > >> > Okay, but usually there are not that many things that point into the >> stack >> > in a typical program. I can think of only three things: references to >> > stack-allocated buffers, base pointer chains and references to >> > caller-allocated return values. >> > - The first one can be lived without - just allocate buffers on the >> heap. >> > - The second one - see above. >> > - The last one is more tricky, but for the sake of argument, let's >> assume >> > that we restricted function signatures such that only register-allocated >> > types can be returned. >> > >> > Let's say we came up with a way to mark up functions that may yield to >> > another greenlet, and also with a way to prohibit taking address of >> > stack-allocated variables for the duration of calls to yielding >> functions. >> > These restrictions would be annoying, but not overly so, as long as you >> had >> > to obey them only in functions that are intended to be run in a >> greenlet. >> > On the plus side, the hardware stack contents would now be relocatable. >> > >> > In this setup, everything could proceed as usual, using the hardware >> stack, >> > until execution came to a blocking I/O call. At that point, the >> scheduler >> > would check if running inside a greenlet, copy greenlet's stack to the >> heap >> > and switch off to another greenlet. Otherwise, it would do the same >> thing >> > it does now, i.e. switch tasks. >> > >> > >> > So, what do you say, rustafarians? Does any of that make any sense? >> > >> > Vadim >> >> Rust has no way to move a stack/value and update the pointers to it. A >> fundamental property of borrowed pointers is that they're just >> integers in memory at runtime without any boxing or type information. >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Wed Nov 13 11:29:03 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 14:29:03 -0500 Subject: [rust-dev] The future of M:N threading In-Reply-To: <871u2k85pz.fsf@mid.deneb.enyo.de> References: <871u2k85pz.fsf@mid.deneb.enyo.de> Message-ID: On Wed, Nov 13, 2013 at 2:24 PM, Florian Weimer wrote: > * Daniel Micay: > >> Rust's tasks are often called *lightweight* but at least on Linux the only >> optimization is the lack of preemption. Since segmented stacks have been >> dropped, the resident/virtual memory usage will be identical. > > Doesn't the lack of a corresponding kernel thread save something on > the kernel side? > > In the C benchmark, the thread attribute should be created outside the > loop. The scheduler resources necessary for a thread are insignificant due to the ~8K RES (4K in userland, 4K overhead) and 8M VIRT required for the stack. Linux/FreeBSD are also fully capable of scheduling a very large number threads. From danielmicay at gmail.com Wed Nov 13 11:30:58 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 14:30:58 -0500 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: On Wed, Nov 13, 2013 at 1:48 PM, Bardur Arantsson wrote: > On 2013-11-13 11:45, Daniel Micay wrote: >> Before getting right into the gritty details about why I think we should think > [--snip--] > > Very interesting video about the kernel (in future) perhaps interacting > more closesly with user-space about scheduling decisions and threads, > thus reducing overhead and perhaps eliminating the *need* for M:N. > > Having said that, M:N seems to work for Haskell where they recently > showed near-perfect scalability to 42 cores for a web server (beating > out nginx and apache handily, even on absolute numbers). For the life of > me I can't find the PDF/paper reference right now, but I'll try to > follow up with a proper reference. Perhaps there's some magical > properties of Haskell with make that less problematic than for Rust, but... > > Anyway, of course we all *hope* that tricks like M:N won't be necessary > in the future, but how soon can we hope that the future arrives? ;) > > Regards, Haskell is a fully managed language with a precise garbage collector and doesn't use a traditional call stack so lightweight threads are a sunken cost. Rust tasks won't be comparably lightweight without segmented stacks and reinventing most of the standard C library like Go has to do. Go has precise garbage collector and could move to relocatable contiguous stacks in the future. It's known that M:N scheduling is a viable way of building a socket server. I'm only questioning whether it's worth making compromises for every other use case to micro-optimize context switches out of socket servers and make them scalable on platforms with poor support for the 1:1 threading model (OS X). From danielmicay at gmail.com Wed Nov 13 11:32:10 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 14:32:10 -0500 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: On Wed, Nov 13, 2013 at 1:32 PM, Alex Crichton wrote: > The situation may not be as dire as you think. The runtime is still in a state > of flux, and don't forget that in one summer the entire runtime was rewritten in > rust and was entirely redesigned. I personally still think that M:N is a viable > model for various applications, and it seems especially unfortunate to just > remove everything because it's not tailored for all use cases. > > Rust made an explicit design decision early on to pursue lightweight/green > tasks, and it was made with the understanding that there were drawbacks to the > strategy. Using libuv as a backend for driving I/O was also an explicit decision > with known drawbacks. > > That being said, I do not believe that all is lost. I don't believe that the > rust standard library as-is today can support *every* use case, but it's getting > to a point where it can get pretty close. In the recent redesign of the I/O > implementation, all I/O was abstracted behind trait objects that are synchronous > in their interface. This I/O interface is all implemented in librustuv by > talking to the rust scheduler under the hood. Additionally, in pull #10457, I'm > starting to add support for a native implementation of this I/O interface. The > great boon of this strategy is that all std::io primitives have no idea if their > underlying interface is native and blocking or libuv and asynchronous. The exact > same rust code works for one as it does for the other. > > I personally don't see why the same strategy shouldn't work for the task model > as well. When you link a program to the librustuv crate, then you're choosing to > have a runtime with M:N scheduling and asynchronous I/O. Perhaps, though, if you > didn't link to librustuv, you would get 1:1 scheduling with blocking I/O. You > would still have all the benefits of the standard library's communication > primitives, spawning primitives, I/O, task-local-storage etc. The only > difference is that everything would be powered by OS-level threads instead of > rust-level green tasks. > > I would very much like to see a standard library which supports this > abstraction, and I believe that it is very realistically possible. Right now we > have an EventLoop interface which defines interacting with I/O that is the > abstraction between asynchronous I/O and blocking I/O. This sounds like > we need a more formalized Scheduler interface which abstracts M:N scheduling vs > 1:1 scheduling. > > The main goal of all of this would be to allow the same exact rust code to work > in both M:N and 1:1 environments. This ability would allow authors to specialize > their code for their task at-hand. Those writing web servers would be sure to > link to librustuv, but those writing command-line utilities would simply just > omit librustuv. Additionally, as a library author, I don't really care which > implementation you're using. I can write a mysql database driver and then you as > a consumer of my library decided whether my network calls are blocking or not. > > This is a fairly new concept to me (I haven't thought much about it before), but > this sounds like it may be the right way forward to addressing your concerns > without compromising too much existing functionality. There would certainly be > plenty of work to do in this realm, and I'm not sure if this goal would block > the 1.0 milestone or not. Ideally, this would be a completely > backwards-compatible change, but there would perhaps be unintended consequences. > As always, this would need plenty of discussion to see whether this is even a > reasonable strategy to take. The same Rust code won't work with both 1:1 threading and M:N threading though. It's nearly impossible to expose safe bindings to a library like NSS with a heavy dependency on thread-local storage. With task pinning, the libraries could pin the task to the thread they were initialized on, but the interface is going to be much lower level than C. It will need a context object with all the functions as methods for the application to shove into task-local storage. I don't think it's possible to build completely lossless abstractions over the differences in TLS and I/O. A library supporting both will have an inferior API to a library with only 1:1 threading. There's an expectation that a language will work with a profiler like callgrind or provide these tools itself. Go comes with an implementation of CPU/memory profiling and analysis of M:N threading. Where are Rust's versions of these tools? The robust, proven solution is 1:1 threading and many operating systems used M:N threading before dropping it due to the significant drawbacks. The move to more expensive fair CPU scheduling didn't happen by historical accident. An M:N threading implementation is nothing but a performance optimization for the HPC and socket server use cases to avoid context switches. I'm not willing to make compromises in semantics or performance for other use cases to support this. I want Rust to be a viable replacement for C, C++, Java, C# and other languages but I don't see it happening with the standard library, so I'll just put my full effort behind developing an alternative. From spam at scientician.net Wed Nov 13 11:41:44 2013 From: spam at scientician.net (Bardur Arantsson) Date: Wed, 13 Nov 2013 20:41:44 +0100 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: On 2013-11-13 20:30, Daniel Micay wrote: > On Wed, Nov 13, 2013 at 1:48 PM, Bardur Arantsson wrote: >> On 2013-11-13 11:45, Daniel Micay wrote: >>> Before getting right into the gritty details about why I think we should think >> [--snip--] >> >> Very interesting video about the kernel (in future) perhaps interacting >> more closesly with user-space about scheduling decisions and threads, >> thus reducing overhead and perhaps eliminating the *need* for M:N. >> >> Having said that, M:N seems to work for Haskell where they recently >> showed near-perfect scalability to 42 cores for a web server (beating >> out nginx and apache handily, even on absolute numbers). For the life of >> me I can't find the PDF/paper reference right now, but I'll try to >> follow up with a proper reference. Perhaps there's some magical >> properties of Haskell with make that less problematic than for Rust, but... >> >> Anyway, of course we all *hope* that tricks like M:N won't be necessary >> in the future, but how soon can we hope that the future arrives? ;) >> >> Regards, > > Haskell is a fully managed language with a precise garbage collector > and doesn't use a traditional call stack so lightweight threads are a > sunken cost. Rust tasks won't be comparably lightweight without > segmented stacks and reinventing most of the standard C library like > Go has to do. Go has precise > garbage collector and could move to relocatable contiguous stacks in > the future. > I haven't been following too closely, so... I'm guessing a whole-program CPS transform is out of the picture? > It's known that M:N scheduling is a viable way of building a socket > server. I'm only questioning whether it's worth making compromises for > every other use case to micro-optimize context switches out of socket > servers and make them scalable on platforms with poor support for the > 1:1 threading model (OS X). Indeed, and abolutely correct. As long as the language semantics supports "thread-like" approach to concurrency (without shared state), you'll be golden. I think the point in the video[2] about non-blocking is bang on. In practice it's much more difficult to be *explicitly* async and it should just be delegated to the language/runtime. There are some things humans just aren't good at. Regards, From fw at deneb.enyo.de Wed Nov 13 11:54:25 2013 From: fw at deneb.enyo.de (Florian Weimer) Date: Wed, 13 Nov 2013 20:54:25 +0100 Subject: [rust-dev] Danger of throwing exceptions through Rust code In-Reply-To: (Daniel Micay's message of "Tue, 12 Nov 2013 14:50:06 -0500") References: Message-ID: <87wqkc6pse.fsf@mid.deneb.enyo.de> * Daniel Micay: > It's undefined behaviour for a C++ function to throw an exception past an > `extern "C"` boundary I don't think this is true. Certainly GCC supports throwing from C as an extension (if the C side has been compiled with -fexceptions), and requires that non-throwing functions are explicitly annotated, even if they have C linkage. From thadguidry at gmail.com Wed Nov 13 11:59:49 2013 From: thadguidry at gmail.com (Thad Guidry) Date: Wed, 13 Nov 2013 13:59:49 -0600 Subject: [rust-dev] Danger of throwing exceptions through Rust code In-Reply-To: <20131113163000.GD17283@Mr-Bennet> References: <20131113163000.GD17283@Mr-Bennet> Message-ID: In awe, Niko does a fantastic job of breaking things down. Give that guy a raise already. ;) And he brings the most important point of all in this discussion. "Sometimes authors care and sometimes they don't" Maybe the important distinction is "how" the author wraps the library, to bring about better failure semantics, regardless if the author needs them or not, at least they are available to care about or not ? -- -Thad +ThadGuidry Thad on LinkedIn -------------- next part -------------- An HTML attachment was scrubbed... URL: From info at bnoordhuis.nl Wed Nov 13 12:08:50 2013 From: info at bnoordhuis.nl (Ben Noordhuis) Date: Wed, 13 Nov 2013 21:08:50 +0100 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: On Wed, Nov 13, 2013 at 11:45 AM, Daniel Micay wrote: > Rust's requirements for asynchronous I/O would be filled well by direct usage > of IOCP on Windows. However, Linux only has solid support for non-blocking > sockets because file operations usually just retrieve a result from cache and > do not truly have to block. This results in libuv being significantly slower > than blocking I/O for most common cases for the sake of scalable socket > servers. Libuv maintainer here. Libuv's current approach to dealing with blocking I/O is fairly crude: it offloads everything to a rather unsophisticated thread pool. There is plenty of room for improvement. So far relatively little effort has gone into optimizing file I/O because it's not very critical for node.js. I've been looking for an excuse to spend more time on it so please file issues or post suggestions. If you have test cases or benchmarks where libuv is significantly lagging, please point me to them and I'll see what I can do. Apropos IOCP, it's no panacea. It has the same issue that native AIO on Linux has: it can silently turn asynchronous operations into synchronous ones. It's sometimes useful but it's not a general solution for all things AIO. > On modern systems with flash memory, including mobile, there is a *consistent* > and relatively small worst-case latency for accessing data on the disk so > blocking is essentially a non-issue. I'm not sure if I can agree with that. One of the issues with blocking I/O is that the calling thread gets rescheduled when the operation cannot be completed immediately. Depending on workload and system scheduler, it may get penalized when blocking often. From vadimcn at gmail.com Wed Nov 13 12:13:38 2013 From: vadimcn at gmail.com (Vadim) Date: Wed, 13 Nov 2013 12:13:38 -0800 Subject: [rust-dev] C# async for Rust In-Reply-To: References: Message-ID: On Wed, Nov 13, 2013 at 10:49 AM, Bill Myers wrote: > I see several proposals for the future of Rust tasks, and I think one of > the best approaches is being overlooked, and that is something similar to > async in C# (http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx > ). > > In C#, the "async" keyword can be applied to functions and it causes the > compiler to transform a function that returns T into a function that > returns a Task (which is C#'s name for a future of type T) representing > the potentially asynchronous computation. > > Blocking is representing by using the "await" keyword on a future > (typically returned by a call to another "async" function), and it causes > the compiler to perform a Continuation-Passing Style transformation, and > attach the continuation to the future, returning another future > representing the composed computation. > > I/O functions are designed to return futures, so in this system blocking > causes all calling "async" functions to return, building up a chain of > continuations on the heap, which is equivalent to the machine stack in a > current-Rust task, but which is as small as needed, and is only used for > call chains that block. > > In Rust, this transformation is much more delicate, because the resulting > return value futures must have a lifetime that is the smallest among all > the arguments to the function, if those arguments are needed by the > continuation, and the argument types must be "shareable" between parallel > forks (e.g. std::rc::Rc is not shareable because RC manipulation is > non-atomic). > Can you please elaborate on this point? What arguments are you talking about here, and why future's lifetime needs to be restricted? -------------- next part -------------- An HTML attachment was scrubbed... URL: From martindemello at gmail.com Wed Nov 13 12:37:40 2013 From: martindemello at gmail.com (Martin DeMello) Date: Wed, 13 Nov 2013 12:37:40 -0800 Subject: [rust-dev] typing in rust In-Reply-To: References: Message-ID: What ML does differently is having the syntax of let bindings explicitly introduce a new scope by being terminated with 'in' - e.g. you'd say let test = test () in println (format! ("{}", test)); which would make the behaviour unsurprising. martin On Wed, Nov 13, 2013 at 10:13 AM, Brendan Zabarauskas wrote: > SML also shares these semantics when it comes to bindings. That is, a subsequent binding to the same identifier can ?mask? those that proceed it, even if they are in the same scope and the bound values are of different types. Once a value has had its identifier masked, it can no longer be accessed. > > I assume this behaviour was passed on to Ocaml, and Rust inherited it from there. Rust was originally written in Ocaml, and has drawn many influences from there. I personally find it useful from time to time. > > ~Brendan > > On 14 Nov 2013, at 3:25 am, Joshua Rodgers wrote: > >> I'm curious as to why this is valid, though? This makes sense if you're inside a new or nested scope, but why is it valid inside the same scope as illustrated in the code example? >> >> I can understand it from the perspective that I need to mask a function name (but that's a nested scope to me, at that point). >> >> >> On Wed, Nov 13, 2013 at 8:54 AM, Scott Lawrence wrote: >> I would think that `test()` (the function) is in scope for the duration of `let test =`, and then the new definition masks the old one. Similarly, >> >> let x = 2; >> let x = x + 2; >> >> If you change the last line to /call/ test(), you should get an error. >> >> >> On Wed, 13 Nov 2013, Philip Herron wrote: >> >> Hey all >> >> I am still learning but i just tried something which i expected to give an >> error but works: >> >> fn test () -> int { >> 1 >> } >> >> fn main () { >> let test = test (); >> println (format! ("{}", test)); >> } >> >> I guess on compilation the names are mangled against their types or >> something so you can differentiate between test the function and test the >> variable. Not sure would be nice to get some clarification what this >> behavior is. >> >> Thanks >> >> --Phil >> >> >> -- >> Scott Lawrence >> _______________________________________________ >> 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 > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From igor at mir2.org Wed Nov 13 12:41:10 2013 From: igor at mir2.org (Igor Bukanov) Date: Wed, 13 Nov 2013 21:41:10 +0100 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: On 13 November 2013 20:41, Bardur Arantsson wrote: > In practice it's much more difficult to be *explicitly* > async and it should just be delegated to the language/runtime. There are > some things humans just aren't good at. I suspect Rust makes asynchronous programming significantly more bearable. Programming in JS in that style is often painful due to the noise of all those function() { } spread through the code and bugs connected with accessing stuff that should only be ready later. Rust nicely addresses that with shorter syntax for closures/macros and move semantics. So an experiment of writing in asynchronous style in Rust and comparing that with C++/JS/other languages would be very useful to judge. From dteller at mozilla.com Wed Nov 13 12:43:39 2013 From: dteller at mozilla.com (David Rajchenbach-Teller) Date: Wed, 13 Nov 2013 21:43:39 +0100 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: <5283E47B.8030901@mozilla.com> For what it's worth, writing async code in JS has become very bearable: http://taskjs.org/ Cheers, David On 11/13/13 9:41 PM, Igor Bukanov wrote: > I suspect Rust makes asynchronous programming significantly more > bearable. Programming in JS in that style is often painful due to the > noise of all those function() { } spread through the code and bugs > connected with accessing stuff that should only be ready later. Rust > nicely addresses that with shorter syntax for closures/macros and move > semantics. > > So an experiment of writing in asynchronous style in Rust and > comparing that with C++/JS/other languages would be very useful to > judge. > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- David Rajchenbach-Teller, PhD Performance Team, Mozilla From james at mansionfamily.plus.com Wed Nov 13 12:51:01 2013 From: james at mansionfamily.plus.com (james) Date: Wed, 13 Nov 2013 20:51:01 +0000 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: <5283E635.7040505@mansionfamily.plus.com> On 13/11/2013 19:30, Daniel Micay wrote: > It's known that M:N scheduling is a viable way of building a socket > server. I'm only questioning whether it's worth making compromises for > every other use case to micro-optimize context switches out of socket > servers and make them scalable on platforms with poor support for the > 1:1 threading model (OS X). I take great issue with some of what you write: - there is an assumption that lightweight is useful primarily for 'socket servers' - you say things are not problems, if they are not problems on Linux, for some unspecified version of Linux. For the former: you seem to disregard the benefits that actor-based systems with very lightweight tasks can have. For the latter, well, not everyone uses Linux, all the time, and I had though Rust was supposed to be portable, and by that I would expect good performance to be portable as well as syntax. I had high hopes of Rust having lightweight segmented stacks and precise per-task GC and portability too. Sort of Erlang with type safety and AOT compilation with a sane model. But now much of this seems abandoned or clearly a long way out and it is becoming more like C++ with some functional bits, and I can get that with Scala and F# now. James, in sadness. -------------- next part -------------- An HTML attachment was scrubbed... URL: From igor at mir2.org Wed Nov 13 12:52:58 2013 From: igor at mir2.org (Igor Bukanov) Date: Wed, 13 Nov 2013 21:52:58 +0100 Subject: [rust-dev] C# async for Rust In-Reply-To: References: Message-ID: On 13 November 2013 19:49, Bill Myers wrote: > Advantages: > - Functions and interfaces that can perform I/O or can block are clearly > marked by a keyword This is similar to IO Monad in Haskell. Adding that to previously pure computational code is painful, but on the other hand it does emphasis that computational code != IO code and minimizing mixing between two typically leads to better design overall. From oren at ben-kiki.org Wed Nov 13 13:22:30 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Wed, 13 Nov 2013 23:22:30 +0200 Subject: [rust-dev] The future of M:N threading In-Reply-To: <5283E635.7040505@mansionfamily.plus.com> References: <5283E635.7040505@mansionfamily.plus.com> Message-ID: On Wed, Nov 13, 2013 at 10:51 PM, james wrote: > On 13/11/2013 19:30, Daniel Micay wrote: > I had high hopes of Rust having lightweight segmented stacks and precise > per-task > GC and portability too. Sort of Erlang with type safety and AOT > compilation with a > sane model. > That's something I'd also love to see! The "Erlang with type safety and compilation" is definitely something I was (am!) expecting from Rust. (I think Rust could be a good basis for distributed actor-style systems, due to the owned pointers it is clear how to send messages from one machine to another, but that's another story...) > But now much of this seems abandoned or clearly a long way out and it is > becoming > more like C++ with some functional bits, and I can get that with Scala > and F# now. > To be fair, Scala and F# are still VM languages while Rust is compiled. And I _hope_ "not all is lost", so that Rust would still be friendly to actor-style programs (as well as to socket-server style programs). It does seem the focus has shifted away from this :-( I find it more scary that Rust might be turning towards a "universal platform for implementing your own pointers/scheduler/abstractions" rather than an "opinionated platform providing a great set of pointers/scheduler/abstractions". The need to allow for "any and every" pattern combined with "extract the last 1% of performance" has IMO poisoned C++; I was drawn to Rust as "take the good parts, bake them into the language, and ignore the rest, even at some reasonable performance cost". It is somewhat ironic that Rust, which at times has a much "lower level" feel to it, provides essential higher-level features like algebraic types and pattern matching and generics, while a "more abstract" language like Go doesn't. As an application developer who doesn't care about the last 15% of the performance, but cares a lot about productivity, I can't help but wish for a happy medium between the two :-) At any rate, language design is _hard_. Rust is actually doing pretty well... and one can drastically evolve the runtime/scheduler over time - even provide different versions for different needs. It is much harder to fix the basic language abstractions, which Rust gets pretty well. -------------- next part -------------- An HTML attachment was scrubbed... URL: From igor at mir2.org Wed Nov 13 13:41:20 2013 From: igor at mir2.org (Igor Bukanov) Date: Wed, 13 Nov 2013 22:41:20 +0100 Subject: [rust-dev] Rust compiler running on ARM? In-Reply-To: References: Message-ID: It seems floating point code generation is broken for armhf as the following trivial program hangs after printing 1 with rust-0.9-pre-3b0d486-arm- unknown-linux-gnueabihf.zip . Should I file a bug about that? enum Test { A(f64), B(f64) } impl Test { fn draw(&self) { println!("1"); match *self { A(x) => println!("A {}", x), B(x) => println!("B {}", x) } println!("2"); } } fn main() { let s = A(0.1); s.draw(); } On 13 November 2013 09:49, Matthew McPherrin wrote: > Luqman got rustc running on ARM. Builds are maybe here: > http://luqman.ca/rust-builds/ > > On Mon, Oct 21, 2013 at 12:42 AM, Corey Richardson wrote: >> I've yet to see or hear of a rustc running native on ARM, though it >> shouldn't be impossible to cross-build rustc for native ARM: we can >> already target ARM just fine. >> >> On Mon, Oct 21, 2013 at 2:01 AM, Igor Bukanov wrote: >>> What is the current status of ARM support in Rust? In particularly I >>> am interested in running the compiler on an ARM Chromebook. >>> _______________________________________________ >>> 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 From pcwalton at mozilla.com Wed Nov 13 13:45:08 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Thu, 14 Nov 2013 06:45:08 +0900 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: <5283F2E4.8040802@mozilla.com> On 11/14/13 4:32 AM, Daniel Micay wrote: > The same Rust code won't work with both 1:1 threading and M:N > threading though. It's nearly impossible to expose safe bindings to a > library like NSS with a heavy dependency on thread-local storage. With > task pinning, the libraries could pin the task to the thread they were > initialized on, but the interface is going to be much lower level than > C. It will need a context object with all the functions as methods for > the application to shove into task-local storage. I don't understand this. If a library uses native TLS, then I think a reasonable implementation strategy in an M:N scheduler is to just perform the task pinning, and then the implementation will be the same as the 1:1 scheduler since TLS will be available. > I don't think it's possible to build completely lossless abstractions > over the differences in TLS and I/O. A library supporting both will > have an inferior API to a library with only 1:1 threading. Without specifics I'm not convinced. I/O is, at its core, about these things: * A `Reader` and `Writer` trait, along with a couple of supporting traits. * Opening files, network streams, and other handles, and RAII-based destructors to close them. TLS is, at its core, about these things: * Declaring and initializing a TLS slot. * Writing and reading data to and from that TLS slot. These interfaces remain the same regardless of whether M:N or 1:1 is used. Now it may well be the case that they're so different that no implementations can reasonably be shared for performance reasons: you don't even want a runtime check to see whether we're in M:N or 1:1 scheduling mode. But it seems to me that that is what `#[cfg]` is for: if we decide that 1:1 scheduling is sufficiently mature on the host OS we can just not even compile M:N scheduling and hardwire in 1:1, eliminating the runtime tax. It may also be the case that there are some APIs that we can only surface in 1:1 and M:N (Built-in TLS variables come to mind for the former; scheduling modes come to mind for the latter.) That's fine; along the edges we can surface those APIs without compromising the core set of abstractions. Moving from one to another may not be as simple as "flip a switch and recompile your app", but it should be reasonable to have an app that works in both with minor `#[cfg]` changes. And this is an important use case: consider a game that does heavy computation and wants maximum performance on Windows 7 and iOS, for example. > There's an expectation that a language will work with a profiler like > callgrind or provide these tools itself. Go comes with an > implementation of CPU/memory profiling and analysis of M:N threading. > Where are Rust's versions of these tools? We haven't written them yet, but we can. But perf and Instruments work reasonably well with the M:N threads already. Enough to find the hot spots in the call graph rooted at a particular function, which is 90% of what you want profilers for. > The robust, proven solution is 1:1 threading and many operating > systems used M:N threading before dropping it due to the significant > drawbacks. The move to more expensive fair CPU scheduling didn't > happen by historical accident. I find the argument that 1:1 threading is where things are going persuasive. But we still need to support systems that are in place today, as well as systems in which M:N currently performs better and may continue to in the future. It sounds like Windows is in good shape, but Linux doesn't have the user-mode scheduling patches yet, and I don't know what Apple's plans are for Mac OS X. Those are all important platforms for us, and for others. I'm personally fine with looking into migrating away from M:N scheduling on some platforms, but I think it would be a shame to fracture the community to do it by forking the standard library. More on that below. > An M:N threading implementation is nothing but a performance > optimization for the HPC and socket server use cases to avoid context > switches. I'm not willing to make compromises in semantics or > performance for other use cases to support this. We're developing a language for many use cases. M:N is useful for some cases and on some platforms, while 1:1 is useful for others. Part of what a general-purpose systems language should strive to do is to provide abstractions that allow for portability to the greatest extent possible. > I want Rust to be a viable replacement for C, C++, Java, C# and other > languages but I don't see it happening with the standard library, so > I'll just put my full effort behind developing an alternative. I hope you reconsider. As I said before, I think that, even if the implementation needs to be totally different, there is little point in duplicating traits like `Reader` and `Writer` and `TcpStream`. Divergence is just going to fragment the nascent community. One of the main reasons that those languages have been successful is that, in all of them, the core set of APIs are consistent and available everywhere. I don't want a situation whereby half of the Rust community will be writing libraries that depend on `libstd` and half will be writing libraries that depend on `rust-core`, when most of the libraries work just fine in either. For example, `lmath` is just linear algebra; it would be a shame if it had to choose a camp over needless API differences. If we need to split out the Rust standard library into a core set of interfaces that remain the same across different implementations, then I think it would be much more productive to talk about doing that. I've reviewed rust-core and I don't really see any fundamental differences that prevent compatibility with the standard library--in fact, I'd really like to try to just merge them: pulling in the I/O as the "native I/O" module, eliminating redundant traits from libstd, eliminating conditions, taking whichever algorithms are faster, and so on. We can find and shake out bugs as we go. Patrick From dteller at mozilla.com Wed Nov 13 13:46:33 2013 From: dteller at mozilla.com (David Rajchenbach-Teller) Date: Wed, 13 Nov 2013 22:46:33 +0100 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: <5283F339.6040201@mozilla.com> On 11/13/13 9:08 PM, Ben Noordhuis wrote: > Libuv maintainer here. Libuv's current approach to dealing with > blocking I/O is fairly crude: it offloads everything to a rather > unsophisticated thread pool. There is plenty of room for improvement. > > So far relatively little effort has gone into optimizing file I/O > because it's not very critical for node.js. I've been looking for an > excuse to spend more time on it so please file issues or post > suggestions. If you have test cases or benchmarks where libuv is > significantly lagging, please point me to them and I'll see what I can > do. If, by any chance, I find time, I would be interested in giving a hand. (I'm the main dev of Mozilla's OS.File) [...] >> On modern systems with flash memory, including mobile, there is a *consistent* >> and relatively small worst-case latency for accessing data on the disk so >> blocking is essentially a non-issue. Well, for some systems, that's possible, but in the wild, that's not realistic. Firefox Telemetry shows unpredictable worst-case latencies that can be very long (I am talking multi-seconds worst-case, and 800 ms rather common cases). > I'm not sure if I can agree with that. One of the issues with > blocking I/O is that the calling thread gets rescheduled when the > operation cannot be completed immediately. Depending on workload and > system scheduler, it may get penalized when blocking often. Is that an issue? I tend to assume that a thread that does I/O should expect being rescheduled often. Cheers, David -- David Rajchenbach-Teller, PhD Performance Team, Mozilla From bill_myers at outlook.com Wed Nov 13 14:12:54 2013 From: bill_myers at outlook.com (Bill Myers) Date: Wed, 13 Nov 2013 22:12:54 +0000 Subject: [rust-dev] C# async for Rust In-Reply-To: References: , Message-ID: > This is similar to IO Monad in Haskell. Adding that to previously pure > computational code is painful, but on the other hand it does emphasis > that computational code != IO code and minimizing mixing between two > typically leads to better design overall. Yes, but you can have the compiler automatically transform normal code into the equivalent of Haskell's "do notation", which is what C# does with async. Basically code like this: async fn foo() -> uint { let a: int = compute_a(); let b: int = compute_b(); let c: char = await read_char(); let r: uint = compute_r(a, b, c); return r; } becomes after the compiler performs CPS transform: // assume that we have trait Continuation {fn continue(~self, v: T);} // assume that cps_read_char is provided by the runtime and tells a main loop to read a char and then schedule a new task running the passed continuation struct foo_Continuation(~Continuation, int, int); fn cps_foo(continuation: ~Continuation) { let a: int = compute_a(); let b: int = compute_b(); return cps_read_char(~foo_Continuation(continuation, a, b)); } impl Continuation for foo_Continuation { fn continue(~self, c: char) { let (continuation, a, b) = *self; let r = compute_r(a, b, c); continuation.continue(r); } } and then a future-based version can also be generated by the compiler based on the CPS transform results: // assume that Continuation is implemented on TaskFuture and causes the TaskFuture to be completed with the value fn future_foo() -> ~TaskFuture { let f = ~TaskFuture::new(); cps_foo(f); return f; } Note that if foo() had taken a borrowed pointer with lifetime 'a, then the CPS version becomes unsafe, and TaskFuture would also need an 'a parameter. Also, one can use a borrowed pointer instead of an owned pointer for continuations and futures, but then they need to be waited on before its lifetime region ends. -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Wed Nov 13 14:15:09 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 17:15:09 -0500 Subject: [rust-dev] C# async for Rust In-Reply-To: References: Message-ID: On Wed, Nov 13, 2013 at 1:49 PM, Bill Myers wrote: > I see several proposals for the future of Rust tasks, and I think one of the > best approaches is being overlooked, and that is something similar to async > in C# (http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx). > > In C#, the "async" keyword can be applied to functions and it causes the > compiler to transform a function that returns T into a function that returns > a Task (which is C#'s name for a future of type T) representing the > potentially asynchronous computation. > > Blocking is representing by using the "await" keyword on a future (typically > returned by a call to another "async" function), and it causes the compiler > to perform a Continuation-Passing Style transformation, and attach the > continuation to the future, returning another future representing the > composed computation. > > I/O functions are designed to return futures, so in this system blocking > causes all calling "async" functions to return, building up a chain of > continuations on the heap, which is equivalent to the machine stack in a > current-Rust task, but which is as small as needed, and is only used for > call chains that block. > > In Rust, this transformation is much more delicate, because the resulting > return value futures must have a lifetime that is the smallest among all the > arguments to the function, if those arguments are needed by the > continuation, and the argument types must be "shareable" between parallel > forks (e.g. std::rc::Rc is not shareable because RC manipulation is > non-atomic). > > However, it is possible to restrict the system to use non-delimited > continuations instead of the delimited continuations and futures, which > would avoid this problem, since futures cannot be used explicitly anymore > (at the cost of making flexible parallelism impossible). > > In this latter case, it would be equivalent to the current task system, > except for requiring blocking functions to be marked "async"; the "await" > keyword would not be required, since it would effectively become compulsory > if there are no first-class futures returned for async functions. > > Advantages: > - Functions and interfaces that can perform I/O or can block are clearly > marked by a keyword > - Can have billions of blocked tasks (with hundreds of gigabytes of RAM) > since the memory used by each blocked task is truly minimized because it's > on the heap > > Disadvantages: > - Requires an heap allocation for every function call to an async function > (to hold the continuation data) > - Non-"async" functions cannot call "async" functions, so interfaces must be > explicitly marked as async or not > - Requires to implement the transform in the compiler > > Microsoft switched to this paradigm in the latest version of C# and in the > Windows RT API, and it might be an appropriate choice for Rust too. The issue with async/await is that while it maps very well to the AIO primitives like IOCP and POSIX AIO, it doesn't map well to something that's solid on Linux. It's just not how I/O is done on the platform. It uses *non-blocking* I/O so scale up socket servers, with notification of ready state rather than completion state. This doesn't work for file system access though. There's a significant performance hit from moving maybe-blocking I/O calls into thread pools to fit a square peg into a round hole. From danielmicay at gmail.com Wed Nov 13 14:26:06 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 17:26:06 -0500 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: On Wed, Nov 13, 2013 at 3:08 PM, Ben Noordhuis wrote: > On Wed, Nov 13, 2013 at 11:45 AM, Daniel Micay wrote: >> Rust's requirements for asynchronous I/O would be filled well by direct usage >> of IOCP on Windows. However, Linux only has solid support for non-blocking >> sockets because file operations usually just retrieve a result from cache and >> do not truly have to block. This results in libuv being significantly slower >> than blocking I/O for most common cases for the sake of scalable socket >> servers. > > Libuv maintainer here. Libuv's current approach to dealing with > blocking I/O is fairly crude: it offloads everything to a rather > unsophisticated thread pool. There is plenty of room for improvement. > > So far relatively little effort has gone into optimizing file I/O > because it's not very critical for node.js. I've been looking for an > excuse to spend more time on it so please file issues or post > suggestions. If you have test cases or benchmarks where libuv is > significantly lagging, please point me to them and I'll see what I can > do. I expect that regardless of how much effort will be put into libuv, it won't be *as fast* as blocking I/O for the common small scale cases most people care about. Rust wants to appeal to C++ programmers, and it isn't going to do that if there's anything more than a 10-15% performance hit (for CPU-bound or IO-bound work). In a 64-bit world, even traditional blocking I/O looks pretty bad when you can memory map everything on many disks many times over. > Apropos IOCP, it's no panacea. It has the same issue that native AIO > on Linux has: it can silently turn asynchronous operations into > synchronous ones. It's sometimes useful but it's not a general > solution for all things AIO. > >> On modern systems with flash memory, including mobile, there is a *consistent* >> and relatively small worst-case latency for accessing data on the disk so >> blocking is essentially a non-issue. > > I'm not sure if I can agree with that. One of the issues with > blocking I/O is that the calling thread gets rescheduled when the > operation cannot be completed immediately. Depending on workload and > system scheduler, it may get penalized when blocking often. Assuming Google lands their user-mode scheduling work, we would have control over the scheduling of tasks with I/O-bound workloads. They could be queued in a round-robin style, or weighted by whatever we consider important (arrival time of a request, etc.). This is already available on the 64-bit versions of Windows 7/8/Server, and I don't think we need to worry about XP/Vista as even security updates will be cut off soon and tasks won't scale any better than threads on 32-bit. It would make sense to keep using libuv for cases where it's faster than the blocking calls, but we wouldn't *have* to use it because control would be returned to the scheduler on a blocking call or page fault. From bill_myers at outlook.com Wed Nov 13 14:32:37 2013 From: bill_myers at outlook.com (Bill Myers) Date: Wed, 13 Nov 2013 22:32:37 +0000 Subject: [rust-dev] C# async for Rust In-Reply-To: References: , Message-ID: > The issue with async/await is that while it maps very well to the AIO > primitives like IOCP and POSIX AIO, it doesn't map well to something > that's solid on Linux. It's just not how I/O is done on the platform. > It uses *non-blocking* I/O so scale up socket servers, with > notification of ready state rather than completion state. This doesn't > work for file system access though. Well, I/O would work exactly the same as the current libuv-based Rust tasks approach, except that one needs a stack for each CPU thread and not for each task, because task creation functions return when a task wants to block, and thus there is no stack to save and restore. On Linux, the epoll interface allows to implement this, and I think it's what libuv uses. The only problem is that Linux doesn't really support asynchronously resolving file paths to inodes (aka opening files), but that can be done on a dedicated thread pool, with the advantage that the threads don't do anything, so they don't have zombie stacks. The problem with blocking on all threads/the 1:1 thread model is that if you do a computation that requires 8MB of stack, and then block with a shallow call stack, the 8MB of stack are not freed, so you waste 8MB per TCP connection in a TCP server example, which means that on a system with 32GB RAM you can only service 4096 TCP connections without swapping to disk instead of millions. A dedicated thread pool for blocking I/O doesn't have this issue because it can run with only 4KB stack or so since it doesn't do anything stack intensive, and the number of its threads can be limited without user-visible results. -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Wed Nov 13 14:37:22 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Thu, 14 Nov 2013 07:37:22 +0900 Subject: [rust-dev] The future of M:N threading In-Reply-To: <5283F2E4.8040802@mozilla.com> References: <5283F2E4.8040802@mozilla.com> Message-ID: <5283FF22.7020106@mozilla.com> On 11/14/13 6:45 AM, Patrick Walton wrote: > If we need to split out the Rust standard library into a core set of > interfaces that remain the same across different implementations, then I > think it would be much more productive to talk about doing that. I've > reviewed rust-core and I don't really see any fundamental differences > that prevent compatibility with the standard library--in fact, I'd > really like to try to just merge them: pulling in the I/O as the "native > I/O" module, eliminating redundant traits from libstd, eliminating > conditions, taking whichever algorithms are faster, and so on. We can > find and shake out bugs as we go. To be more specific, here's how I propose to move forward. 1. Finish fleshing out the native I/O in libstd to achieve parity with the uv-based I/O. 2. Provide pthread-based implementations of `task::spawn`. 3. Provide native TLS with a matching API to the task-local storage API. 4. Figure out what to do about ports and channels and failure in 1:1 scheduling. At this point we will have a task story for 1:1 scheduling that mirrors the M:N scheduling. We will then have a solid basis to decide what the defaults should be on each platform. If we decide that 1:1 scheduling is the best fit for all platforms, we can then consider dumping the M:N scheduling. At the same time, I would like to suggest that rust-core track the APIs of libstd and file bugs/PRs to get APIs changed if there are problems, to avoid fragmenting downstream libraries. I welcome discussion on this strategy and hope that it's acceptable to everyone. Patrick From dbau.pp at gmail.com Wed Nov 13 14:43:10 2013 From: dbau.pp at gmail.com (Huon Wilson) Date: Thu, 14 Nov 2013 09:43:10 +1100 Subject: [rust-dev] The future of M:N threading In-Reply-To: <5283FF22.7020106@mozilla.com> References: <5283F2E4.8040802@mozilla.com> <5283FF22.7020106@mozilla.com> Message-ID: <5284007E.4000204@gmail.com> On 14/11/13 09:37, Patrick Walton wrote: > On 11/14/13 6:45 AM, Patrick Walton wrote: >> If we need to split out the Rust standard library into a core set of >> interfaces that remain the same across different implementations, then I >> think it would be much more productive to talk about doing that. I've >> reviewed rust-core and I don't really see any fundamental differences >> that prevent compatibility with the standard library--in fact, I'd >> really like to try to just merge them: pulling in the I/O as the "native >> I/O" module, eliminating redundant traits from libstd, eliminating >> conditions, taking whichever algorithms are faster, and so on. We can >> find and shake out bugs as we go. > > To be more specific, here's how I propose to move forward. > > 1. Finish fleshing out the native I/O in libstd to achieve parity with > the uv-based I/O. Coincidentally, Alex opened #10457 in the last day which makes things like println() work with without libuv (and without the runtime!). https://github.com/mozilla/rust/pull/10457 Examples: https://github.com/mozilla/rust/pull/10457/files#diff-10 Huon From dteller at mozilla.com Wed Nov 13 14:44:33 2013 From: dteller at mozilla.com (David Rajchenbach-Teller) Date: Wed, 13 Nov 2013 23:44:33 +0100 Subject: [rust-dev] The future of M:N threading In-Reply-To: <5283FF22.7020106@mozilla.com> References: <5283F2E4.8040802@mozilla.com> <5283FF22.7020106@mozilla.com> Message-ID: <528400D1.10007@mozilla.com> On 11/13/13 11:37 PM, Patrick Walton wrote: > 1. Finish fleshing out the native I/O in libstd to achieve parity with > the uv-based I/O. You may be interested in taking a look at the API of OS.File. The design is rather different to libuv, as it is meant (only) for file I/O rather than (mostly) net I/O. In particular, we to: - minimize the total amount of I/O required (so as to save battery); - take advantage of high-level primitives provided by the OS wherever available; - expose OS-specific features, rather than just ~Posix; - use a single worker thread, to avoid causing disk thrashing. Cheers, David -- David Rajchenbach-Teller, PhD Performance Team, Mozilla From bill_myers at outlook.com Wed Nov 13 14:51:46 2013 From: bill_myers at outlook.com (Bill Myers) Date: Wed, 13 Nov 2013 22:51:46 +0000 Subject: [rust-dev] C# async for Rust In-Reply-To: References: , , , Message-ID: Although, on second thought, one could just free the unused part of the user mode stack whenever a thread blocks, either in the user mode code (i.e. using madvise MADV_DONTNEED or equivalent to discard everything below the stack pointer modulo the page size, perhaps minus the page size) or automatically in a modified kernel, and thus greatly reduce the worst case. It's still going to have higher overhead than the CPS continuations on the heap, because the stack will tend to have holes where dead variables live, for aligning to page boundaries, and you also keep around the kernel stack and kernel scheduler objects. And it doesn't work on 32-bit, because you cannot have more than around 2048 tasks with megabyte-sized task stacks (which is way too low for several usages), and unfortunately there are lots of 32-bit-only smartphones and tablets that should probably be supported. -------------- next part -------------- An HTML attachment was scrubbed... URL: From pcwalton at mozilla.com Wed Nov 13 14:55:13 2013 From: pcwalton at mozilla.com (Patrick Walton) Date: Thu, 14 Nov 2013 07:55:13 +0900 Subject: [rust-dev] The future of M:N threading In-Reply-To: <5283E635.7040505@mansionfamily.plus.com> References: <5283E635.7040505@mansionfamily.plus.com> Message-ID: <52840351.8070802@mozilla.com> On 11/14/13 5:51 AM, james wrote: > I had high hopes of Rust having lightweight segmented stacks and precise > per-task > GC and portability too. Sort of Erlang with type safety and AOT > compilation with a > sane model. None of this has changed, except for segmented stacks. Regarding segmented stacks, I think they should be viewed as a means to an end (scalability) rather than an end in and of themselves. 64-bit hardware and lazy OS-level page mapping is just another means to achieve the same end. Patrick From danielmicay at gmail.com Wed Nov 13 15:03:15 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 18:03:15 -0500 Subject: [rust-dev] C# async for Rust In-Reply-To: References: Message-ID: On Wed, Nov 13, 2013 at 5:51 PM, Bill Myers wrote: > Although, on second thought, one could just free the unused part of the user > mode stack whenever a thread blocks, either in the user mode code (i.e. > using madvise MADV_DONTNEED or equivalent to discard everything below the > stack pointer modulo the page size, perhaps minus the page size) or > automatically in a modified kernel, and thus greatly reduce the worst case. > > It's still going to have higher overhead than the CPS continuations on the > heap, because the stack will tend to have holes where dead variables live, > for aligning to page boundaries, and you also keep around the kernel stack > and kernel scheduler objects. > > And it doesn't work on 32-bit, because you cannot have more than around 2048 > tasks with megabyte-sized task stacks (which is way too low for several > usages), and unfortunately there are lots of 32-bit-only smartphones and > tablets that should probably be supported. > We don't need to worry about scaling on existing phones and tablets. They have short lifetimes, and most of them don't even receive security updates. The iPhone 5S is already 64-bit and Android vendors will move too, especially since they traditionally ship a lot more memory in even mid-level phones. From danielmicay at gmail.com Wed Nov 13 15:10:27 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 18:10:27 -0500 Subject: [rust-dev] C# async for Rust In-Reply-To: References: Message-ID: On Wed, Nov 13, 2013 at 5:32 PM, Bill Myers wrote: >> The issue with async/await is that while it maps very well to the AIO >> primitives like IOCP and POSIX AIO, it doesn't map well to something >> that's solid on Linux. It's just not how I/O is done on the platform. >> It uses *non-blocking* I/O so scale up socket servers, with >> notification of ready state rather than completion state. This doesn't >> work for file system access though. > > Well, I/O would work exactly the same as the current libuv-based Rust tasks > approach, except that one needs a stack for each CPU thread and not for each > task, because task creation functions return when a task wants to block, and > thus there is no stack to save and restore. > > On Linux, the epoll interface allows to implement this, and I think it's > what libuv uses. The epoll interface only allows waiting for ready (not completion) state from sockets. It does not work for file system input/output or meta operations. As a hack, timers, signals and pluggable events have been exposed as file descriptors with ready events but nothing for truly doing non-blocking file I/O. The libuv implementation of non-socket I/O uses thread pools on Linux. Note that *writes* to sockets are still potentially blocking and a thread pool might be used even for that. > The only problem is that Linux doesn't really support asynchronously > resolving file paths to inodes (aka opening files), but that can be done on > a dedicated thread pool, with the advantage that the threads don't do > anything, so they don't have zombie stacks. The file metadata cache is small enough that there's no point in considering it blocking. You might as well considering memory accesses blocking at that extreme, because they might require fetching memory to the CPU cache. > The problem with blocking on all threads/the 1:1 thread model is that if you > do a computation that requires 8MB of stack, and then block with a shallow > call stack, the 8MB of stack are not freed, so you waste 8MB per TCP > connection in a TCP server example, which means that on a system with 32GB > RAM you can only service 4096 TCP connections without swapping to disk > instead of millions. There's no difference between M:N scheduling and 1:1 scheduling in regards to resource usage and stacks. Every task has to have a stack. > A dedicated thread pool for blocking I/O doesn't have this issue because it > can run with only 4KB stack or so since it doesn't do anything stack > intensive, and the number of its threads can be limited without user-visible > results. Using a thread pool for blocking I/O is a significant performance issue. Is it okay for small operating to be 5x, 10x, 20x or 30x slower than C in a *systems language*? Perhaps 15%, but context switches to and from a thread pool aren't going to get you that. It's always going to be much slower to pretend Linux I/O is non-blocking via layers of indirection and dispatching to other threads. The model Rust wants to use is appreciated enough that the Linux kernel will likely support it directly via 1:1 threading like Win7/8 already do. From dteller at mozilla.com Wed Nov 13 15:21:50 2013 From: dteller at mozilla.com (David Rajchenbach-Teller) Date: Thu, 14 Nov 2013 00:21:50 +0100 Subject: [rust-dev] C# async for Rust In-Reply-To: References: Message-ID: <5284098E.4050302@mozilla.com> On Thu Nov 14 00:10:27 2013, Daniel Micay wrote: >> The only problem is that Linux doesn't really support asynchronously >> resolving file paths to inodes (aka opening files), but that can be done on >> a dedicated thread pool, with the advantage that the threads don't do >> anything, so they don't have zombie stacks. > > The file metadata cache is small enough that there's no point in > considering it blocking. You might as well considering memory accesses > blocking at that extreme, because they might require fetching memory > to the CPU cache. Are you sure about that? If my memory serves, you still need to fetch it from disk in most cases. On platforms in which devices have a mechanical component, even trivial accesses can end up very expensive in case of disk thrashing and/or sleeping disk. Cheers, David -- David Rajchenbach-Teller, PhD Performance Team, Mozilla From vadimcn at gmail.com Wed Nov 13 15:25:22 2013 From: vadimcn at gmail.com (Vadim) Date: Wed, 13 Nov 2013 15:25:22 -0800 Subject: [rust-dev] C# async for Rust In-Reply-To: References: Message-ID: But I guarantee you that a smaller form factor devices will appear in short order, and they won't use 64-bit CPUs, because in the beginning they won't have anywhere close to 4GB RAM, so a 64-bit memory bus and MMU will be an overkill for them. And the cycle will repeat... Even in the phones and PCs, many sub-components contain their own 32-bit controllers, and those need to be programmed too. And Rust is aiming for this niche, doesn't it? I think you are getting dangerously close to the argument that "we don't need to optimize code, because Moore's law will take care of performance" :-) On Wed, Nov 13, 2013 at 3:03 PM, Daniel Micay wrote: > On Wed, Nov 13, 2013 at 5:51 PM, Bill Myers > wrote: > > Although, on second thought, one could just free the unused part of the > user > > mode stack whenever a thread blocks, either in the user mode code (i.e. > > using madvise MADV_DONTNEED or equivalent to discard everything below the > > stack pointer modulo the page size, perhaps minus the page size) or > > automatically in a modified kernel, and thus greatly reduce the worst > case. > > > > It's still going to have higher overhead than the CPS continuations on > the > > heap, because the stack will tend to have holes where dead variables > live, > > for aligning to page boundaries, and you also keep around the kernel > stack > > and kernel scheduler objects. > > > > And it doesn't work on 32-bit, because you cannot have more than around > 2048 > > tasks with megabyte-sized task stacks (which is way too low for several > > usages), and unfortunately there are lots of 32-bit-only smartphones and > > tablets that should probably be supported. > > > > We don't need to worry about scaling on existing phones and tablets. > They have short lifetimes, and most of them don't even receive > security updates. The iPhone 5S is already 64-bit and Android vendors > will move too, especially since they traditionally ship a lot more > memory in even mid-level phones. > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From vadimcn at gmail.com Wed Nov 13 15:29:45 2013 From: vadimcn at gmail.com (Vadim) Date: Wed, 13 Nov 2013 15:29:45 -0800 Subject: [rust-dev] C# async for Rust In-Reply-To: <5284098E.4050302@mozilla.com> References: <5284098E.4050302@mozilla.com> Message-ID: Yes, that. And what about network file systems or removable drives, which were just plugged in? Can't expect all that stuff to be cached. But even for local storage, I doubt that metadata for the entire volume is cached in RAM at all times. On Wed, Nov 13, 2013 at 3:21 PM, David Rajchenbach-Teller < dteller at mozilla.com> wrote: > On Thu Nov 14 00:10:27 2013, Daniel Micay wrote: > >> The only problem is that Linux doesn't really support asynchronously > >> resolving file paths to inodes (aka opening files), but that can be > done on > >> a dedicated thread pool, with the advantage that the threads don't do > >> anything, so they don't have zombie stacks. > > > > The file metadata cache is small enough that there's no point in > > considering it blocking. You might as well considering memory accesses > > blocking at that extreme, because they might require fetching memory > > to the CPU cache. > > Are you sure about that? If my memory serves, you still need to fetch it > from disk in most cases. On platforms in which devices have a mechanical > component, even trivial accesses can end up very expensive in case of > disk thrashing and/or sleeping disk. > > Cheers, > David > > -- > David Rajchenbach-Teller, PhD > Performance Team, Mozilla > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Wed Nov 13 15:56:53 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 18:56:53 -0500 Subject: [rust-dev] C# async for Rust In-Reply-To: <5284098E.4050302@mozilla.com> References: <5284098E.4050302@mozilla.com> Message-ID: On Wed, Nov 13, 2013 at 6:21 PM, David Rajchenbach-Teller wrote: > On Thu Nov 14 00:10:27 2013, Daniel Micay wrote: >>> The only problem is that Linux doesn't really support asynchronously >>> resolving file paths to inodes (aka opening files), but that can be done on >>> a dedicated thread pool, with the advantage that the threads don't do >>> anything, so they don't have zombie stacks. >> >> The file metadata cache is small enough that there's no point in >> considering it blocking. You might as well considering memory accesses >> blocking at that extreme, because they might require fetching memory >> to the CPU cache. > > Are you sure about that? If my memory serves, you still need to fetch it > from disk in most cases. On platforms in which devices have a mechanical > component, even trivial accesses can end up very expensive in case of > disk thrashing and/or sleeping disk. > > Cheers, > David > > -- > David Rajchenbach-Teller, PhD > Performance Team, Mozilla Mechanical disks are already dead in mobile though, and will be dead elsewhere by the time Rust is widely used. It's normal for all of the metadata to remain in cache, but obviously not page cache. Either way, Linux doesn't expose non-blocking file primitives and (fast) AIO is only a dream at this point. The glibc implementation of POSIX AIO uses threads and blocking I/O. From kevin at sb.org Wed Nov 13 16:19:32 2013 From: kevin at sb.org (Kevin Ballard) Date: Wed, 13 Nov 2013 16:19:32 -0800 Subject: [rust-dev] C# async for Rust In-Reply-To: References: <5284098E.4050302@mozilla.com> Message-ID: <08963D5D-E882-4D75-986E-FA6095D260CD@sb.org> On Nov 13, 2013, at 3:56 PM, Daniel Micay wrote: > On Wed, Nov 13, 2013 at 6:21 PM, David Rajchenbach-Teller > wrote: >> On Thu Nov 14 00:10:27 2013, Daniel Micay wrote: >>>> The only problem is that Linux doesn't really support asynchronously >>>> resolving file paths to inodes (aka opening files), but that can be done on >>>> a dedicated thread pool, with the advantage that the threads don't do >>>> anything, so they don't have zombie stacks. >>> >>> The file metadata cache is small enough that there's no point in >>> considering it blocking. You might as well considering memory accesses >>> blocking at that extreme, because they might require fetching memory >>> to the CPU cache. >> >> Are you sure about that? If my memory serves, you still need to fetch it >> from disk in most cases. On platforms in which devices have a mechanical >> component, even trivial accesses can end up very expensive in case of >> disk thrashing and/or sleeping disk. >> >> Cheers, >> David >> >> -- >> David Rajchenbach-Teller, PhD >> Performance Team, Mozilla > > Mechanical disks are already dead in mobile though, and will be dead > elsewhere by the time Rust is widely used. In consumer devices, perhaps. But in large data arrays, probably not so much. Also, don?t forget that there?s more to a filesystem than just local drives. What about network-mounted filesystems? > It's normal for all of the metadata to remain in cache, but obviously not page cache. Either way, > Linux doesn't expose non-blocking file primitives and (fast) AIO is > only a dream at this point. The glibc implementation of POSIX AIO uses > threads and blocking I/O. Does ?all of the metadata? mean everything that stat() returns, or are you talking about a limited subset here? Because if it?s the former, then I?m pretty sure all stat metadata for the filesystem does not necessarily reside in cache at the same time. This should be obvious for anyone who?s used a VCS with a gigantic project, and waited for it to stat() all the files to see if they changed. And this is doubly-true for network filesystems. -Kevin -------------- next part -------------- An HTML attachment was scrubbed... URL: From danielmicay at gmail.com Wed Nov 13 16:33:12 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 19:33:12 -0500 Subject: [rust-dev] C# async for Rust In-Reply-To: <08963D5D-E882-4D75-986E-FA6095D260CD@sb.org> References: <5284098E.4050302@mozilla.com> <08963D5D-E882-4D75-986E-FA6095D260CD@sb.org> Message-ID: The `stat` calls are potentially blocking, so what do you do beyond blocking a thread? Ideally the current thread, to avoid a context switch to and from another core - especially since it will often not block. There's nothing else you can do without a horrible performance reduction in the common case. From danielmicay at gmail.com Wed Nov 13 16:36:57 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Wed, 13 Nov 2013 19:36:57 -0500 Subject: [rust-dev] C# async for Rust In-Reply-To: References: <5284098E.4050302@mozilla.com> <08963D5D-E882-4D75-986E-FA6095D260CD@sb.org> Message-ID: On Wed, Nov 13, 2013 at 7:33 PM, Daniel Micay wrote: > The `stat` calls are potentially blocking, so what do you do beyond > blocking a thread? Ideally the current thread, to avoid a context > switch to and from another core - especially since it will often not > block. There's nothing else you can do without a horrible performance > reduction in the common case. Of course, if it does block, you really have no idea whether `stat` calls elsewhere will block because the drives could be arranged in any fashion, and you don't know what's in the cache. The best you can do is make the calls and have the I/O scheduler plan them out in a reasonable way. If you only make one at a time, it's not going to go nearly as quickly. From alex at crichton.co Wed Nov 13 17:55:54 2013 From: alex at crichton.co (Alex Crichton) Date: Wed, 13 Nov 2013 17:55:54 -0800 Subject: [rust-dev] about Rust and static memory allocation In-Reply-To: References: Message-ID: Right now the compiler will not do anything fancy in terms of changing allocations to static or not, but rust does provide some amount of support for patterns like this. There is a lint mode #[deny(heap_memory)] you can use to statically ensure that there is no heap-allocated memory in your program. Rust also allows you to control how all your local variables are allocated, so the compiler will never magically make an allocation behind the scenes that you aren't aware of. Were those the kinds of static analysis that you were looking for? On Wed, Nov 13, 2013 at 8:35 AM, Nicolas Boulay wrote: > Hello, > > I?m an hardware scientist, working for a software compagny. I had follow > some open cpu design like F-cpu, and the langage design of Lisaac. I?m an > expert in C programming, and have some skills in ocaml, perl, c++, java. > > > In synchrone langage (Lustre/Scade), there is no dynamic memory allocation. > This kind of langage have the data inside function (or ?block?), the > opposite way of object langage with method beside the data. It?s like having > ?static? variable in the C sens, but a different one for each call site. > There is no loops in Lustre, only high order function like map and fold > operation, that duplicate the variable for each call. Having such feature, > reduce the need a dynamic allocation and garbage collector. > > > I think this looks new and strange, but Lustre are used since 10 years in > real time safety critical software. This kind of (static, compile time) > memory allocation could be a great help for long running, fast and > responsive system. I know you target a 1.0 release but this could ease the > write of software without any dynamic memory allocation. > > > Do you think, this could be implemented in rust ? > > > Regards, > > Nicolas Boulay > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > From rusty.gates at icloud.com Wed Nov 13 19:50:05 2013 From: rusty.gates at icloud.com (Tommi) Date: Thu, 14 Nov 2013 05:50:05 +0200 Subject: [rust-dev] Built-in types should accept a pointer rhs-argument to binary operators Message-ID: let mut n = 11; let p: &int = &123; p + n; // OK n + p; // error: mismatched types: expected `int` but found `&int` Shouldn't this error be considered a compiler-bug? The Add trait says '&' for rhs after all: fn add(&self, rhs: &RHS) -> Result; -Tommi From dbau.pp at gmail.com Wed Nov 13 19:54:44 2013 From: dbau.pp at gmail.com (Huon Wilson) Date: Thu, 14 Nov 2013 14:54:44 +1100 Subject: [rust-dev] Built-in types should accept a pointer rhs-argument to binary operators In-Reply-To: References: Message-ID: <52844984.1040401@gmail.com> On 14/11/13 14:50, Tommi wrote: > let mut n = 11; > let p: &int = &123; > > p + n; // OK > n + p; // error: mismatched types: expected `int` but found `&int` > > Shouldn't this error be considered a compiler-bug? The Add trait says '&' for rhs after all: > fn add(&self, rhs: &RHS) -> Result; > > -Tommi > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev This is https://github.com/mozilla/rust/issues/8895 . I believe it is caused by the implementation details of the overloaded-operator desugaring (a + b is equivalent to `a.add(&b)`, so auto-deref allows for `a: &T` with `b: T`), I personally think the more sensible resolution would be for `p + n` to be disallowed as well as `n + p`. Huon From rusty.gates at icloud.com Wed Nov 13 20:20:46 2013 From: rusty.gates at icloud.com (Tommi) Date: Thu, 14 Nov 2013 06:20:46 +0200 Subject: [rust-dev] Built-in types should accept a pointer rhs-argument to binary operators In-Reply-To: <52844984.1040401@gmail.com> References: <52844984.1040401@gmail.com> Message-ID: <8EBDE92C-6F12-48BB-A230-79F4FFA220A5@icloud.com> On 2013-11-14, at 5:54, Huon Wilson wrote: > On 14/11/13 14:50, Tommi wrote: >> let mut n = 11; >> let p: &int = &123; >> >> p + n; // OK >> n + p; // error: mismatched types: expected `int` but found `&int` >> >> Shouldn't this error be considered a compiler-bug? The Add trait says '&' for rhs after all: >> fn add(&self, rhs: &RHS) -> Result; >> >> -Tommi >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > > This is https://github.com/mozilla/rust/issues/8895 . I believe it is caused by the implementation details of the overloaded-operator desugaring (a + b is equivalent to `a.add(&b)`, so auto-deref allows for `a: &T` with `b: T`), I personally think the more sensible resolution would be for `p + n` to be disallowed as well as `n + p`. > > Huon > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev Thanks, I tried to search for a bug report for this but didn't manage to find that one. To me it makes perfect sense that p + n would work because if a + b is specified to be "just" syntactic sugar for a.add(b), then a + b should behave exactly like a.add(b), with implicit pointer dereferencing and all that good stuff. But, I don't understand why is it a.add(&b) like you said, though. By the way, I would hate all of this behavior if Rust had pointer arithmetic, but luckily it doesn't seem to have it. -Tommi From rusty.gates at icloud.com Wed Nov 13 21:00:09 2013 From: rusty.gates at icloud.com (Tommi) Date: Thu, 14 Nov 2013 07:00:09 +0200 Subject: [rust-dev] Built-in types should accept a pointer rhs-argument to binary operators In-Reply-To: <8EBDE92C-6F12-48BB-A230-79F4FFA220A5@icloud.com> References: <52844984.1040401@gmail.com> <8EBDE92C-6F12-48BB-A230-79F4FFA220A5@icloud.com> Message-ID: On 2013-11-14, at 6:20, Tommi wrote: > On 2013-11-14, at 5:54, Huon Wilson wrote: > >> On 14/11/13 14:50, Tommi wrote: >>> let mut n = 11; >>> let p: &int = &123; >>> >>> p + n; // OK >>> n + p; // error: mismatched types: expected `int` but found `&int` >>> >>> Shouldn't this error be considered a compiler-bug? The Add trait says '&' for rhs after all: >>> fn add(&self, rhs: &RHS) -> Result; >>> >>> -Tommi >>> >>> _______________________________________________ >>> Rust-dev mailing list >>> Rust-dev at mozilla.org >>> https://mail.mozilla.org/listinfo/rust-dev >> >> This is https://github.com/mozilla/rust/issues/8895 . I believe it is caused by the implementation details of the overloaded-operator desugaring (a + b is equivalent to `a.add(&b)`, so auto-deref allows for `a: &T` with `b: T`), I personally think the more sensible resolution would be for `p + n` to be disallowed as well as `n + p`. >> >> Huon >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > > > Thanks, I tried to search for a bug report for this but didn't manage to find that one. To me it makes perfect sense that p + n would work because if a + b is specified to be "just" syntactic sugar for a.add(b), then a + b should behave exactly like a.add(b), with implicit pointer dereferencing and all that good stuff. But, I don't understand why is it a.add(&b) like you said, though. > > By the way, I would hate all of this behavior if Rust had pointer arithmetic, but luckily it doesn't seem to have it. > > -Tommi > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev You're right in that it's not a bug in built-in types, but affects user-defined types also. But n.add(p) works just fine, while n.add(&p) doesn't: struct Num { n: int } impl Add for Num { fn add(&self, other: &Num) -> Num { Num { n: self.n + other.n } } } fn main() { let n = 11i; let p = &22i; p + n; // OK n + p; // error: mismatched types: expected `int` but found `&int` n.add(p); // OK n.add(&p); // error: mismatched types: expected `&int` but found `&&int` let n = Num { n: 11 }; let p = &Num { n: 22 }; p + n; // OK n + p; // error: mismatched types: expected `Num` but found `&Num` n.add(p); // OK n.add(&p); // error: mismatched types: expected `&Num` but found `&&Num` } -Tommi From dbau.pp at gmail.com Wed Nov 13 21:12:31 2013 From: dbau.pp at gmail.com (Huon Wilson) Date: Thu, 14 Nov 2013 16:12:31 +1100 Subject: [rust-dev] Built-in types should accept a pointer rhs-argument to binary operators In-Reply-To: References: <52844984.1040401@gmail.com> <8EBDE92C-6F12-48BB-A230-79F4FFA220A5@icloud.com> Message-ID: <52845BBF.70509@gmail.com> On 14/11/13 16:00, Tommi wrote: > On 2013-11-14, at 6:20, Tommi wrote: > >> On 2013-11-14, at 5:54, Huon Wilson wrote: >> >>> On 14/11/13 14:50, Tommi wrote: >>>> let mut n = 11; >>>> let p: &int = &123; >>>> >>>> p + n; // OK >>>> n + p; // error: mismatched types: expected `int` but found `&int` >>>> >>>> Shouldn't this error be considered a compiler-bug? The Add trait says '&' for rhs after all: >>>> fn add(&self, rhs: &RHS) -> Result; >>>> >>>> -Tommi >>>> >>>> _______________________________________________ >>>> Rust-dev mailing list >>>> Rust-dev at mozilla.org >>>> https://mail.mozilla.org/listinfo/rust-dev >>> This is https://github.com/mozilla/rust/issues/8895 . I believe it is caused by the implementation details of the overloaded-operator desugaring (a + b is equivalent to `a.add(&b)`, so auto-deref allows for `a: &T` with `b: T`), I personally think the more sensible resolution would be for `p + n` to be disallowed as well as `n + p`. >>> >>> Huon >>> _______________________________________________ >>> Rust-dev mailing list >>> Rust-dev at mozilla.org >>> https://mail.mozilla.org/listinfo/rust-dev >> >> Thanks, I tried to search for a bug report for this but didn't manage to find that one. To me it makes perfect sense that p + n would work because if a + b is specified to be "just" syntactic sugar for a.add(b), then a + b should behave exactly like a.add(b), with implicit pointer dereferencing and all that good stuff. But, I don't understand why is it a.add(&b) like you said, though. >> >> By the way, I would hate all of this behavior if Rust had pointer arithmetic, but luckily it doesn't seem to have it. >> >> -Tommi >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > > You're right in that it's not a bug in built-in types, but affects user-defined types also. But n.add(p) works just fine, while n.add(&p) doesn't: > > struct Num { n: int } > > impl Add for Num { > fn add(&self, other: &Num) -> Num { Num { n: self.n + other.n } } > } > > fn main() { > let n = 11i; > let p = &22i; > > p + n; // OK > n + p; // error: mismatched types: expected `int` but found `&int` > n.add(p); // OK > n.add(&p); // error: mismatched types: expected `&int` but found `&&int` > > let n = Num { n: 11 }; > let p = &Num { n: 22 }; > > p + n; // OK > n + p; // error: mismatched types: expected `Num` but found `&Num` > n.add(p); // OK > n.add(&p); // error: mismatched types: expected `&Num` but found `&&Num` > } > > -Tommi p has type &Num, which matches the type signature of add for Num, so it is expected that it compiles. And, &p has type & &Num, which doesn't match the signature of add for Num and so correspondingly doesn't compile. Similarly, for the + sugar, `n + p` and `n.add(&p)` (with the extra &) are the same (despite the error messages having one fewer layers of &). The operator traits all take references because they (in the common case) don't want ownership of their arguments. If they didn't take references (i.e. `fn add(self, other: Num) -> Num`) then something like bigint_1.add(&bigint_2) // bigint_1 + bigint_2 would likely require bigint_1.clone().add(bigint_2.clone()) // bigint_1.clone() + bigint_2.clone() if one wanted to reuse the values in bigint_1 and bigint_2 later. The current definitions of the traits means that the operator desugaring needs to implicitly add the references (that is a + b -> a.add(&b), rather than a.add(b)`) to match the type signature, or else we'd be forced to write `x + &1` everywhere. (Just to be clear the auto-deref only happens on the "self" value, i.e. the value on which you are calling the method, not any arguments.) Huon From spam at scientician.net Wed Nov 13 21:23:42 2013 From: spam at scientician.net (Bardur Arantsson) Date: Thu, 14 Nov 2013 06:23:42 +0100 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: On 2013-11-13 21:41, Igor Bukanov wrote: > On 13 November 2013 20:41, Bardur Arantsson wrote: > >> In practice it's much more difficult to be *explicitly* >> async and it should just be delegated to the language/runtime. There are >> some things humans just aren't good at. > > I suspect Rust makes asynchronous programming significantly more > bearable. Programming in JS in that style is often painful due to the > noise of all those function() { } spread through the code and bugs > connected with accessing stuff that should only be ready later. Rust > nicely addresses that with shorter syntax for closures/macros and move > semantics. > > So an experiment of writing in asynchronous style in Rust and > comparing that with C++/JS/other languages would be very useful to > judge. > It's *not* a matter of just making the syntax "lighter". Asynchronous callbacks lead to "the pyramid of doom" (as Dave Herman puts it) of nested callback functions. Unfortunately, instead of actually fixing the underlying problem (which is the need for an explicit callback model in the first place), the ECMAScript committee seems to have gone with function foo*(...) { yield ....; } which is lighter syntax but still absurd. (To bear fair they also have extreme constraints of backward compatibility.) Python has also (to my great disappointment) gone this route, but there you can't even tell "from the outside" if a function is async-safe -- it's not part of its interface syntactically, but it's of huge importance in practice. My overall point is: Why should the *programmer* be segregating functions into asynchronous and synchronous? We have computers and compilers which are more than capable than doing this for us at this point! Regards, From rusty.gates at icloud.com Wed Nov 13 21:35:06 2013 From: rusty.gates at icloud.com (Tommi) Date: Thu, 14 Nov 2013 07:35:06 +0200 Subject: [rust-dev] Built-in types should accept a pointer rhs-argument to binary operators In-Reply-To: <52845BBF.70509@gmail.com> References: <52844984.1040401@gmail.com> <8EBDE92C-6F12-48BB-A230-79F4FFA220A5@icloud.com> <52845BBF.70509@gmail.com> Message-ID: <9D2409F0-4634-479C-91A9-EA856C4DA296@icloud.com> On 2013-11-14, at 7:12, Huon Wilson wrote: > On 14/11/13 16:00, Tommi wrote: >> On 2013-11-14, at 6:20, Tommi wrote: >> >> You're right in that it's not a bug in built-in types, but affects user-defined types also. But n.add(p) works just fine, while n.add(&p) doesn't: >> >> struct Num { n: int } >> >> impl Add for Num { >> fn add(&self, other: &Num) -> Num { Num { n: self.n + other.n } } >> } >> >> fn main() { >> let n = 11i; >> let p = &22i; >> >> p + n; // OK >> n + p; // error: mismatched types: expected `int` but found `&int` >> n.add(p); // OK >> n.add(&p); // error: mismatched types: expected `&int` but found `&&int` >> >> let n = Num { n: 11 }; >> let p = &Num { n: 22 }; >> >> p + n; // OK >> n + p; // error: mismatched types: expected `Num` but found `&Num` >> n.add(p); // OK >> n.add(&p); // error: mismatched types: expected `&Num` but found `&&Num` >> } >> >> -Tommi > > p has type &Num, which matches the type signature of add for Num, so it is expected that it compiles. And, &p has type & &Num, which doesn't match the signature of add for Num and so correspondingly doesn't compile. Similarly, for the + sugar, `n + p` and `n.add(&p)` (with the extra &) are the same (despite the error messages having one fewer layers of &). Right, I actually had failed to realize that those two different error messages are effectively the same. > The current definitions of the traits means that the operator desugaring needs to implicitly add the references (that is a + b -> a.add(&b), rather than a.add(b)`) to match the type signature, or else we'd be forced to write `x + &1` everywhere. I think this is what the operator de-sugaring should do: If b is lvalue: a + b -> a.add(b) and... If b is rvalue: a + b -> a.add(&b) -Tommi From spam at scientician.net Wed Nov 13 21:36:47 2013 From: spam at scientician.net (Bardur Arantsson) Date: Thu, 14 Nov 2013 06:36:47 +0100 Subject: [rust-dev] C# async for Rust In-Reply-To: References: Message-ID: On 2013-11-13 23:15, Daniel Micay wrote: > The issue with async/await is that while it maps very well to the AIO > primitives like IOCP and POSIX AIO, it doesn't map well to something > that's solid on Linux. Then help fix Linux. (Yes, I'm serious.) > It's just not how I/O is done on the platform. > It uses *non-blocking* I/O so scale up socket servers, with > notification of ready state rather than completion state. This doesn't > work for file system access though. > > There's a significant performance hit from moving maybe-blocking I/O > calls into thread pools to fit a square peg into a round hole. > And your proposed solution for this is to force *everything* into a round hole? You'd essentially be forcing every single socket server-type application to implement their *own* thread pool mechanism. Which (assuming Windows IOCPs work well) would be suboptimal on Windows and an extra interoperability concern when sharing code which lives atop a "socket server". The JVM world is actually doing this experiment and it has led to a huge mess of non-interoperable and non-composable code. I would urge anyone to *not* follow the same route. Regards, From danielmicay at gmail.com Wed Nov 13 21:42:13 2013 From: danielmicay at gmail.com (Daniel Micay) Date: Thu, 14 Nov 2013 00:42:13 -0500 Subject: [rust-dev] C# async for Rust In-Reply-To: References: Message-ID: On Thu, Nov 14, 2013 at 12:36 AM, Bardur Arantsson wrote: > On 2013-11-13 23:15, Daniel Micay wrote: >> The issue with async/await is that while it maps very well to the AIO >> primitives like IOCP and POSIX AIO, it doesn't map well to something >> that's solid on Linux. > > Then help fix Linux. (Yes, I'm serious.) > >> It's just not how I/O is done on the platform. >> It uses *non-blocking* I/O so scale up socket servers, with >> notification of ready state rather than completion state. This doesn't >> work for file system access though. >> >> There's a significant performance hit from moving maybe-blocking I/O >> calls into thread pools to fit a square peg into a round hole. >> > > And your proposed solution for this is to force *everything* into a > round hole? > > You'd essentially be forcing every single socket server-type application > to implement their *own* thread pool mechanism. Which (assuming Windows > IOCPs work well) would be suboptimal on Windows and an extra > interoperability concern when sharing code which lives atop a "socket > server". > > The JVM world is actually doing this experiment and it has led to a huge > mess of non-interoperable and non-composable code. I would urge anyone > to *not* follow the same route. > > Regards, I suggest reading the content I posted to the list then, going into depth about the drawbacks of the current system and how user-mode 1:1 scheduling maintains the same advantages without many of the disadvantages. There's a link to the Microsoft documentation on the implementation (replacing Windows fibers) we could be using right now. It's not entirely necessary to have it on Linux because threads scale well, but it would be nice. From banderson at mozilla.com Wed Nov 13 21:50:14 2013 From: banderson at mozilla.com (Brian Anderson) Date: Wed, 13 Nov 2013 21:50:14 -0800 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: <52846496.2060508@mozilla.com> Thanks for the great reply, Alex. This is the approach we are going to take. Rust is not going to move away from green threads; the plan is to support both use cases in the standard library. On 11/13/2013 10:32 AM, Alex Crichton wrote: > The situation may not be as dire as you think. The runtime is still in a state > of flux, and don't forget that in one summer the entire runtime was rewritten in > rust and was entirely redesigned. I personally still think that M:N is a viable > model for various applications, and it seems especially unfortunate to just > remove everything because it's not tailored for all use cases. > > Rust made an explicit design decision early on to pursue lightweight/green > tasks, and it was made with the understanding that there were drawbacks to the > strategy. Using libuv as a backend for driving I/O was also an explicit decision > with known drawbacks. > > That being said, I do not believe that all is lost. I don't believe that the > rust standard library as-is today can support *every* use case, but it's getting > to a point where it can get pretty close. In the recent redesign of the I/O > implementation, all I/O was abstracted behind trait objects that are synchronous > in their interface. This I/O interface is all implemented in librustuv by > talking to the rust scheduler under the hood. Additionally, in pull #10457, I'm > starting to add support for a native implementation of this I/O interface. The > great boon of this strategy is that all std::io primitives have no idea if their > underlying interface is native and blocking or libuv and asynchronous. The exact > same rust code works for one as it does for the other. > > I personally don't see why the same strategy shouldn't work for the task model > as well. When you link a program to the librustuv crate, then you're choosing to > have a runtime with M:N scheduling and asynchronous I/O. Perhaps, though, if you > didn't link to librustuv, you would get 1:1 scheduling with blocking I/O. You > would still have all the benefits of the standard library's communication > primitives, spawning primitives, I/O, task-local-storage etc. The only > difference is that everything would be powered by OS-level threads instead of > rust-level green tasks. > > I would very much like to see a standard library which supports this > abstraction, and I believe that it is very realistically possible. Right now we > have an EventLoop interface which defines interacting with I/O that is the > abstraction between asynchronous I/O and blocking I/O. This sounds like > we need a more formalized Scheduler interface which abstracts M:N scheduling vs > 1:1 scheduling. > > The main goal of all of this would be to allow the same exact rust code to work > in both M:N and 1:1 environments. This ability would allow authors to specialize > their code for their task at-hand. Those writing web servers would be sure to > link to librustuv, but those writing command-line utilities would simply just > omit librustuv. Additionally, as a library author, I don't really care which > implementation you're using. I can write a mysql database driver and then you as > a consumer of my library decided whether my network calls are blocking or not. > > This is a fairly new concept to me (I haven't thought much about it before), but > this sounds like it may be the right way forward to addressing your concerns > without compromising too much existing functionality. There would certainly be > plenty of work to do in this realm, and I'm not sure if this goal would block > the 1.0 milestone or not. Ideally, this would be a completely > backwards-compatible change, but there would perhaps be unintended consequences. > As always, this would need plenty of discussion to see whether this is even a > reasonable strategy to take. > > > On Wed, Nov 13, 2013 at 2:45 AM, Daniel Micay wrote: >> Before getting right into the gritty details about why I think we should think >> about a path away from M:N scheduling, I'll go over the details of the >> concurrency model we currently use. >> >> Rust uses a user-mode scheduler to cooperatively schedule many tasks onto OS >> threads. Due to the lack of preemption, tasks need to manually yield control >> back to the scheduler. Performing I/O with the standard library will block the >> *task*, but yield control back to the scheduler until the I/O is completed. >> >> The scheduler manages a thread pool where the unit of work is a task rather >> than a queue of closures to be executed or data to be pass to a function. A >> task consists of a stack, register context and task-local storage much like an >> OS thread. >> >> In the world of high-performance computing, this is a proven model for >> maximizing throughput for CPU-bound tasks. By abandoning preemption, there's >> zero overhead from context switches. For socket servers with only negligible >> server-side computations the avoidance of context switching is a boon for >> scalability and predictable performance. >> >> # Lightweight? >> >> Rust's tasks are often called *lightweight* but at least on Linux the only >> optimization is the lack of preemption. Since segmented stacks have been >> dropped, the resident/virtual memory usage will be identical. >> >> # Spawning performance >> >> An OS thread can actually spawn nearly as fast as a Rust task on a system with >> one CPU. On a multi-core system, there's a high chance of the new thread being >> spawned on a different CPU resulting in a performance loss. >> >> Sample C program, if you need to see it to believe it: >> >> ``` >> #include >> #include >> >> static const size_t n_thread = 100000; >> >> static void *foo(void *arg) { >> return arg; >> } >> >> int main(void) { >> for (size_t i = 0; i < n_thread; i++) { >> pthread_attr_t attr; >> if (pthread_attr_init(&attr) < 0) { >> return 1; >> } >> if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) < 0) { >> return 1; >> } >> pthread_t thread; >> if (pthread_create(&thread, &attr, foo, NULL) < 0) { >> return 1; >> } >> } >> pthread_exit(NULL); >> } >> ``` >> >> Sample Rust program: >> >> ``` >> fn main() { >> for _ in range(0, 100000) { >> do spawn { >> } >> } >> } >> ``` >> >> For both programs, I get around 0.9s consistently when pinned to a core. The >> Rust version drops to 1.1s when not pinned and the OS thread one to about 2s. >> It drops further when asked to allocate 8MiB stacks like C is doing, and will >> drop more when it has to do `mmap` and `mprotect` calls like the pthread API. >> >> # Asynchronous I/O >> >> Rust's requirements for asynchronous I/O would be filled well by direct usage >> of IOCP on Windows. However, Linux only has solid support for non-blocking >> sockets because file operations usually just retrieve a result from cache and >> do not truly have to block. This results in libuv being significantly slower >> than blocking I/O for most common cases for the sake of scalable socket >> servers. >> >> On modern systems with flash memory, including mobile, there is a *consistent* >> and relatively small worst-case latency for accessing data on the disk so >> blocking is essentially a non-issue. Memory mapped I/O is also an incredibly >> important feature for I/O performance, and there's almost no reason to use >> traditional I/O on 64-bit. However, it's a no-go with M:N scheduling because >> the page faults block the thread. >> >> # Overview >> >> Advantages: >> >> * lack of preemptive/fair scheduling, leading to higher throughput >> * very fast context switches to other tasks on the same scheduler thread >> >> Disadvantages: >> >> * lack of preemptive/fair scheduling (lower-level model) >> * poor profiler/debugger support >> * async I/O stack is much slower for the common case; for example stat is 35x >> slower when run in a loop for an mlocate-like utility >> * true blocking code will still block a scheduler thread >> * most existing libraries use blocking I/O and OS threads >> * cannot directly use fast and easy to use linker-supported thread-local data >> * many existing libraries rely on thread-local storage, so there's a need to be >> wary of hidden yields in Rust function calls and it's very difficult to >> expose a safe interface to these libraries >> * every level of a CPU architecture adding registers needs explicit support >> from Rust, and it must be selected at runtime when not targeting a specific >> CPU (this is currently not done correctly) >> >> # User-mode scheduling >> >> Windows 7 introduced user-mode scheduling[1] to replace fibers on 64-bit. >> Google implemented the same thing for Linux (perhaps even before Windows 7 was >> released), and plans on pushing for it upstream.[2] The linked video does a >> better job of covering this than I can. >> >> User-mode scheduling provides a 1:1 threading model including full support for >> normal thread-local data and existing debuggers/profilers. It can yield to the >> scheduler on system calls and page faults. The operating system is responsible >> for details like context switching, so a large maintenance/portability burden >> is dealt with. It narrows down the above disadvantage list to just the point >> about not having preemptive/fair scheduling and doesn't introduce any new ones. >> >> I hope this is where concurrency is headed, and I hope Rust doesn't miss this >> boat by concentrating too much on libuv. I think it would allow us to simply >> drop support for pseudo-blocking I/O in the Go style and ignore asynchronous >> I/O and non-blocking sockets in the standard library. It may be useful to have >> the scheduler use them, but it wouldn't be essential. >> >> [1] http://msdn.microsoft.com/en-us/library/windows/desktop/dd627187(v=vs.85).aspx >> [2] http://www.youtube.com/watch?v=KXuZi9aeGTw >> _______________________________________________ >> 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 From rossberg at mpi-sws.org Wed Nov 13 23:05:41 2013 From: rossberg at mpi-sws.org (Andreas Rossberg) Date: Thu, 14 Nov 2013 08:05:41 +0100 Subject: [rust-dev] typing in rust In-Reply-To: References: Message-ID: <6EB1D754-96CD-4703-B0DD-31686BE95ED9@mpi-sws.org> On Nov 13, 2013, at 21:37 , Martin DeMello wrote: > What ML does differently is having the syntax of let bindings > explicitly introduce a new scope by being terminated with 'in' - e.g. > you'd say > > let test = test () in > println (format! ("{}", test)); In OCaml, not so in Standard ML: let fun m() = ?Hello" val m = m() ^ ? world" in print m end And even in OCaml you can do it in other contexts: module M = struct let m() = ?Hello? let m = m() ^ ? world end /Andreas > On Wed, Nov 13, 2013 at 10:13 AM, Brendan Zabarauskas > wrote: >> SML also shares these semantics when it comes to bindings. That is, a subsequent binding to the same identifier can ?mask? those that proceed it, even if they are in the same scope and the bound values are of different types. Once a value has had its identifier masked, it can no longer be accessed. >> >> I assume this behaviour was passed on to Ocaml, and Rust inherited it from there. Rust was originally written in Ocaml, and has drawn many influences from there. I personally find it useful from time to time. >> >> ~Brendan >> >> On 14 Nov 2013, at 3:25 am, Joshua Rodgers wrote: >> >>> I'm curious as to why this is valid, though? This makes sense if you're inside a new or nested scope, but why is it valid inside the same scope as illustrated in the code example? >>> >>> I can understand it from the perspective that I need to mask a function name (but that's a nested scope to me, at that point). >>> >>> >>> On Wed, Nov 13, 2013 at 8:54 AM, Scott Lawrence wrote: >>> I would think that `test()` (the function) is in scope for the duration of `let test =`, and then the new definition masks the old one. Similarly, >>> >>> let x = 2; >>> let x = x + 2; >>> >>> If you change the last line to /call/ test(), you should get an error. >>> >>> >>> On Wed, 13 Nov 2013, Philip Herron wrote: >>> >>> Hey all >>> >>> I am still learning but i just tried something which i expected to give an >>> error but works: >>> >>> fn test () -> int { >>> 1 >>> } >>> >>> fn main () { >>> let test = test (); >>> println (format! ("{}", test)); >>> } >>> >>> I guess on compilation the names are mangled against their types or >>> something so you can differentiate between test the function and test the >>> variable. Not sure would be nice to get some clarification what this >>> behavior is. >>> >>> Thanks >>> >>> --Phil >>> >>> >>> -- >>> Scott Lawrence >>> _______________________________________________ >>> 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 >> >> _______________________________________________ >> 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 From marijnh at gmail.com Thu Nov 14 01:00:54 2013 From: marijnh at gmail.com (Marijn Haverbeke) Date: Thu, 14 Nov 2013 10:00:54 +0100 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: > Unfortunately, instead of actually fixing the underlying problem [?] the ECMAScript committee seems to have gone with [?] which is lighter syntax but still absurd. Flaming other languages / committees is very much not the point of this mailing list. Try to stay on topic and dispassionate. On Thu, Nov 14, 2013 at 6:23 AM, Bardur Arantsson wrote: > On 2013-11-13 21:41, Igor Bukanov wrote: >> On 13 November 2013 20:41, Bardur Arantsson wrote: >> >>> In practice it's much more difficult to be *explicitly* >>> async and it should just be delegated to the language/runtime. There are >>> some things humans just aren't good at. >> >> I suspect Rust makes asynchronous programming significantly more >> bearable. Programming in JS in that style is often painful due to the >> noise of all those function() { } spread through the code and bugs >> connected with accessing stuff that should only be ready later. Rust >> nicely addresses that with shorter syntax for closures/macros and move >> semantics. >> >> So an experiment of writing in asynchronous style in Rust and >> comparing that with C++/JS/other languages would be very useful to >> judge. >> > > It's *not* a matter of just making the syntax "lighter". Asynchronous > callbacks lead to "the pyramid of doom" (as Dave Herman puts it) of > nested callback functions. > > Unfortunately, instead of actually fixing the underlying problem (which > is the need for an explicit callback model in the first place), the > ECMAScript committee seems to have gone with > > function foo*(...) { > yield ....; > } > > which is lighter syntax but still absurd. (To bear fair they also have > extreme constraints of backward compatibility.) > > Python has also (to my great disappointment) gone this route, but there > you can't even tell "from the outside" if a function is async-safe -- > it's not part of its interface syntactically, but it's of huge > importance in practice. > > My overall point is: Why should the *programmer* be segregating > functions into asynchronous and synchronous? We have computers and > compilers which are more than capable than doing this for us at this point! > > Regards, > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From spam at scientician.net Thu Nov 14 01:24:57 2013 From: spam at scientician.net (Bardur Arantsson) Date: Thu, 14 Nov 2013 10:24:57 +0100 Subject: [rust-dev] The future of M:N threading In-Reply-To: References: Message-ID: On 2013-11-14 10:00, Marijn Haverbeke wrote: >> Unfortunately, instead of actually fixing the underlying problem [?] the ECMAScript committee seems to have gone with [?] which is lighter syntax but still absurd. > > Flaming other languages / committees is very much not the point of > this mailing list. Try to stay on topic and dispassionate. Apologies. (However, I think you might also have quoted the very next sentence which explains that I understand that they were working under different constraints.) Regards, From igor at mir2.org Thu Nov 14 02:27:58 2013 From: igor at mir2.org (Igor Bukanov) Date: Thu, 14 Nov 2013 11:27:58 +0100 Subject: [rust-dev] C# async for Rust In-Reply-To: References: Message-ID: On 14 November 2013 06:42, Daniel Micay wrote: > There's a link to the Microsoft documentation on the > implementation (replacing Windows fibers) we could be using right now. > It's not entirely necessary to have it on Linux because threads scale > well, but it would be nice. It is exactly Microsoft that added async keywords to C#. So they know that UMS does not cover all their needs. Plus various Linux servers with long-term support (32 bit RedHat 5 is alive and kicking...) make sure that the need for scalable IO without UMS will exist for a long time even if UMS will be available with the latest kernels. It also interesting that both MS documentation and that Google video talk emphases on compatibility with existing applications and tools and I doubt that one can both compatibility and optimal performance. From thadguidry at gmail.com Thu Nov 14 07:01:28 2013 From: thadguidry at gmail.com (Thad Guidry) Date: Thu, 14 Nov 2013 09:01:28 -0600 Subject: [rust-dev] The future of M:N threading In-Reply-To: <52846496.2060508@mozilla.com> References: <52846496.2060508@mozilla.com> Message-ID: Great ! Glad to hear that the plan is to support both use cases by abstracting M:N and 1:1 eventually. That will go a long way towards my later experiments with ETL (extract, transform, load) under various OS's and multi-core architectures using parallel task flow (I still don't know what I will call the flow type...lolol) On Wed, Nov 13, 2013 at 11:50 PM, Brian Anderson wrote: > Thanks for the great reply, Alex. This is the approach we are going to > take. Rust is not going to move away from green threads; the plan is to > support both use cases in the standard library. > > > On 11/13/2013 10:32 AM, Alex Crichton wrote: > >> The situation may not be as dire as you think. The runtime is still in a >> state >> of flux, and don't forget that in one summer the entire runtime was >> rewritten in >> rust and was entirely redesigned. I personally still think that M:N is a >> viable >> model for various applications, and it seems especially unfortunate to >> just >> remove everything because it's not tailored for all use cases. >> >> Rust made an explicit design decision early on to pursue lightweight/green >> tasks, and it was made with the understanding that there were drawbacks >> to the >> strategy. Using libuv as a backend for driving I/O was also an explicit >> decision >> with known drawbacks. >> >> That being said, I do not believe that all is lost. I don't believe that >> the >> rust standard library as-is today can support *every* use case, but it's >> getting >> to a point where it can get pretty close. In the recent redesign of the >> I/O >> implementation, all I/O was abstracted behind trait objects that are >> synchronous >> in their interface. This I/O interface is all implemented in librustuv by >> talking to the rust scheduler under the hood. Additionally, in pull >> #10457, I'm >> starting to add support for a native implementation of this I/O >> interface. The >> great boon of this strategy is that all std::io primitives have no idea >> if their >> underlying interface is native and blocking or libuv and asynchronous. >> The exact >> same rust code works for one as it does for the other. >> >> I personally don't see why the same strategy shouldn't work for the task >> model >> as well. When you link a program to the librustuv crate, then you're >> choosing to >> have a runtime with M:N scheduling and asynchronous I/O. Perhaps, though, >> if you >> didn't link to librustuv, you would get 1:1 scheduling with blocking I/O. >> You >> would still have all the benefits of the standard library's communication >> primitives, spawning primitives, I/O, task-local-storage etc. The only >> difference is that everything would be powered by OS-level threads >> instead of >> rust-level green tasks. >> >> I would very much like to see a standard library which supports this >> abstraction, and I believe that it is very realistically possible. Right >> now we >> have an EventLoop interface which defines interacting with I/O that is the >> abstraction between asynchronous I/O and blocking I/O. This sounds like >> we need a more formalized Scheduler interface which abstracts M:N >> scheduling vs >> 1:1 scheduling. >> >> The main goal of all of this would be to allow the same exact rust code >> to work >> in both M:N and 1:1 environments. This ability would allow authors to >> specialize >> their code for their task at-hand. Those writing web servers would be >> sure to >> link to librustuv, but those writing command-line utilities would simply >> just >> omit librustuv. Additionally, as a library author, I don't really care >> which >> implementation you're using. I can write a mysql database driver and then >> you as >> a consumer of my library decided whether my network calls are blocking or >> not. >> >> This is a fairly new concept to me (I haven't thought much about it >> before), but >> this sounds like it may be the right way forward to addressing your >> concerns >> without compromising too much existing functionality. There would >> certainly be >> plenty of work to do in this realm, and I'm not sure if this goal would >> block >> the 1.0 milestone or not. Ideally, this would be a completely >> backwards-compatible change, but there would perhaps be unintended >> consequences. >> As always, this would need plenty of discussion to see whether this is >> even a >> reasonable strategy to take. >> >> >> On Wed, Nov 13, 2013 at 2:45 AM, Daniel Micay >> wrote: >> >>> Before getting right into the gritty details about why I think we should >>> think >>> about a path away from M:N scheduling, I'll go over the details of the >>> concurrency model we currently use. >>> >>> Rust uses a user-mode scheduler to cooperatively schedule many tasks >>> onto OS >>> threads. Due to the lack of preemption, tasks need to manually yield >>> control >>> back to the scheduler. Performing I/O with the standard library will >>> block the >>> *task*, but yield control back to the scheduler until the I/O is >>> completed. >>> >>> The scheduler manages a thread pool where the unit of work is a task >>> rather >>> than a queue of closures to be executed or data to be pass to a >>> function. A >>> task consists of a stack, register context and task-local storage much >>> like an >>> OS thread. >>> >>> In the world of high-performance computing, this is a proven model for >>> maximizing throughput for CPU-bound tasks. By abandoning preemption, >>> there's >>> zero overhead from context switches. For socket servers with only >>> negligible >>> server-side computations the avoidance of context switching is a boon for >>> scalability and predictable performance. >>> >>> # Lightweight? >>> >>> Rust's tasks are often called *lightweight* but at least on Linux the >>> only >>> optimization is the lack of preemption. Since segmented stacks have been >>> dropped, the resident/virtual memory usage will be identical. >>> >>> # Spawning performance >>> >>> An OS thread can actually spawn nearly as fast as a Rust task on a >>> system with >>> one CPU. On a multi-core system, there's a high chance of the new thread >>> being >>> spawned on a different CPU resulting in a performance loss. >>> >>> Sample C program, if you need to see it to believe it: >>> >>> ``` >>> #include >>> #include >>> >>> static const size_t n_thread = 100000; >>> >>> static void *foo(void *arg) { >>> return arg; >>> } >>> >>> int main(void) { >>> for (size_t i = 0; i < n_thread; i++) { >>> pthread_attr_t attr; >>> if (pthread_attr_init(&attr) < 0) { >>> return 1; >>> } >>> if (pthread_attr_setdetachstate(&attr, >>> PTHREAD_CREATE_DETACHED) < 0) { >>> return 1; >>> } >>> pthread_t thread; >>> if (pthread_create(&thread, &attr, foo, NULL) < 0) { >>> return 1; >>> } >>> } >>> pthread_exit(NULL); >>> } >>> ``` >>> >>> Sample Rust program: >>> >>> ``` >>> fn main() { >>> for _ in range(0, 100000) { >>> do spawn { >>> } >>> } >>> } >>> ``` >>> >>> For both programs, I get around 0.9s consistently when pinned to a core. >>> The >>> Rust version drops to 1.1s when not pinned and the OS thread one to >>> about 2s. >>> It drops further when asked to allocate 8MiB stacks like C is doing, and >>> will >>> drop more when it has to do `mmap` and `mprotect` calls like the pthread >>> API. >>> >>> # Asynchronous I/O >>> >>> Rust's requirements for asynchronous I/O would be filled well by direct >>> usage >>> of IOCP on Windows. However, Linux only has solid support for >>> non-blocking >>> sockets because file operations usually just retrieve a result from >>> cache and >>> do not truly have to block. This results in libuv being significantly >>> slower >>> than blocking I/O for most common cases for the sake of scalable socket >>> servers. >>> >>> On modern systems with flash memory, including mobile, there is a >>> *consistent* >>> and relatively small worst-case latency for accessing data on the disk so >>> blocking is essentially a non-issue. Memory mapped I/O is also an >>> incredibly >>> important feature for I/O performance, and there's almost no reason to >>> use >>> traditional I/O on 64-bit. However, it's a no-go with M:N scheduling >>> because >>> the page faults block the thread. >>> >>> # Overview >>> >>> Advantages: >>> >>> * lack of preemptive/fair scheduling, leading to higher throughput >>> * very fast context switches to other tasks on the same scheduler thread >>> >>> Disadvantages: >>> >>> * lack of preemptive/fair scheduling (lower-level model) >>> * poor profiler/debugger support >>> * async I/O stack is much slower for the common case; for example stat >>> is 35x >>> slower when run in a loop for an mlocate-like utility >>> * true blocking code will still block a scheduler thread >>> * most existing libraries use blocking I/O and OS threads >>> * cannot directly use fast and easy to use linker-supported thread-local >>> data >>> * many existing libraries rely on thread-local storage, so there's a >>> need to be >>> wary of hidden yields in Rust function calls and it's very difficult >>> to >>> expose a safe interface to these libraries >>> * every level of a CPU architecture adding registers needs explicit >>> support >>> from Rust, and it must be selected at runtime when not targeting a >>> specific >>> CPU (this is currently not done correctly) >>> >>> # User-mode scheduling >>> >>> Windows 7 introduced user-mode scheduling[1] to replace fibers on 64-bit. >>> Google implemented the same thing for Linux (perhaps even before Windows >>> 7 was >>> released), and plans on pushing for it upstream.[2] The linked video >>> does a >>> better job of covering this than I can. >>> >>> User-mode scheduling provides a 1:1 threading model including full >>> support for >>> normal thread-local data and existing debuggers/profilers. It can yield >>> to the >>> scheduler on system calls and page faults. The operating system is >>> responsible >>> for details like context switching, so a large maintenance/portability >>> burden >>> is dealt with. It narrows down the above disadvantage list to just the >>> point >>> about not having preemptive/fair scheduling and doesn't introduce any >>> new ones. >>> >>> I hope this is where concurrency is headed, and I hope Rust doesn't miss >>> this >>> boat by concentrating too much on libuv. I think it would allow us to >>> simply >>> drop support for pseudo-blocking I/O in the Go style and ignore >>> asynchronous >>> I/O and non-blocking sockets in the standard library. It may be useful >>> to have >>> the scheduler use them, but it wouldn't be essential. >>> >>> [1] http://msdn.microsoft.com/en-us/library/windows/desktop/ >>> dd627187(v=vs.85).aspx >>> [2] http://www.youtube.com/watch?v=KXuZi9aeGTw >>> _______________________________________________ >>> 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 >> > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- -Thad +ThadGuidry Thad on LinkedIn -------------- next part -------------- An HTML attachment was scrubbed... URL: From d.glazman at partner.samsung.com Thu Nov 14 07:03:36 2013 From: d.glazman at partner.samsung.com (Daniel Glazman) Date: Thu, 14 Nov 2013 16:03:36 +0100 Subject: [rust-dev] Rust docs Message-ID: <5284E648.1000301@partner.samsung.com> Hello rust-dev, I would like to make a comment I feel is important about both the Rust tutorial and manual. Please don't misunderstand me, no flame here, I am sending this message to help. I think good docs are extremely important to increase the size of a community, and in particular make more people contribute to Servo (the reason why I'm here). If the Reference Manual for Rust tries to be complete and does not try to avoid language complexity, it can be from time to time hard to read because of one thing: examples are not well or often enough explained and are often too complex given the section they belong too. It's for instance difficult for the reader to understand an example of section n that uses notions explained only in section n+4. The Tutorial is the entry point for all people willing to investigate Rust and/or contribute to Servo. I think that document is super precious, super-important. Unfortunately, I don't think it is really a tutorial but only a lighter manual. Examples are here even more important than in the case of the Manual above. A good Tutorial is often built around one single programming task that becomes more and more complex as more features of the language are read and known. Furthermore, the Tutorial has clearly adopted the language complexity of the reference manual, something that I think should be in general avoided. I also think all examples should be buildable and produce a readable result on the console even if that result is a build or execution error. That would drastically help the reader. All in all, I think the Tutorial needs some love and probably a technical writer who is not working on the guts of Rust, someone who could vulgarize the notions of the Manual into an easy-to-read, simple-to-experiment, step-by-step tutorial and avoiding in general vocabulary inherited from programming language science. Best regards, From corey at octayn.net Thu Nov 14 07:38:53 2013 From: corey at octayn.net (Corey Richardson) Date: Thu, 14 Nov 2013 10:38:53 -0500 Subject: [rust-dev] Rust docs In-Reply-To: <5284E648.1000301@partner.samsung.com> References: <5284E648.1000301@partner.samsung.com> Message-ID: On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman wrote: > The Tutorial is the entry point for all people willing to investigate > Rust and/or contribute to Servo. I think that document is super > precious, super-important. Unfortunately, I don't think it is really a > tutorial but only a lighter manual. Examples are here even more > important than in the case of the Manual above. A good Tutorial is > often built around one single programming task that becomes more and > more complex as more features of the language are read and > known. Furthermore, the Tutorial has clearly adopted the language > complexity of the reference manual, something that I think should be > in general avoided. I also think all examples should be buildable > and produce a readable result on the console even if that result is a > build or execution error. That would drastically help the reader. > > All in all, I think the Tutorial needs some love and probably a > technical writer who is not working on the guts of Rust, someone who > could vulgarize the notions of the Manual into an easy-to-read, > simple-to-experiment, step-by-step tutorial and avoiding in general > vocabulary inherited from programming language science. > I agree, partially. I think "Rust for Rubyists" fills this role quite well for now. Generally I think the language tutorial should not try to hide complexity or paper over things, at the very least so it can be complete and correct. I think the Python tutorial is a good benchmark. We might even be able to rip off the Python tutorial's structure wholesale. The "on-boarding" process is still very rough. Maybe some sort of live-comment system would work well for finding pain points, where one can add comments/feedback while reading the tutorial. From redbrain at gcc.gnu.org Thu Nov 14 07:51:23 2013 From: redbrain at gcc.gnu.org (Philip Herron) Date: Thu, 14 Nov 2013 15:51:23 +0000 Subject: [rust-dev] Rust docs In-Reply-To: References: <5284E648.1000301@partner.samsung.com> Message-ID: I would defineltly like to see a clone of the python tutorial because it really does it so well going inch by inch building up what way things work i am not a web developer but would love to write content i wonder is it possible to start a github project for this using sphinx i think it uses isn't it? On 14 November 2013 15:38, Corey Richardson wrote: > On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman > wrote: > > The Tutorial is the entry point for all people willing to investigate > > Rust and/or contribute to Servo. I think that document is super > > precious, super-important. Unfortunately, I don't think it is really a > > tutorial but only a lighter manual. Examples are here even more > > important than in the case of the Manual above. A good Tutorial is > > often built around one single programming task that becomes more and > > more complex as more features of the language are read and > > known. Furthermore, the Tutorial has clearly adopted the language > > complexity of the reference manual, something that I think should be > > in general avoided. I also think all examples should be buildable > > and produce a readable result on the console even if that result is a > > build or execution error. That would drastically help the reader. > > > > All in all, I think the Tutorial needs some love and probably a > > technical writer who is not working on the guts of Rust, someone who > > could vulgarize the notions of the Manual into an easy-to-read, > > simple-to-experiment, step-by-step tutorial and avoiding in general > > vocabulary inherited from programming language science. > > > > I agree, partially. I think "Rust for Rubyists" fills this role quite > well for now. Generally I think the language tutorial should not try > to hide complexity or paper over things, at the very least so it can > be complete and correct. I think the Python tutorial is a good > benchmark. We might even be able to rip off the Python tutorial's > structure wholesale. > > The "on-boarding" process is still very rough. Maybe some sort of > live-comment system would work well for finding pain points, where one > can add comments/feedback while reading the tutorial. > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From thadguidry at gmail.com Thu Nov 14 08:21:46 2013 From: thadguidry at gmail.com (Thad Guidry) Date: Thu, 14 Nov 2013 10:21:46 -0600 Subject: [rust-dev] Rust docs In-Reply-To: References: <5284E648.1000301@partner.samsung.com> Message-ID: Corey, Could we get that comments/feedback ability into the tutorial easily ? I agree that would be a good start in improving things. On Thu, Nov 14, 2013 at 9:38 AM, Corey Richardson wrote: > On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman > wrote: > > The Tutorial is the entry point for all people willing to investigate > > Rust and/or contribute to Servo. I think that document is super > > precious, super-important. Unfortunately, I don't think it is really a > > tutorial but only a lighter manual. Examples are here even more > > important than in the case of the Manual above. A good Tutorial is > > often built around one single programming task that becomes more and > > more complex as more features of the language are read and > > known. Furthermore, the Tutorial has clearly adopted the language > > complexity of the reference manual, something that I think should be > > in general avoided. I also think all examples should be buildable > > and produce a readable result on the console even if that result is a > > build or execution error. That would drastically help the reader. > > > > All in all, I think the Tutorial needs some love and probably a > > technical writer who is not working on the guts of Rust, someone who > > could vulgarize the notions of the Manual into an easy-to-read, > > simple-to-experiment, step-by-step tutorial and avoiding in general > > vocabulary inherited from programming language science. > > > > I agree, partially. I think "Rust for Rubyists" fills this role quite > well for now. Generally I think the language tutorial should not try > to hide complexity or paper over things, at the very least so it can > be complete and correct. I think the Python tutorial is a good > benchmark. We might even be able to rip off the Python tutorial's > structure wholesale. > > The "on-boarding" process is still very rough. Maybe some sort of > live-comment system would work well for finding pain points, where one > can add comments/feedback while reading the tutorial. > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- -Thad +ThadGuidry Thad on LinkedIn -------------- next part -------------- An HTML attachment was scrubbed... URL: From erick.tryzelaar at gmail.com Thu Nov 14 08:35:05 2013 From: erick.tryzelaar at gmail.com (Erick Tryzelaar) Date: Thu, 14 Nov 2013 08:35:05 -0800 Subject: [rust-dev] Call for speakers at the next Bay Area meetup Message-ID: Good morning Rustics, The second Bay Area meetup is happening in 6 days: http://www.meetup.com/Rust-Bay-Area/events/143439552/ Patrick will be giving a presentation about Sprocketnes along with a few others giving some lightning talks. I'd like to start planning for the next one in December/January. Would anyone like to give a 30 minute - 1 hour presentation? If so, please let me know the subject and when you'd be available to speak. Thanks! -Erick -------------- next part -------------- An HTML attachment was scrubbed... URL: From corey at octayn.net Thu Nov 14 08:36:07 2013 From: corey at octayn.net (Corey Richardson) Date: Thu, 14 Nov 2013 11:36:07 -0500 Subject: [rust-dev] Rust docs In-Reply-To: References: <5284E648.1000301@partner.samsung.com> Message-ID: I've never setup such a system. I imagine it'd need some infrastructure in place. On Thu, Nov 14, 2013 at 11:21 AM, Thad Guidry wrote: > Corey, > > Could we get that comments/feedback ability into the tutorial easily ? I > agree that would be a good start in improving things. > > > On Thu, Nov 14, 2013 at 9:38 AM, Corey Richardson wrote: >> >> On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman >> wrote: >> > The Tutorial is the entry point for all people willing to investigate >> > Rust and/or contribute to Servo. I think that document is super >> > precious, super-important. Unfortunately, I don't think it is really a >> > tutorial but only a lighter manual. Examples are here even more >> > important than in the case of the Manual above. A good Tutorial is >> > often built around one single programming task that becomes more and >> > more complex as more features of the language are read and >> > known. Furthermore, the Tutorial has clearly adopted the language >> > complexity of the reference manual, something that I think should be >> > in general avoided. I also think all examples should be buildable >> > and produce a readable result on the console even if that result is a >> > build or execution error. That would drastically help the reader. >> > >> > All in all, I think the Tutorial needs some love and probably a >> > technical writer who is not working on the guts of Rust, someone who >> > could vulgarize the notions of the Manual into an easy-to-read, >> > simple-to-experiment, step-by-step tutorial and avoiding in general >> > vocabulary inherited from programming language science. >> > >> >> I agree, partially. I think "Rust for Rubyists" fills this role quite >> well for now. Generally I think the language tutorial should not try >> to hide complexity or paper over things, at the very least so it can >> be complete and correct. I think the Python tutorial is a good >> benchmark. We might even be able to rip off the Python tutorial's >> structure wholesale. >> >> The "on-boarding" process is still very rough. Maybe some sort of >> live-comment system would work well for finding pain points, where one >> can add comments/feedback while reading the tutorial. >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > > > > > -- > -Thad > +ThadGuidry > Thad on LinkedIn From niko at alum.mit.edu Thu Nov 14 08:57:43 2013 From: niko at alum.mit.edu (Niko Matsakis) Date: Thu, 14 Nov 2013 11:57:43 -0500 Subject: [rust-dev] Built-in types should accept a pointer rhs-argument to binary operators In-Reply-To: References: Message-ID: <20131114165743.GC6546@Mr-Bennet> This is to some extent in flux (see bug #10337). But the branch I am working on actually reports *both* usages as errors. The correct code would be: *p + n n + *p Basically, a binary operator like `l + r` is translated to something similar to the following (which assumes universal function notation, not yet implemented): Add::add(&l, &r) In other words, no autoderef or other transformation takes place. We just look for a matching trait. Instead we just pass the values in by reference. The reason for passing by reference is so that you can compare linear types more naturally (i.e., `~[1, 2, 3]`). I still consider the precise behavior of overloaded operators somewhat experimental, but I know that I am not happy with the current one, which is quite ad hoc. Niko On Thu, Nov 14, 2013 at 05:50:05AM +0200, Tommi wrote: > let mut n = 11; > let p: &int = &123; > > p + n; // OK > n + p; // error: mismatched types: expected `int` but found `&int` > > Shouldn't this error be considered a compiler-bug? The Add trait says '&' for rhs after all: > fn add(&self, rhs: &RHS) -> Result; > > -Tommi > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From gaetan at xeberon.net Thu Nov 14 08:58:12 2013 From: gaetan at xeberon.net (Gaetan) Date: Thu, 14 Nov 2013 17:58:12 +0100 Subject: [rust-dev] Rust docs In-Reply-To: References: <5284E648.1000301@partner.samsung.com> Message-ID: I would love helping on this matter, I'm use to setting up automatic documentation generation (rst, sphinx, doxygen,...). ----- Gaetan 2013/11/14 Philip Herron > I would defineltly like to see a clone of the python tutorial because it > really does it so well going inch by inch building up what way things work > i am not a web developer but would love to write content i wonder is it > possible to start a github project for this using sphinx i think it uses > isn't it? > > > On 14 November 2013 15:38, Corey Richardson wrote: > >> On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman >> wrote: >> > The Tutorial is the entry point for all people willing to investigate >> > Rust and/or contribute to Servo. I think that document is super >> > precious, super-important. Unfortunately, I don't think it is really a >> > tutorial but only a lighter manual. Examples are here even more >> > important than in the case of the Manual above. A good Tutorial is >> > often built around one single programming task that becomes more and >> > more complex as more features of the language are read and >> > known. Furthermore, the Tutorial has clearly adopted the language >> > complexity of the reference manual, something that I think should be >> > in general avoided. I also think all examples should be buildable >> > and produce a readable result on the console even if that result is a >> > build or execution error. That would drastically help the reader. >> > >> > All in all, I think the Tutorial needs some love and probably a >> > technical writer who is not working on the guts of Rust, someone who >> > could vulgarize the notions of the Manual into an easy-to-read, >> > simple-to-experiment, step-by-step tutorial and avoiding in general >> > vocabulary inherited from programming language science. >> > >> >> I agree, partially. I think "Rust for Rubyists" fills this role quite >> well for now. Generally I think the language tutorial should not try >> to hide complexity or paper over things, at the very least so it can >> be complete and correct. I think the Python tutorial is a good >> benchmark. We might even be able to rip off the Python tutorial's >> structure wholesale. >> >> The "on-boarding" process is still very rough. Maybe some sort of >> live-comment system would work well for finding pain points, where one >> can add comments/feedback while reading the tutorial. >> _______________________________________________ >> 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: From tessyjoseph1992 at gmail.com Thu Nov 14 09:29:03 2013 From: tessyjoseph1992 at gmail.com (tessy joseph) Date: Thu, 14 Nov 2013 12:29:03 -0500 Subject: [rust-dev] Rust-dev Digest, Vol 41, Issue 76 In-Reply-To: References: Message-ID: Hi I am interested in contributing mozilla.especially to know more about RUST.I tried installing it on my Ubuntu.after make && make install I am getting an error.please report the issue https://gist.github.com/Tessie/7470406 Regards Tessy On Thu, Nov 14, 2013 at 11:35 AM, wrote: > Send Rust-dev mailing list submissions to > rust-dev at mozilla.org > > To subscribe or unsubscribe via the World Wide Web, visit > https://mail.mozilla.org/listinfo/rust-dev > or, via email, send a message with subject or body 'help' to > rust-dev-request at mozilla.org > > You can reach the person managing the list at > rust-dev-owner at mozilla.org > > When replying, please edit your Subject line so it is more specific > than "Re: Contents of Rust-dev digest..." > > > Today's Topics: > > 1. Rust docs (Daniel Glazman) > 2. Re: Rust docs (Corey Richardson) > 3. Re: Rust docs (Philip Herron) > 4. Re: Rust docs (Thad Guidry) > 5. Call for speakers at the next Bay Area meetup (Erick Tryzelaar) > > > ---------------------------------------------------------------------- > > Message: 1 > Date: Thu, 14 Nov 2013 16:03:36 +0100 > From: Daniel Glazman > To: rust-dev at mozilla.org > Subject: [rust-dev] Rust docs > Message-ID: <5284E648.1000301 at partner.samsung.com> > Content-Type: text/plain; charset=ISO-8859-1 > > Hello rust-dev, > > I would like to make a comment I feel is important about both the Rust > tutorial and manual. Please don't misunderstand me, no flame here, I > am sending this message to help. I think good docs are extremely > important to increase the size of a community, and in particular make > more people contribute to Servo (the reason why I'm here). > > If the Reference Manual for Rust tries to be complete and does not try > to avoid language complexity, it can be from time to time hard to read > because of one thing: examples are not well or often enough explained > and are often too complex given the section they belong too. It's for > instance difficult for the reader to understand an example of section > n that uses notions explained only in section n+4. > > The Tutorial is the entry point for all people willing to investigate > Rust and/or contribute to Servo. I think that document is super > precious, super-important. Unfortunately, I don't think it is really a > tutorial but only a lighter manual. Examples are here even more > important than in the case of the Manual above. A good Tutorial is > often built around one single programming task that becomes more and > more complex as more features of the language are read and > known. Furthermore, the Tutorial has clearly adopted the language > complexity of the reference manual, something that I think should be > in general avoided. I also think all examples should be buildable > and produce a readable result on the console even if that result is a > build or execution error. That would drastically help the reader. > > All in all, I think the Tutorial needs some love and probably a > technical writer who is not working on the guts of Rust, someone who > could vulgarize the notions of the Manual into an easy-to-read, > simple-to-experiment, step-by-step tutorial and avoiding in general > vocabulary inherited from programming language science. > > Best regards, > > > > > ------------------------------ > > Message: 2 > Date: Thu, 14 Nov 2013 10:38:53 -0500 > From: Corey Richardson > To: Daniel Glazman > Cc: "rust-dev at mozilla.org" > Subject: Re: [rust-dev] Rust docs > Message-ID: > < > CA++BO6Rk41vs-GTLW8wbugE7PbD3_EGXzMdj9nhoqsKyL24iMg at mail.gmail.com> > Content-Type: text/plain; charset=UTF-8 > > On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman > wrote: > > The Tutorial is the entry point for all people willing to investigate > > Rust and/or contribute to Servo. I think that document is super > > precious, super-important. Unfortunately, I don't think it is really a > > tutorial but only a lighter manual. Examples are here even more > > important than in the case of the Manual above. A good Tutorial is > > often built around one single programming task that becomes more and > > more complex as more features of the language are read and > > known. Furthermore, the Tutorial has clearly adopted the language > > complexity of the reference manual, something that I think should be > > in general avoided. I also think all examples should be buildable > > and produce a readable result on the console even if that result is a > > build or execution error. That would drastically help the reader. > > > > All in all, I think the Tutorial needs some love and probably a > > technical writer who is not working on the guts of Rust, someone who > > could vulgarize the notions of the Manual into an easy-to-read, > > simple-to-experiment, step-by-step tutorial and avoiding in general > > vocabulary inherited from programming language science. > > > > I agree, partially. I think "Rust for Rubyists" fills this role quite > well for now. Generally I think the language tutorial should not try > to hide complexity or paper over things, at the very least so it can > be complete and correct. I think the Python tutorial is a good > benchmark. We might even be able to rip off the Python tutorial's > structure wholesale. > > The "on-boarding" process is still very rough. Maybe some sort of > live-comment system would work well for finding pain points, where one > can add comments/feedback while reading the tutorial. > > > ------------------------------ > > Message: 3 > Date: Thu, 14 Nov 2013 15:51:23 +0000 > From: Philip Herron > To: Corey Richardson > Cc: "rust-dev at mozilla.org" > Subject: Re: [rust-dev] Rust docs > Message-ID: > < > CAEvRbeqNf+ZnF-N-JWmiE5axmTMjG2fmaYE_RHjdBuiJyezR4g at mail.gmail.com> > Content-Type: text/plain; charset="iso-8859-1" > > I would defineltly like to see a clone of the python tutorial because it > really does it so well going inch by inch building up what way things work > i am not a web developer but would love to write content i wonder is it > possible to start a github project for this using sphinx i think it uses > isn't it? > > > On 14 November 2013 15:38, Corey Richardson wrote: > > > On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman > > wrote: > > > The Tutorial is the entry point for all people willing to investigate > > > Rust and/or contribute to Servo. I think that document is super > > > precious, super-important. Unfortunately, I don't think it is really a > > > tutorial but only a lighter manual. Examples are here even more > > > important than in the case of the Manual above. A good Tutorial is > > > often built around one single programming task that becomes more and > > > more complex as more features of the language are read and > > > known. Furthermore, the Tutorial has clearly adopted the language > > > complexity of the reference manual, something that I think should be > > > in general avoided. I also think all examples should be buildable > > > and produce a readable result on the console even if that result is a > > > build or execution error. That would drastically help the reader. > > > > > > All in all, I think the Tutorial needs some love and probably a > > > technical writer who is not working on the guts of Rust, someone who > > > could vulgarize the notions of the Manual into an easy-to-read, > > > simple-to-experiment, step-by-step tutorial and avoiding in general > > > vocabulary inherited from programming language science. > > > > > > > I agree, partially. I think "Rust for Rubyists" fills this role quite > > well for now. Generally I think the language tutorial should not try > > to hide complexity or paper over things, at the very least so it can > > be complete and correct. I think the Python tutorial is a good > > benchmark. We might even be able to rip off the Python tutorial's > > structure wholesale. > > > > The "on-boarding" process is still very rough. Maybe some sort of > > live-comment system would work well for finding pain points, where one > > can add comments/feedback while reading the tutorial. > > _______________________________________________ > > 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/20131114/7361ce13/attachment-0001.html > > > > ------------------------------ > > Message: 4 > Date: Thu, 14 Nov 2013 10:21:46 -0600 > From: Thad Guidry > To: Corey Richardson > Cc: "rust-dev at mozilla.org" > Subject: Re: [rust-dev] Rust docs > Message-ID: > CojWkiEthPbPON1R7aiNiu0ykHB_OcSZ6ef9Jg at mail.gmail.com> > Content-Type: text/plain; charset="iso-8859-1" > > Corey, > > Could we get that comments/feedback ability into the tutorial easily ? I > agree that would be a good start in improving things. > > > On Thu, Nov 14, 2013 at 9:38 AM, Corey Richardson > wrote: > > > On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman > > wrote: > > > The Tutorial is the entry point for all people willing to investigate > > > Rust and/or contribute to Servo. I think that document is super > > > precious, super-important. Unfortunately, I don't think it is really a > > > tutorial but only a lighter manual. Examples are here even more > > > important than in the case of the Manual above. A good Tutorial is > > > often built around one single programming task that becomes more and > > > more complex as more features of the language are read and > > > known. Furthermore, the Tutorial has clearly adopted the language > > > complexity of the reference manual, something that I think should be > > > in general avoided. I also think all examples should be buildable > > > and produce a readable result on the console even if that result is a > > > build or execution error. That would drastically help the reader. > > > > > > All in all, I think the Tutorial needs some love and probably a > > > technical writer who is not working on the guts of Rust, someone who > > > could vulgarize the notions of the Manual into an easy-to-read, > > > simple-to-experiment, step-by-step tutorial and avoiding in general > > > vocabulary inherited from programming language science. > > > > > > > I agree, partially. I think "Rust for Rubyists" fills this role quite > > well for now. Generally I think the language tutorial should not try > > to hide complexity or paper over things, at the very least so it can > > be complete and correct. I think the Python tutorial is a good > > benchmark. We might even be able to rip off the Python tutorial's > > structure wholesale. > > > > The "on-boarding" process is still very rough. Maybe some sort of > > live-comment system would work well for finding pain points, where one > > can add comments/feedback while reading the tutorial. > > _______________________________________________ > > Rust-dev mailing list > > Rust-dev at mozilla.org > > https://mail.mozilla.org/listinfo/rust-dev > > > > > > -- > -Thad > +ThadGuidry > Thad on LinkedIn > -------------- next part -------------- > An HTML attachment was scrubbed... > URL: < > http://mail.mozilla.org/pipermail/rust-dev/attachments/20131114/56237d25/attachment-0001.html > > > > ------------------------------ > > Message: 5 > Date: Thu, 14 Nov 2013 08:35:05 -0800 > From: Erick Tryzelaar > To: "rust-dev at mozilla.org" > Subject: [rust-dev] Call for speakers at the next Bay Area meetup > Message-ID: > < > CALdfqQLPyYHv8DdXnjR4HvQ3k8nzYP+MLDqP6s+JOQeCBzz4EQ at mail.gmail.com> > Content-Type: text/plain; charset="utf-8" > > Good morning Rustics, > > The second Bay Area meetup is happening in 6 days: > > http://www.meetup.com/Rust-Bay-Area/events/143439552/ > > Patrick will be giving a presentation about Sprocketnes along with a few > others giving some lightning talks. I'd like to start planning for the next > one in December/January. Would anyone like to give a 30 minute - 1 hour > presentation? If so, please let me know the subject and when you'd be > available to speak. > > Thanks! > -Erick > -------------- next part -------------- > An HTML attachment was scrubbed... > URL: < > http://mail.mozilla.org/pipermail/rust-dev/attachments/20131114/4df883a3/attachment.html > > > > ------------------------------ > > Subject: Digest Footer > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > > ------------------------------ > > End of Rust-dev Digest, Vol 41, Issue 76 > **************************************** > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ben.striegel at gmail.com Thu Nov 14 09:30:25 2013 From: ben.striegel at gmail.com (Benjamin Striegel) Date: Thu, 14 Nov 2013 12:30:25 -0500 Subject: [rust-dev] Rust docs In-Reply-To: References: <5284E648.1000301@partner.samsung.com> Message-ID: I would welcome such an effort, and suggest that it live as its own project, outside of the Rust repo. We really aren't set up currently to handle rapid and frequent documentation changes. Once it gets to a reasonable level of maturity we could then give it a mention from the main tutorial, and then once it's ready we could replace the current tutorial entirely. On Thu, Nov 14, 2013 at 11:58 AM, Gaetan wrote: > I would love helping on this matter, I'm use to setting up automatic > documentation generation (rst, sphinx, doxygen,...). > > ----- > Gaetan > > > > 2013/11/14 Philip Herron > >> I would defineltly like to see a clone of the python tutorial because it >> really does it so well going inch by inch building up what way things work >> i am not a web developer but would love to write content i wonder is it >> possible to start a github project for this using sphinx i think it uses >> isn't it? >> >> >> On 14 November 2013 15:38, Corey Richardson wrote: >> >>> On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman >>> wrote: >>> > The Tutorial is the entry point for all people willing to investigate >>> > Rust and/or contribute to Servo. I think that document is super >>> > precious, super-important. Unfortunately, I don't think it is really a >>> > tutorial but only a lighter manual. Examples are here even more >>> > important than in the case of the Manual above. A good Tutorial is >>> > often built around one single programming task that becomes more and >>> > more complex as more features of the language are read and >>> > known. Furthermore, the Tutorial has clearly adopted the language >>> > complexity of the reference manual, something that I think should be >>> > in general avoided. I also think all examples should be buildable >>> > and produce a readable result on the console even if that result is a >>> > build or execution error. That would drastically help the reader. >>> > >>> > All in all, I think the Tutorial needs some love and probably a >>> > technical writer who is not working on the guts of Rust, someone who >>> > could vulgarize the notions of the Manual into an easy-to-read, >>> > simple-to-experiment, step-by-step tutorial and avoiding in general >>> > vocabulary inherited from programming language science. >>> > >>> >>> I agree, partially. I think "Rust for Rubyists" fills this role quite >>> well for now. Generally I think the language tutorial should not try >>> to hide complexity or paper over things, at the very least so it can >>> be complete and correct. I think the Python tutorial is a good >>> benchmark. We might even be able to rip off the Python tutorial's >>> structure wholesale. >>> >>> The "on-boarding" process is still very rough. Maybe some sort of >>> live-comment system would work well for finding pain points, where one >>> can add comments/feedback while reading the tutorial. >>> _______________________________________________ >>> 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 >> >> > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ben.striegel at gmail.com Thu Nov 14 09:38:16 2013 From: ben.striegel at gmail.com (Benjamin Striegel) Date: Thu, 14 Nov 2013 12:38:16 -0500 Subject: [rust-dev] Rust docs In-Reply-To: References: <5284E648.1000301@partner.samsung.com> Message-ID: And by replace I mean we could relegate the current tutorial to an "advanced" tutorial or somesuch. On Thu, Nov 14, 2013 at 12:30 PM, Benjamin Striegel wrote: > I would welcome such an effort, and suggest that it live as its own > project, outside of the Rust repo. We really aren't set up currently to > handle rapid and frequent documentation changes. Once it gets to a > reasonable level of maturity we could then give it a mention from the main > tutorial, and then once it's ready we could replace the current tutorial > entirely. > > > On Thu, Nov 14, 2013 at 11:58 AM, Gaetan wrote: > >> I would love helping on this matter, I'm use to setting up automatic >> documentation generation (rst, sphinx, doxygen,...). >> >> ----- >> Gaetan >> >> >> >> 2013/11/14 Philip Herron >> >>> I would defineltly like to see a clone of the python tutorial because it >>> really does it so well going inch by inch building up what way things work >>> i am not a web developer but would love to write content i wonder is it >>> possible to start a github project for this using sphinx i think it uses >>> isn't it? >>> >>> >>> On 14 November 2013 15:38, Corey Richardson wrote: >>> >>>> On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman >>>> wrote: >>>> > The Tutorial is the entry point for all people willing to investigate >>>> > Rust and/or contribute to Servo. I think that document is super >>>> > precious, super-important. Unfortunately, I don't think it is really a >>>> > tutorial but only a lighter manual. Examples are here even more >>>> > important than in the case of the Manual above. A good Tutorial is >>>> > often built around one single programming task that becomes more and >>>> > more complex as more features of the language are read and >>>> > known. Furthermore, the Tutorial has clearly adopted the language >>>> > complexity of the reference manual, something that I think should be >>>> > in general avoided. I also think all examples should be buildable >>>> > and produce a readable result on the console even if that result is a >>>> > build or execution error. That would drastically help the reader. >>>> > >>>> > All in all, I think the Tutorial needs some love and probably a >>>> > technical writer who is not working on the guts of Rust, someone who >>>> > could vulgarize the notions of the Manual into an easy-to-read, >>>> > simple-to-experiment, step-by-step tutorial and avoiding in general >>>> > vocabulary inherited from programming language science. >>>> > >>>> >>>> I agree, partially. I think "Rust for Rubyists" fills this role quite >>>> well for now. Generally I think the language tutorial should not try >>>> to hide complexity or paper over things, at the very least so it can >>>> be complete and correct. I think the Python tutorial is a good >>>> benchmark. We might even be able to rip off the Python tutorial's >>>> structure wholesale. >>>> >>>> The "on-boarding" process is still very rough. Maybe some sort of >>>> live-comment system would work well for finding pain points, where one >>>> can add comments/feedback while reading the tutorial. >>>> _______________________________________________ >>>> 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 >>> >>> >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gaetan at xeberon.net Thu Nov 14 09:39:16 2013 From: gaetan at xeberon.net (Gaetan) Date: Thu, 14 Nov 2013 18:39:16 +0100 Subject: [rust-dev] Rust docs In-Reply-To: References: <5284E648.1000301@partner.samsung.com> Message-ID: do you have a buildbot or jenkins for the rust ? I don't think travis could push html pages to a remote repository, do it? ----- Gaetan 2013/11/14 Benjamin Striegel > I would welcome such an effort, and suggest that it live as its own > project, outside of the Rust repo. We really aren't set up currently to > handle rapid and frequent documentation changes. Once it gets to a > reasonable level of maturity we could then give it a mention from the main > tutorial, and then once it's ready we could replace the current tutorial > entirely. > > > On Thu, Nov 14, 2013 at 11:58 AM, Gaetan wrote: > >> I would love helping on this matter, I'm use to setting up automatic >> documentation generation (rst, sphinx, doxygen,...). >> >> ----- >> Gaetan >> >> >> >> 2013/11/14 Philip Herron >> >>> I would defineltly like to see a clone of the python tutorial because it >>> really does it so well going inch by inch building up what way things work >>> i am not a web developer but would love to write content i wonder is it >>> possible to start a github project for this using sphinx i think it uses >>> isn't it? >>> >>> >>> On 14 November 2013 15:38, Corey Richardson wrote: >>> >>>> On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman >>>> wrote: >>>> > The Tutorial is the entry point for all people willing to investigate >>>> > Rust and/or contribute to Servo. I think that document is super >>>> > precious, super-important. Unfortunately, I don't think it is really a >>>> > tutorial but only a lighter manual. Examples are here even more >>>> > important than in the case of the Manual above. A good Tutorial is >>>> > often built around one single programming task that becomes more and >>>> > more complex as more features of the language are read and >>>> > known. Furthermore, the Tutorial has clearly adopted the language >>>> > complexity of the reference manual, something that I think should be >>>> > in general avoided. I also think all examples should be buildable >>>> > and produce a readable result on the console even if that result is a >>>> > build or execution error. That would drastically help the reader. >>>> > >>>> > All in all, I think the Tutorial needs some love and probably a >>>> > technical writer who is not working on the guts of Rust, someone who >>>> > could vulgarize the notions of the Manual into an easy-to-read, >>>> > simple-to-experiment, step-by-step tutorial and avoiding in general >>>> > vocabulary inherited from programming language science. >>>> > >>>> >>>> I agree, partially. I think "Rust for Rubyists" fills this role quite >>>> well for now. Generally I think the language tutorial should not try >>>> to hide complexity or paper over things, at the very least so it can >>>> be complete and correct. I think the Python tutorial is a good >>>> benchmark. We might even be able to rip off the Python tutorial's >>>> structure wholesale. >>>> >>>> The "on-boarding" process is still very rough. Maybe some sort of >>>> live-comment system would work well for finding pain points, where one >>>> can add comments/feedback while reading the tutorial. >>>> _______________________________________________ >>>> 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 >>> >>> >> >> _______________________________________________ >> 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: From corey at octayn.net Thu Nov 14 09:43:11 2013 From: corey at octayn.net (Corey Richardson) Date: Thu, 14 Nov 2013 12:43:11 -0500 Subject: [rust-dev] Rust docs In-Reply-To: References: <5284E648.1000301@partner.samsung.com> Message-ID: Travis could, but then anyone could (since the travis.yml is public and it'd need credentials to the repo). We have a buildbot, buildbot.rust-lang.org On Thu, Nov 14, 2013 at 12:39 PM, Gaetan wrote: > do you have a buildbot or jenkins for the rust ? > I don't think travis could push html pages to a remote repository, do it? > > ----- > Gaetan > > > > 2013/11/14 Benjamin Striegel >> >> I would welcome such an effort, and suggest that it live as its own >> project, outside of the Rust repo. We really aren't set up currently to >> handle rapid and frequent documentation changes. Once it gets to a >> reasonable level of maturity we could then give it a mention from the main >> tutorial, and then once it's ready we could replace the current tutorial >> entirely. >> >> >> On Thu, Nov 14, 2013 at 11:58 AM, Gaetan wrote: >>> >>> I would love helping on this matter, I'm use to setting up automatic >>> documentation generation (rst, sphinx, doxygen,...). >>> >>> ----- >>> Gaetan >>> >>> >>> >>> 2013/11/14 Philip Herron >>>> >>>> I would defineltly like to see a clone of the python tutorial because it >>>> really does it so well going inch by inch building up what way things work i >>>> am not a web developer but would love to write content i wonder is it >>>> possible to start a github project for this using sphinx i think it uses >>>> isn't it? >>>> >>>> >>>> On 14 November 2013 15:38, Corey Richardson wrote: >>>>> >>>>> On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman >>>>> wrote: >>>>> > The Tutorial is the entry point for all people willing to investigate >>>>> > Rust and/or contribute to Servo. I think that document is super >>>>> > precious, super-important. Unfortunately, I don't think it is really >>>>> > a >>>>> > tutorial but only a lighter manual. Examples are here even more >>>>> > important than in the case of the Manual above. A good Tutorial is >>>>> > often built around one single programming task that becomes more and >>>>> > more complex as more features of the language are read and >>>>> > known. Furthermore, the Tutorial has clearly adopted the language >>>>> > complexity of the reference manual, something that I think should be >>>>> > in general avoided. I also think all examples should be buildable >>>>> > and produce a readable result on the console even if that result is a >>>>> > build or execution error. That would drastically help the reader. >>>>> > >>>>> > All in all, I think the Tutorial needs some love and probably a >>>>> > technical writer who is not working on the guts of Rust, someone who >>>>> > could vulgarize the notions of the Manual into an easy-to-read, >>>>> > simple-to-experiment, step-by-step tutorial and avoiding in general >>>>> > vocabulary inherited from programming language science. >>>>> > >>>>> >>>>> I agree, partially. I think "Rust for Rubyists" fills this role quite >>>>> well for now. Generally I think the language tutorial should not try >>>>> to hide complexity or paper over things, at the very least so it can >>>>> be complete and correct. I think the Python tutorial is a good >>>>> benchmark. We might even be able to rip off the Python tutorial's >>>>> structure wholesale. >>>>> >>>>> The "on-boarding" process is still very rough. Maybe some sort of >>>>> live-comment system would work well for finding pain points, where one >>>>> can add comments/feedback while reading the tutorial. >>>>> _______________________________________________ >>>>> 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 >>>> >>> >>> >>> _______________________________________________ >>> 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 >> > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > From gaetan at xeberon.net Thu Nov 14 09:50:48 2013 From: gaetan at xeberon.net (Gaetan) Date: Thu, 14 Nov 2013 18:50:48 +0100 Subject: [rust-dev] library name libstd and libextra Message-ID: I have a question about the two files "libextra" and "libstd" that are installed by rust compiler. Can they be called by any normal average program? If so, shouldn't we document how? If this has no sense, I suggest to rename them to something like "libruststd" or "librustextra" to avoid naming conflict with system libraries. We can also move to a subdirectory of /usr/lib, like /usr/lib/rust. What do you think about this? ----- Gaetan -------------- next part -------------- An HTML attachment was scrubbed... URL: From gaetan at xeberon.net Thu Nov 14 09:51:57 2013 From: gaetan at xeberon.net (Gaetan) Date: Thu, 14 Nov 2013 18:51:57 +0100 Subject: [rust-dev] Rust docs In-Reply-To: References: <5284E648.1000301@partner.samsung.com> Message-ID: good :) so, what is missing to have an automatic generation of html page from a github page? ----- Gaetan 2013/11/14 Corey Richardson > Travis could, but then anyone could (since the travis.yml is public > and it'd need credentials to the repo). We have a buildbot, > buildbot.rust-lang.org > > On Thu, Nov 14, 2013 at 12:39 PM, Gaetan wrote: > > do you have a buildbot or jenkins for the rust ? > > I don't think travis could push html pages to a remote repository, do it? > > > > ----- > > Gaetan > > > > > > > > 2013/11/14 Benjamin Striegel > >> > >> I would welcome such an effort, and suggest that it live as its own > >> project, outside of the Rust repo. We really aren't set up currently to > >> handle rapid and frequent documentation changes. Once it gets to a > >> reasonable level of maturity we could then give it a mention from the > main > >> tutorial, and then once it's ready we could replace the current tutorial > >> entirely. > >> > >> > >> On Thu, Nov 14, 2013 at 11:58 AM, Gaetan wrote: > >>> > >>> I would love helping on this matter, I'm use to setting up automatic > >>> documentation generation (rst, sphinx, doxygen,...). > >>> > >>> ----- > >>> Gaetan > >>> > >>> > >>> > >>> 2013/11/14 Philip Herron > >>>> > >>>> I would defineltly like to see a clone of the python tutorial because > it > >>>> really does it so well going inch by inch building up what way things > work i > >>>> am not a web developer but would love to write content i wonder is it > >>>> possible to start a github project for this using sphinx i think it > uses > >>>> isn't it? > >>>> > >>>> > >>>> On 14 November 2013 15:38, Corey Richardson wrote: > >>>>> > >>>>> On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman > >>>>> wrote: > >>>>> > The Tutorial is the entry point for all people willing to > investigate > >>>>> > Rust and/or contribute to Servo. I think that document is super > >>>>> > precious, super-important. Unfortunately, I don't think it is > really > >>>>> > a > >>>>> > tutorial but only a lighter manual. Examples are here even more > >>>>> > important than in the case of the Manual above. A good Tutorial is > >>>>> > often built around one single programming task that becomes more > and > >>>>> > more complex as more features of the language are read and > >>>>> > known. Furthermore, the Tutorial has clearly adopted the language > >>>>> > complexity of the reference manual, something that I think should > be > >>>>> > in general avoided. I also think all examples should be buildable > >>>>> > and produce a readable result on the console even if that result > is a > >>>>> > build or execution error. That would drastically help the reader. > >>>>> > > >>>>> > All in all, I think the Tutorial needs some love and probably a > >>>>> > technical writer who is not working on the guts of Rust, someone > who > >>>>> > could vulgarize the notions of the Manual into an easy-to-read, > >>>>> > simple-to-experiment, step-by-step tutorial and avoiding in general > >>>>> > vocabulary inherited from programming language science. > >>>>> > > >>>>> > >>>>> I agree, partially. I think "Rust for Rubyists" fills this role quite > >>>>> well for now. Generally I think the language tutorial should not try > >>>>> to hide complexity or paper over things, at the very least so it can > >>>>> be complete and correct. I think the Python tutorial is a good > >>>>> benchmark. We might even be able to rip off the Python tutorial's > >>>>> structure wholesale. > >>>>> > >>>>> The "on-boarding" process is still very rough. Maybe some sort of > >>>>> live-comment system would work well for finding pain points, where > one > >>>>> can add comments/feedback while reading the tutorial. > >>>>> _______________________________________________ > >>>>> 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 > >>>> > >>> > >>> > >>> _______________________________________________ > >>> 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 > >> > > > > > > _______________________________________________ > > Rust-dev mailing list > > Rust-dev at mozilla.org > > https://mail.mozilla.org/listinfo/rust-dev > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From corey at octayn.net Thu Nov 14 09:56:56 2013 From: corey at octayn.net (Corey Richardson) Date: Thu, 14 Nov 2013 12:56:56 -0500 Subject: [rust-dev] Rust docs In-Reply-To: References: <5284E648.1000301@partner.samsung.com> Message-ID: We *do* do automatic generation. It uses the markdown in `doc`. tutorial.md, and rust.md is the manual. On Thu, Nov 14, 2013 at 12:51 PM, Gaetan wrote: > good :) > > so, what is missing to have an automatic generation of html page from a > github page? > > ----- > Gaetan > > > > 2013/11/14 Corey Richardson >> >> Travis could, but then anyone could (since the travis.yml is public >> and it'd need credentials to the repo). We have a buildbot, >> buildbot.rust-lang.org >> >> On Thu, Nov 14, 2013 at 12:39 PM, Gaetan wrote: >> > do you have a buildbot or jenkins for the rust ? >> > I don't think travis could push html pages to a remote repository, do >> > it? >> > >> > ----- >> > Gaetan >> > >> > >> > >> > 2013/11/14 Benjamin Striegel >> >> >> >> I would welcome such an effort, and suggest that it live as its own >> >> project, outside of the Rust repo. We really aren't set up currently to >> >> handle rapid and frequent documentation changes. Once it gets to a >> >> reasonable level of maturity we could then give it a mention from the >> >> main >> >> tutorial, and then once it's ready we could replace the current >> >> tutorial >> >> entirely. >> >> >> >> >> >> On Thu, Nov 14, 2013 at 11:58 AM, Gaetan wrote: >> >>> >> >>> I would love helping on this matter, I'm use to setting up automatic >> >>> documentation generation (rst, sphinx, doxygen,...). >> >>> >> >>> ----- >> >>> Gaetan >> >>> >> >>> >> >>> >> >>> 2013/11/14 Philip Herron >> >>>> >> >>>> I would defineltly like to see a clone of the python tutorial because >> >>>> it >> >>>> really does it so well going inch by inch building up what way things >> >>>> work i >> >>>> am not a web developer but would love to write content i wonder is it >> >>>> possible to start a github project for this using sphinx i think it >> >>>> uses >> >>>> isn't it? >> >>>> >> >>>> >> >>>> On 14 November 2013 15:38, Corey Richardson wrote: >> >>>>> >> >>>>> On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman >> >>>>> wrote: >> >>>>> > The Tutorial is the entry point for all people willing to >> >>>>> > investigate >> >>>>> > Rust and/or contribute to Servo. I think that document is super >> >>>>> > precious, super-important. Unfortunately, I don't think it is >> >>>>> > really >> >>>>> > a >> >>>>> > tutorial but only a lighter manual. Examples are here even more >> >>>>> > important than in the case of the Manual above. A good Tutorial is >> >>>>> > often built around one single programming task that becomes more >> >>>>> > and >> >>>>> > more complex as more features of the language are read and >> >>>>> > known. Furthermore, the Tutorial has clearly adopted the language >> >>>>> > complexity of the reference manual, something that I think should >> >>>>> > be >> >>>>> > in general avoided. I also think all examples should be buildable >> >>>>> > and produce a readable result on the console even if that result >> >>>>> > is a >> >>>>> > build or execution error. That would drastically help the reader. >> >>>>> > >> >>>>> > All in all, I think the Tutorial needs some love and probably a >> >>>>> > technical writer who is not working on the guts of Rust, someone >> >>>>> > who >> >>>>> > could vulgarize the notions of the Manual into an easy-to-read, >> >>>>> > simple-to-experiment, step-by-step tutorial and avoiding in >> >>>>> > general >> >>>>> > vocabulary inherited from programming language science. >> >>>>> > >> >>>>> >> >>>>> I agree, partially. I think "Rust for Rubyists" fills this role >> >>>>> quite >> >>>>> well for now. Generally I think the language tutorial should not >> >>>>> try >> >>>>> to hide complexity or paper over things, at the very least so it can >> >>>>> be complete and correct. I think the Python tutorial is a good >> >>>>> benchmark. We might even be able to rip off the Python tutorial's >> >>>>> structure wholesale. >> >>>>> >> >>>>> The "on-boarding" process is still very rough. Maybe some sort of >> >>>>> live-comment system would work well for finding pain points, where >> >>>>> one >> >>>>> can add comments/feedback while reading the tutorial. >> >>>>> _______________________________________________ >> >>>>> 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 >> >>>> >> >>> >> >>> >> >>> _______________________________________________ >> >>> 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 >> >> >> > >> > >> > _______________________________________________ >> > Rust-dev mailing list >> > Rust-dev at mozilla.org >> > https://mail.mozilla.org/listinfo/rust-dev >> > > > From tessyjoseph1992 at gmail.com Thu Nov 14 09:57:01 2013 From: tessyjoseph1992 at gmail.com (tessy joseph) Date: Thu, 14 Nov 2013 12:57:01 -0500 Subject: [rust-dev] Compiler hitting an unexpected failure path Message-ID: Hi I was trying to install RUST on my ubuntu local system.I could not complete after make && make install.I also tried sudo make install.Both of them failed .I got this note;Bug reported Compiler hitting unexpected failure path https://gist.github.com/Tessie/7470406 Regards Tessy -------------- next part -------------- An HTML attachment was scrubbed... URL: From me at kevincantu.org Thu Nov 14 10:04:37 2013 From: me at kevincantu.org (Kevin Cantu) Date: Thu, 14 Nov 2013 10:04:37 -0800 Subject: [rust-dev] library name libstd and libextra In-Reply-To: References: Message-ID: These standard libraries are already packaged for use and documented on the homepage. The import for std is implied, and for the second you just need this: extern mod extra; Cheers, Kevin On Thu, Nov 14, 2013 at 9:50 AM, Gaetan wrote: > > I have a question about the two files "libextra" and "libstd" that are > installed by rust compiler. > > Can they be called by any normal average program? > > If so, shouldn't we document how? > If this has no sense, I suggest to rename them to something like > "libruststd" or "librustextra" to avoid naming conflict with system > libraries. We can also move to a subdirectory of /usr/lib, like > /usr/lib/rust. > > What do you think about this? > ----- > Gaetan > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From me at kevincantu.org Thu Nov 14 10:07:00 2013 From: me at kevincantu.org (Kevin Cantu) Date: Thu, 14 Nov 2013 10:07:00 -0800 Subject: [rust-dev] Compiler hitting an unexpected failure path In-Reply-To: References: Message-ID: Definitely looks like an internal compiler error (a.k.a. an ICE). If you happen to have the time, run it again with more logging (like that error message says) and file an issue on GitHub! :D Kevin On Thu, Nov 14, 2013 at 9:57 AM, tessy joseph wrote: > Hi > > I was trying to install RUST on my ubuntu local system.I could not > complete after make && make install.I also tried sudo make install.Both of > them failed .I got this note;Bug reported Compiler hitting unexpected > failure path > > https://gist.github.com/Tessie/7470406 > > Regards > Tessy > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gaetan at xeberon.net Thu Nov 14 10:17:15 2013 From: gaetan at xeberon.net (Gaetan) Date: Thu, 14 Nov 2013 19:17:15 +0100 Subject: [rust-dev] library name libstd and libextra In-Reply-To: References: Message-ID: I speak about the file names: /usr/local/lib/libstd... And /usr/local/lib/libextra Le jeudi 14 novembre 2013, Kevin Cantu a ?crit : > These standard libraries are already packaged for use and documented on > the homepage. The import for std is implied, and for the second you just > need this: > > extern mod extra; > > > Cheers, > Kevin > > > > On Thu, Nov 14, 2013 at 9:50 AM, Gaetan > > wrote: > >> >> I have a question about the two files "libextra" and "libstd" that are >> installed by rust compiler. >> >> Can they be called by any normal average program? >> >> If so, shouldn't we document how? >> If this has no sense, I suggest to rename them to something like >> "libruststd" or "librustextra" to avoid naming conflict with system >> libraries. We can also move to a subdirectory of /usr/lib, like >> /usr/lib/rust. >> >> What do you think about this? >> ----- >> Gaetan >> >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> >> > -- ----- Gaetan -------------- next part -------------- An HTML attachment was scrubbed... URL: From alex at crichton.co Thu Nov 14 10:20:11 2013 From: alex at crichton.co (Alex Crichton) Date: Thu, 14 Nov 2013 10:20:11 -0800 Subject: [rust-dev] Compiler hitting an unexpected failure path In-Reply-To: References: Message-ID: It looks like you're compiling a fairly old version of the compiler, I would recommend that you update to the master branch instead of using older copies (we're a fast-moving target right now!) On Thu, Nov 14, 2013 at 9:57 AM, tessy joseph wrote: > Hi > > I was trying to install RUST on my ubuntu local system.I could not complete > after make && make install.I also tried sudo make install.Both of them > failed .I got this note;Bug reported Compiler hitting unexpected failure > path > > https://gist.github.com/Tessie/7470406 > > Regards > Tessy > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > From kevin at sb.org Thu Nov 14 10:47:19 2013 From: kevin at sb.org (Kevin Ballard) Date: Thu, 14 Nov 2013 10:47:19 -0800 Subject: [rust-dev] library name libstd and libextra In-Reply-To: References: Message-ID: I was initially concerned, like you, about putting such generic-sounding libraries in /usr/local/lib, but of course that?s not the full name. On the current machine (whose rust is slightly out of date, so this may not match the name you have), libstd is actually /usr/local/lib/libstd-6c65cf4b443341b1-0.9-pre.dylib I?m not aware of any other system that adds hashes to library names like rust does, so it seems like a pretty good distinction without needing to namespace them or put ?rust? in the name. -Kevin On Nov 14, 2013, at 10:17 AM, Gaetan wrote: > I speak about the file names: /usr/local/lib/libstd... And /usr/local/lib/libextra > > Le jeudi 14 novembre 2013, Kevin Cantu a ?crit : > These standard libraries are already packaged for use and documented on the homepage. The import for std is implied, and for the second you just need this: > extern mod extra; > > Cheers, > Kevin > > > > On Thu, Nov 14, 2013 at 9:50 AM, Gaetan wrote: > > I have a question about the two files "libextra" and "libstd" that are installed by rust compiler. > > Can they be called by any normal average program? > > If so, shouldn't we document how? > If this has no sense, I suggest to rename them to something like "libruststd" or "librustextra" to avoid naming conflict with system libraries. We can also move to a subdirectory of /usr/lib, like /usr/lib/rust. > > What do you think about this? > ----- > Gaetan > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > > > > -- > ----- > Gaetan > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev -------------- next part -------------- An HTML attachment was scrubbed... URL: From oren at ben-kiki.org Thu Nov 14 10:53:09 2013 From: oren at ben-kiki.org (Oren Ben-Kiki) Date: Thu, 14 Nov 2013 20:53:09 +0200 Subject: [rust-dev] "Implementation Inheritance" / mixins In-Reply-To: References: <52814F8F.3020609@mozilla.com> <5281DC30.8040402@mozilla.com> <81B5FB1E-F1B2-4AF7-A12B-302C436887B5@sb.org> <52829BF8.3000200@mozilla.com> <52830794.3070504@mozilla.com> <129CF8DC-08FB-43B8-8A8B-985C254A5AEA@sb.org> <9859FE7A-3F11-4317-9491-6EEB4F4157AF@sb.org> Message-ID: I added https://github.com/mozilla/rust/issues/10491 which links to https://github.com/mozilla/rust/issues/9728 to propose that single inheritance can co-exist and be compatible with anonymous fields, achieving the best of both worlds. -------------- next part -------------- An HTML attachment was scrubbed... URL: From rusty.gates at icloud.com Thu Nov 14 11:05:40 2013 From: rusty.gates at icloud.com (Tommi) Date: Thu, 14 Nov 2013 21:05:40 +0200 Subject: [rust-dev] Built-in types should accept a pointer rhs-argument to binary operators In-Reply-To: <20131114165743.GC6546@Mr-Bennet> References: <20131114165743.GC6546@Mr-Bennet> Message-ID: <282AF5F5-3352-4F88-BCF9-FBF26DBA3B01@icloud.com> On 2013-11-14, at 18:57, Niko Matsakis wrote: > Basically, a binary operator like `l + r` is translated to something > similar to the following (which assumes universal function notation, > not yet implemented): > > Add::add(&l, &r) > > In other words, no autoderef or other transformation takes place. We > just look for a matching trait. Instead we just pass the values in by > reference. The reason for passing by reference is so that you can > compare linear types more naturally (i.e., `~[1, 2, 3]`). I'm sorry, I don't understand that last point. Can you explain why it makes those comparisons more natural. -Tommi From gaetan at xeberon.net Thu Nov 14 11:18:26 2013 From: gaetan at xeberon.net (Gaetan) Date: Thu, 14 Nov 2013 20:18:26 +0100 Subject: [rust-dev] Rust docs In-Reply-To: References: <5284E648.1000301@partner.samsung.com> Message-ID: do you have suggestion ? sphinx support for rust? It would require to switch to restructuredtext syntax ----- Gaetan 2013/11/14 Corey Richardson > We *do* do automatic generation. It uses the markdown in `doc`. > tutorial.md, and rust.md is the manual. > > On Thu, Nov 14, 2013 at 12:51 PM, Gaetan wrote: > > good :) > > > > so, what is missing to have an automatic generation of html page from a > > github page? > > > > ----- > > Gaetan > > > > > > > > 2013/11/14 Corey Richardson > >> > >> Travis could, but then anyone could (since the travis.yml is public > >> and it'd need credentials to the repo). We have a buildbot, > >> buildbot.rust-lang.org > >> > >> On Thu, Nov 14, 2013 at 12:39 PM, Gaetan wrote: > >> > do you have a buildbot or jenkins for the rust ? > >> > I don't think travis could push html pages to a remote repository, do > >> > it? > >> > > >> > ----- > >> > Gaetan > >> > > >> > > >> > > >> > 2013/11/14 Benjamin Striegel > >> >> > >> >> I would welcome such an effort, and suggest that it live as its own > >> >> project, outside of the Rust repo. We really aren't set up currently > to > >> >> handle rapid and frequent documentation changes. Once it gets to a > >> >> reasonable level of maturity we could then give it a mention from the > >> >> main > >> >> tutorial, and then once it's ready we could replace the current > >> >> tutorial > >> >> entirely. > >> >> > >> >> > >> >> On Thu, Nov 14, 2013 at 11:58 AM, Gaetan wrote: > >> >>> > >> >>> I would love helping on this matter, I'm use to setting up automatic > >> >>> documentation generation (rst, sphinx, doxygen,...). > >> >>> > >> >>> ----- > >> >>> Gaetan > >> >>> > >> >>> > >> >>> > >> >>> 2013/11/14 Philip Herron > >> >>>> > >> >>>> I would defineltly like to see a clone of the python tutorial > because > >> >>>> it > >> >>>> really does it so well going inch by inch building up what way > things > >> >>>> work i > >> >>>> am not a web developer but would love to write content i wonder is > it > >> >>>> possible to start a github project for this using sphinx i think it > >> >>>> uses > >> >>>> isn't it? > >> >>>> > >> >>>> > >> >>>> On 14 November 2013 15:38, Corey Richardson > wrote: > >> >>>>> > >> >>>>> On Thu, Nov 14, 2013 at 10:03 AM, Daniel Glazman > >> >>>>> wrote: > >> >>>>> > The Tutorial is the entry point for all people willing to > >> >>>>> > investigate > >> >>>>> > Rust and/or contribute to Servo. I think that document is super > >> >>>>> > precious, super-important. Unfortunately, I don't think it is > >> >>>>> > really > >> >>>>> > a > >> >>>>> > tutorial but only a lighter manual. Examples are here even more > >> >>>>> > important than in the case of the Manual above. A good Tutorial > is > >> >>>>> > often built around one single programming task that becomes more > >> >>>>> > and > >> >>>>> > more complex as more features of the language are read and > >> >>>>> > known. Furthermore, the Tutorial has clearly adopted the > language > >> >>>>> > complexity of the reference manual, something that I think > should > >> >>>>> > be > >> >>>>> > in general avoided. I also think all examples should be > buildable > >> >>>>> > and produce a readable result on the console even if that result > >> >>>>> > is a > >> >>>>> > build or execution error. That would drastically help the > reader. > >> >>>>> > > >> >>>>> > All in all, I think the Tutorial needs some love and probably a > >> >>>>> > technical writer who is not working on the guts of Rust, someone > >> >>>>> > who > >> >>>>> > could vulgarize the notions of the Manual into an easy-to-read, > >> >>>>> > simple-to-experiment, step-by-step tutorial and avoiding in > >> >>>>> > general > >> >>>>> > vocabulary inherited from programming language science. > >> >>>>> > > >> >>>>> > >> >>>>> I agree, partially. I think "Rust for Rubyists" fills this role > >> >>>>> quite > >> >>>>> well for now. Generally I think the language tutorial should not > >> >>>>> try > >> >>>>> to hide complexity or paper over things, at the very least so it > can > >> >>>>> be complete and correct. I think the Python tutorial is a good > >> >>>>> benchmark. We might even be able to rip off the Python tutorial's > >> >>>>> structure wholesale. > >> >>>>> > >> >>>>> The "on-boarding" process is still very rough. Maybe some sort of > >> >>>>> live-comment system would work well for finding pain points, where > >> >>>>> one > >> >>>>> can add comments/feedback while reading the tutorial. > >> >>>>> _______________________________________________ > >> >>>>> 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 > >> >>>> > >> >>> > >> >>> > >> >>> _______________________________________________ > >> >>> 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 > >> >> > >> > > >> > > >> > _______________________________________________ > >> > Rust-dev mailing list > >> > Rust-dev at mozilla.org > >> > https://mail.mozilla.org/listinfo/rust-dev > >> > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From denis.spir at gmail.com Thu Nov 14 11:24:46 2013 From: denis.spir at gmail.com (spir) Date: Thu, 14 Nov 2013 20:24:46 +0100 Subject: [rust-dev] Rust docs In-Reply-To: <5284E648.1000301@partner.samsung.com> References: <5284E648.1000301@partner.samsung.com> Message-ID: <5285237E.2030505@gmail.com> I completely share your views, Daniel. [Would have expressed them myself if I did not know (from experience) that constructive critics by me (in english) usually are mistaken or misunderstood: people just deny, argue, or reply violently. But you do a good job, here, in my opinion.] Denis On 11/14/2013 04:03 PM, Daniel Glazman wrote: > Hello rust-dev, > > I would like to make a comment I feel is important about both the Rust > tutorial and manual. Please don't misunderstand me, no flame here, I > am sending this message to help. I think good docs are extremely > important to increase the size of a community, and in particular make > more people contribute to Servo (the reason why I'm here). > > If the Reference Manual for Rust tries to be complete and does not try > to avoid language complexity, it can be from time to time hard to read > because of one thing: examples are not well or often enough explained > and are often too complex given the section they belong too. It's for > instance difficult for the reader to understand an example of section > n that uses notions explained only in section n+4. > > The Tutorial is the entry point for all people willing to investigate > Rust and/or contribute to Servo. I think that document is super > precious, super-important. Unfortunately, I don't think it is really a > tutorial but only a lighter manual. Examples are here even more > important than in the case of the Manual above. A good Tutorial is > often built around one single programming task that becomes more and > more complex as more features of the language are read and > known. Furthermore, the Tutorial has clearly adopted the language > complexity of the reference manual, something that I think should be > in general avoided. I also think all examples should be buildable > and produce a readable result on the console even if that result is a > build or execution error. That would drastically help the reader. > > All in all, I think the Tutorial needs some love and probably a > technical writer who is not working on the guts of Rust, someone who > could vulgarize the notions of the Manual into an easy-to-read, > simple-to-experiment, step-by-step tutorial and avoiding in general > vocabulary inherited from programming language science. > > Best regards, > > > _______________________________________________ > Rust-dev mailing list > R