[rust-dev] Possible bug? os::args() then split then print
Hello everyone, I might have found a bug. Ubuntu 12.04 LTS, rust master pulled a few hours ago. I've isolated my problem down to the following: fn main() { let arr : ~[str] = std::os::args()[1].split_str(::).collect(); std::io::println(first + arr[0]); std::io::println(first again + arr[0]); } $ rustc isolate_issue.rs $ ./isolate_issue foo::bar first fir first again non ascii char It looks like pointer corruption somewhere. Can somebody explain to me what is going on? Many thanks, Phil ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Breaking change: new Hash framework has landed
On 02/24/2014 10:15 PM, Erick Tryzelaar wrote: Brian: yes, at the moment `#[deriving(Hash)]` does support more than SipHash. However this PR temporarily removes that feature to replace `#[allow(default_type_param_usage)]` with `#[feature(default_type_params)]`: https://github.com/mozilla/rust/pull/12525 If we land that change, we could try two things. First, we could just turn on default_type_params permanently. Second, we could allow a syntax extension to check if a feature has been enabled in a crate. Brian, I know you were talking about this earlier on IRC, did you end up making a decision on what to do? I am hoping that somebody will prototype allocators before we turn default_type_params on permanently. György: Yep, there is. I went through approximately 13 iterations to converge on this design :) The reason why the `impl`'s need to know what kind of state they are dealing with is to support custom hashers. In most cases, people will want to compute a hash over the bytes of a value, so that value's hash impl needs to know that it can pass the value's bytes in with `state.write(...)`. Other values may actually have a hash baked into them, or want to use an integer value as a hash. These can just return the hash value by directly assigning the hash to the `*state` as I did in the example. While not cryptographically safe, this can be dramatically faster than using something like SipHash. Yet another value may want to use two completely different hashing algorithms depending depending on some property. Letting the `Hash`ee know about the state type allows for this level of flexibility. It also adds some type safety, in that it'll prevent you from accidentally passing a `Writer`-based hash state into a type that should only be used with a specific hasher. On Mon, Feb 24, 2014 at 9:35 PM, Niko Matsakis n...@alum.mit.edu mailto:n...@alum.mit.edu wrote: This looks very cool. On Mon, Feb 24, 2014 at 11:31:19AM -0500, Erick Tryzelaar wrote: I'm happy to announce that Rust's new hashing framework has landed in: https://github.com/mozilla/rust/pull/11863 https://github.com/mozilla/rust/pull/12492 This PR has has changed how to declare a type is hashable. Here's a full example on how to hash a value using either the new `#[deriving(Hash)]` or manual implementation. ``` use std::hash::{Hash, hash}; use std::hash::sip::SipState; #[deriving(Hash)] struct Foo { a: ~str, b: uint, c: bool, } struct Bar { a: ~str, b: uint, c: bool, } impl Hash for Bar { fn hash(self, state: mut SipState) { self.a.hash(state); self.b.hash(state); self.c.hash(state); } } fn main() { let foo = Foo { a: ~hello world, b: 5, c: true }; println!({}, hash(foo)); let bar = Bar { a: ~hello world, b: 5, c: true }; println!({}, hash(bar)); } ``` We also have experimental support for hashers that compute a value off a stream of bytes: ``` use std::hash::{Hash, Hasher}; use std::io::IoResult; #[deriving(Hash)] // automatically provides hashing from a stream of bytes struct Foo { a: ~str, b: uint, c: bool, } struct Bar { a: ~str, b: uint, c: bool, } #[allow(default_type_param_usage)] implS: Writer HashS for Bar { fn hash(self, state: mut S) { self.a.hash(state); self.b.hash(state); self.c.hash(state); } } struct SumState { sum: u64, } impl Writer for SumState { fn write(mut self, bytes: [u8]) - IoResult() { for byte in bytes.iter() { self.sum += *byte as u64; } Ok(()) } } struct SumHasher; #[allow(default_type_param_usage)] impl HasherSumState for SumHasher { fn hashT: HashSumState(self, value: T) - u64 { let mut state = SumState { sum: 0 }; value.hash(mut state); state.sum } } fn main() { let hasher = SumHasher; let foo = Foo { a: ~hello world, b: 5, c: true }; println!({}, hasher.hash(foo)); let bar = Bar { a: ~hello world, b: 5, c: true }; println!({}, hasher.hash(bar)); } ``` Finally, we also support completely custom hash computation: ``` use std::hash::{Hash, Hasher}; struct Foo { hash: u64 } #[allow(default_type_param_usage)] impl Hashu64 for Foo { fn hash(self, state: mut u64)
[rust-dev] How to import std::comm::select?
Hi everyone, Here with a novice question. I'm trying to use the select! macro in: http://static.rust-lang.org/doc/0.9/std/comm/select/index.html And can't figure out how to get it to import. My current code looks like this: use std::comm::select; fn main() { let (p,c): (Portint, Chanint) = Chan::new(); spawn(proc() { c.send(42); }); select! ( val = p.recv() = { print(val); } ); } However, `rustc testselect.rs` says error: macro undefined: 'select'. I've also tried use std::comm::* with feature(globs). Thanks for the help! Frank ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] How to import std::comm::select?
You can use the prototype through `std::comm::Select` for now, but the macro is not currently exported. See https://github.com/mozilla/rust/issues/12044 for more information. On Mon, Feb 24, 2014 at 10:59 PM, Frank Huang fyhu...@gmail.com wrote: Hi everyone, Here with a novice question. I'm trying to use the select! macro in: http://static.rust-lang.org/doc/0.9/std/comm/select/index.html And can't figure out how to get it to import. My current code looks like this: use std::comm::select; fn main() { let (p,c): (Portint, Chanint) = Chan::new(); spawn(proc() { c.send(42); }); select! ( val = p.recv() = { print(val); } ); } However, `rustc testselect.rs` says error: macro undefined: 'select'. I've also tried use std::comm::* with feature(globs). Thanks for the help! Frank ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] RFC: Stronger aliasing guarantees about mutable borrows
I wrote up an RFC. Posted on my blog at: http://smallcultfollowing.com/babysteps/blog/2014/02/25/rust-rfc-stronger-guarantees-for-mutable-borrows/ Inlined here: Today, if you do a mutable borrow of a local variable, you lose the ability to *write* to that variable except through the new reference you just created: let mut x = 3; let p = mut x; x += 1; // Error *p += 1; // OK However, you retain the ability to *read* the original variable: let mut x = 3; let p = mut x; print(x); // OK print(*p); // OK I would like to change the borrow checker rules so that both writes and reads through the original path `x` are illegal while `x` is mutably borrowed. This change is not motivated by soundness, as I believe the current rules are sound. Rather, the motivation is that this change gives strong guarantees to the holder of an `mut` pointer: at present, they can assume that an `mut` referent will not be changed by anyone else. With this change, they can also assume that an `mut` referent will not be read by anyone else. This enable more flexible borrowing rules and a more flexible kind of data parallelism API than what is possible today. It may also help to create more flexible rules around moves of borrowed data. As a side benefit, I personally think it also makes the borrow checker rules more consistent (mutable borrows mean original value is not usable during the mutable borrow, end of story). Let me lead with the motivation. ### Brief overview of my previous data-parallelism proposal In a previous post I outlined a plan for [data parallelism in Rust][dp] based on closure bounds. The rough idea is to leverage the checks that the borrow checker already does for segregating state into mutable-and-non-aliasable and immutable-but-aliasable. This is not only the recipe for creating memory safe programs, but it is also the recipe for data-race freedom: we can permit data to be shared between tasks, so long as it is immutable. The API that I outlined in that previous post was based on a `fork_join` function that took an array of closures. You would use it like this: fn sum(x: [int]) { if x.len() == 0 { return 0; } let mid = x.len() / 2; let mut left = 0; let mut right = 0; fork_join([ || left = sum(x.slice(0, mid)), || right = sum(x.slice(mid, x.len())), ]); return left + right; } The idea of `fork_join` was that it would (potentially) fork into N threads, one for each closure, and execute them in parallel. These closures may access and even mutate state from the containing scope -- the normal borrow checker rules will ensure that, if one closure mutates a variable, the other closures cannot read or write it. In this example, that means that the first closure can mutate `left` so long as the second closure doesn't touch it (and vice versa for `right`). Note that both closures share access to `x`, and this is fine because `x` is immutable. This kind of API isn't safe for all data though. There are things that cannot be shared in this way. One example is `Cell`, which is Rust's way of cheating the mutability rules and making a value that is *always* mutable. If we permitted two threads to touch the same `Cell`, they could both try to read and write it and, since `Cell` does not employ locks, this would not be race free. To avoid these sorts of cases, the closures that you pass to to `fork_join` would be *bounded* by the builtin trait `Share`. As I wrote in [issue 11781][share], the trait `Share` indicates data that is threadsafe when accessed through an `T` reference (i.e., when aliased). Most data is sharable (let `T` stand for some other sharable type): - POD (plain old data) types are forkable, so things like `int` etc. - `T` and `mut T`, because both are immutable when aliased. - `~T` is sharable, because is is not aliasable. - Structs and enums that are composed of sharable data are sharable. - `ARC`, because the reference count is maintained atomically. - The various thread-safe atomic integer intrinsics and so on. Things which are *not* sharable include: - Many types that are unsafely implemented: - `Cell` and `RefCell`, which have non-atomic interior mutability - `Rc`, which uses non-atomic reference counting - Managed data (`GcT`) because we do not wish to maintain or support a cross-thread garbage collector There is a wrinkle though. With the *current* borrow checker rules, forkable data is only safe to access from a parallel thread if the *main thread* is suspended. Put another way, forkable closures can only run concurrently with other forkable closures, but not with the parent, which might not be a forkable thing. This is reflected in the API, which consisted of a function `fork_join` function that both spawned the threads and joined them. The natural semantics of a function call would thus cause the parent to block
Re: [rust-dev] RFC: Stronger aliasing guarantees about mutable borrows
I'm in favor. I guess if there's some giant use case for the current mut then we could keep it and add this new version as move, but I agree that that probably isn't the case. On Tue, Feb 25, 2014 at 10:32 AM, Niko Matsakis n...@alum.mit.edu wrote: I wrote up an RFC. Posted on my blog at: http://smallcultfollowing.com/babysteps/blog/2014/02/25/rust-rfc-stronger-guarantees-for-mutable-borrows/ Inlined here: Today, if you do a mutable borrow of a local variable, you lose the ability to *write* to that variable except through the new reference you just created: let mut x = 3; let p = mut x; x += 1; // Error *p += 1; // OK However, you retain the ability to *read* the original variable: let mut x = 3; let p = mut x; print(x); // OK print(*p); // OK I would like to change the borrow checker rules so that both writes and reads through the original path `x` are illegal while `x` is mutably borrowed. This change is not motivated by soundness, as I believe the current rules are sound. Rather, the motivation is that this change gives strong guarantees to the holder of an `mut` pointer: at present, they can assume that an `mut` referent will not be changed by anyone else. With this change, they can also assume that an `mut` referent will not be read by anyone else. This enable more flexible borrowing rules and a more flexible kind of data parallelism API than what is possible today. It may also help to create more flexible rules around moves of borrowed data. As a side benefit, I personally think it also makes the borrow checker rules more consistent (mutable borrows mean original value is not usable during the mutable borrow, end of story). Let me lead with the motivation. ### Brief overview of my previous data-parallelism proposal In a previous post I outlined a plan for [data parallelism in Rust][dp] based on closure bounds. The rough idea is to leverage the checks that the borrow checker already does for segregating state into mutable-and-non-aliasable and immutable-but-aliasable. This is not only the recipe for creating memory safe programs, but it is also the recipe for data-race freedom: we can permit data to be shared between tasks, so long as it is immutable. The API that I outlined in that previous post was based on a `fork_join` function that took an array of closures. You would use it like this: fn sum(x: [int]) { if x.len() == 0 { return 0; } let mid = x.len() / 2; let mut left = 0; let mut right = 0; fork_join([ || left = sum(x.slice(0, mid)), || right = sum(x.slice(mid, x.len())), ]); return left + right; } The idea of `fork_join` was that it would (potentially) fork into N threads, one for each closure, and execute them in parallel. These closures may access and even mutate state from the containing scope -- the normal borrow checker rules will ensure that, if one closure mutates a variable, the other closures cannot read or write it. In this example, that means that the first closure can mutate `left` so long as the second closure doesn't touch it (and vice versa for `right`). Note that both closures share access to `x`, and this is fine because `x` is immutable. This kind of API isn't safe for all data though. There are things that cannot be shared in this way. One example is `Cell`, which is Rust's way of cheating the mutability rules and making a value that is *always* mutable. If we permitted two threads to touch the same `Cell`, they could both try to read and write it and, since `Cell` does not employ locks, this would not be race free. To avoid these sorts of cases, the closures that you pass to to `fork_join` would be *bounded* by the builtin trait `Share`. As I wrote in [issue 11781][share], the trait `Share` indicates data that is threadsafe when accessed through an `T` reference (i.e., when aliased). Most data is sharable (let `T` stand for some other sharable type): - POD (plain old data) types are forkable, so things like `int` etc. - `T` and `mut T`, because both are immutable when aliased. - `~T` is sharable, because is is not aliasable. - Structs and enums that are composed of sharable data are sharable. - `ARC`, because the reference count is maintained atomically. - The various thread-safe atomic integer intrinsics and so on. Things which are *not* sharable include: - Many types that are unsafely implemented: - `Cell` and `RefCell`, which have non-atomic interior mutability - `Rc`, which uses non-atomic reference counting - Managed data (`GcT`) because we do not wish to maintain or support a cross-thread garbage collector There is a wrinkle though. With the *current* borrow checker rules, forkable data is only safe to access from a parallel thread if the *main thread* is suspended. Put another way, forkable closures can
Re: [rust-dev] RFC: Stronger aliasing guarantees about mutable borrows
I'm all for it. In fact, I thought the proposed new rules *already* where the case :-) On 25.02.2014 19:32, Niko Matsakis wrote: I wrote up an RFC. Posted on my blog at: http://smallcultfollowing.com/babysteps/blog/2014/02/25/rust-rfc-stronger-guarantees-for-mutable-borrows/ Inlined here: Today, if you do a mutable borrow of a local variable, you lose the ability to *write* to that variable except through the new reference you just created: let mut x = 3; let p = mut x; x += 1; // Error *p += 1; // OK However, you retain the ability to *read* the original variable: let mut x = 3; let p = mut x; print(x); // OK print(*p); // OK I would like to change the borrow checker rules so that both writes and reads through the original path `x` are illegal while `x` is mutably borrowed. This change is not motivated by soundness, as I believe the current rules are sound. Rather, the motivation is that this change gives strong guarantees to the holder of an `mut` pointer: at present, they can assume that an `mut` referent will not be changed by anyone else. With this change, they can also assume that an `mut` referent will not be read by anyone else. This enable more flexible borrowing rules and a more flexible kind of data parallelism API than what is possible today. It may also help to create more flexible rules around moves of borrowed data. As a side benefit, I personally think it also makes the borrow checker rules more consistent (mutable borrows mean original value is not usable during the mutable borrow, end of story). Let me lead with the motivation. ### Brief overview of my previous data-parallelism proposal In a previous post I outlined a plan for [data parallelism in Rust][dp] based on closure bounds. The rough idea is to leverage the checks that the borrow checker already does for segregating state into mutable-and-non-aliasable and immutable-but-aliasable. This is not only the recipe for creating memory safe programs, but it is also the recipe for data-race freedom: we can permit data to be shared between tasks, so long as it is immutable. The API that I outlined in that previous post was based on a `fork_join` function that took an array of closures. You would use it like this: fn sum(x: [int]) { if x.len() == 0 { return 0; } let mid = x.len() / 2; let mut left = 0; let mut right = 0; fork_join([ || left = sum(x.slice(0, mid)), || right = sum(x.slice(mid, x.len())), ]); return left + right; } The idea of `fork_join` was that it would (potentially) fork into N threads, one for each closure, and execute them in parallel. These closures may access and even mutate state from the containing scope -- the normal borrow checker rules will ensure that, if one closure mutates a variable, the other closures cannot read or write it. In this example, that means that the first closure can mutate `left` so long as the second closure doesn't touch it (and vice versa for `right`). Note that both closures share access to `x`, and this is fine because `x` is immutable. This kind of API isn't safe for all data though. There are things that cannot be shared in this way. One example is `Cell`, which is Rust's way of cheating the mutability rules and making a value that is *always* mutable. If we permitted two threads to touch the same `Cell`, they could both try to read and write it and, since `Cell` does not employ locks, this would not be race free. To avoid these sorts of cases, the closures that you pass to to `fork_join` would be *bounded* by the builtin trait `Share`. As I wrote in [issue 11781][share], the trait `Share` indicates data that is threadsafe when accessed through an `T` reference (i.e., when aliased). Most data is sharable (let `T` stand for some other sharable type): - POD (plain old data) types are forkable, so things like `int` etc. - `T` and `mut T`, because both are immutable when aliased. - `~T` is sharable, because is is not aliasable. - Structs and enums that are composed of sharable data are sharable. - `ARC`, because the reference count is maintained atomically. - The various thread-safe atomic integer intrinsics and so on. Things which are *not* sharable include: - Many types that are unsafely implemented: - `Cell` and `RefCell`, which have non-atomic interior mutability - `Rc`, which uses non-atomic reference counting - Managed data (`GcT`) because we do not wish to maintain or support a cross-thread garbage collector There is a wrinkle though. With the *current* borrow checker rules, forkable data is only safe to access from a parallel thread if the *main thread* is suspended. Put another way, forkable closures can only run concurrently with other forkable closures, but not with the parent, which might not be a forkable thing. This is reflected in the API, which consisted
Re: [rust-dev] RFC: Stronger aliasing guarantees about mutable borrows
I too was under the impression that you could not read from a mutably-borrowed location. I am looking forward to the ability to move out of a mut (as long as the value is replaced again), if the issues around task failure and destructors can be solved. -Kevin On Feb 25, 2014, at 12:19 PM, Michael Woerister michaelwoeris...@posteo.de wrote: I'm all for it. In fact, I thought the proposed new rules *already* where the case :-) On 25.02.2014 19:32, Niko Matsakis wrote: I wrote up an RFC. Posted on my blog at: http://smallcultfollowing.com/babysteps/blog/2014/02/25/rust-rfc-stronger-guarantees-for-mutable-borrows/ Inlined here: Today, if you do a mutable borrow of a local variable, you lose the ability to *write* to that variable except through the new reference you just created: let mut x = 3; let p = mut x; x += 1; // Error *p += 1; // OK However, you retain the ability to *read* the original variable: let mut x = 3; let p = mut x; print(x); // OK print(*p); // OK I would like to change the borrow checker rules so that both writes and reads through the original path `x` are illegal while `x` is mutably borrowed. This change is not motivated by soundness, as I believe the current rules are sound. Rather, the motivation is that this change gives strong guarantees to the holder of an `mut` pointer: at present, they can assume that an `mut` referent will not be changed by anyone else. With this change, they can also assume that an `mut` referent will not be read by anyone else. This enable more flexible borrowing rules and a more flexible kind of data parallelism API than what is possible today. It may also help to create more flexible rules around moves of borrowed data. As a side benefit, I personally think it also makes the borrow checker rules more consistent (mutable borrows mean original value is not usable during the mutable borrow, end of story). Let me lead with the motivation. ### Brief overview of my previous data-parallelism proposal In a previous post I outlined a plan for [data parallelism in Rust][dp] based on closure bounds. The rough idea is to leverage the checks that the borrow checker already does for segregating state into mutable-and-non-aliasable and immutable-but-aliasable. This is not only the recipe for creating memory safe programs, but it is also the recipe for data-race freedom: we can permit data to be shared between tasks, so long as it is immutable. The API that I outlined in that previous post was based on a `fork_join` function that took an array of closures. You would use it like this: fn sum(x: [int]) { if x.len() == 0 { return 0; } let mid = x.len() / 2; let mut left = 0; let mut right = 0; fork_join([ || left = sum(x.slice(0, mid)), || right = sum(x.slice(mid, x.len())), ]); return left + right; } The idea of `fork_join` was that it would (potentially) fork into N threads, one for each closure, and execute them in parallel. These closures may access and even mutate state from the containing scope -- the normal borrow checker rules will ensure that, if one closure mutates a variable, the other closures cannot read or write it. In this example, that means that the first closure can mutate `left` so long as the second closure doesn't touch it (and vice versa for `right`). Note that both closures share access to `x`, and this is fine because `x` is immutable. This kind of API isn't safe for all data though. There are things that cannot be shared in this way. One example is `Cell`, which is Rust's way of cheating the mutability rules and making a value that is *always* mutable. If we permitted two threads to touch the same `Cell`, they could both try to read and write it and, since `Cell` does not employ locks, this would not be race free. To avoid these sorts of cases, the closures that you pass to to `fork_join` would be *bounded* by the builtin trait `Share`. As I wrote in [issue 11781][share], the trait `Share` indicates data that is threadsafe when accessed through an `T` reference (i.e., when aliased). Most data is sharable (let `T` stand for some other sharable type): - POD (plain old data) types are forkable, so things like `int` etc. - `T` and `mut T`, because both are immutable when aliased. - `~T` is sharable, because is is not aliasable. - Structs and enums that are composed of sharable data are sharable. - `ARC`, because the reference count is maintained atomically. - The various thread-safe atomic integer intrinsics and so on. Things which are *not* sharable include: - Many types that are unsafely implemented: - `Cell` and `RefCell`, which have non-atomic interior mutability - `Rc`, which uses non-atomic reference counting - Managed data (`GcT`) because we do not wish to
[rust-dev] RFC: Importing/exporting macros
Rust now has the ability to import macros from other crates, hurray! However, I'd like to propose adjusting the current way of using them to be more like importing/exporting other symbols of a crate. 1) It's more consistent, makes it easier to find where macros came from. 2) Current usage brings name collisions. Current example: pub mod foo { // assume other macros as well #[macro_export] macro_rules! bar ( ... ) } pub mod baz { // assume other macros as well #[macro_export] macro_rules! bar ( ... ) } mod herp { // i want bar! from foo, and some other macros from baz [phase(syntax)] use super::foo; [phase(syntax)] use super::baz; pub Derp = bar!(); // which bar? is this an ICE? or logic error? } Proposed example: pub mod foo { pub marco_rules! bar ( ... ); } pub mod baz { pub marco_rules! bar ( ... ); pub marco_rules! quux ( ... ); } mod herp { use super::foo::bar!; use super::baz::quux!; // using same name macros, no problem use baz! = super::baz::bar!; pub Derp = bar!(baz!()); } ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Stronger aliasing guarantees about mutable borrows
Me three. I thought the last of this reading-while-mut was excised with the removal of @mut. If you think you might like to implement this change, though, let me know. =) Given generous amounts of hand-holding, I might give it a shot. On Tue, Feb 25, 2014 at 10:23 PM, Kevin Ballard ke...@sb.org wrote: I too was under the impression that you could not read from a mutably-borrowed location. I am looking forward to the ability to move out of a mut (as long as the value is replaced again), if the issues around task failure and destructors can be solved. -Kevin On Feb 25, 2014, at 12:19 PM, Michael Woerister michaelwoeris...@posteo.de wrote: I'm all for it. In fact, I thought the proposed new rules *already* where the case :-) On 25.02.2014 19:32, Niko Matsakis wrote: I wrote up an RFC. Posted on my blog at: http://smallcultfollowing.com/babysteps/blog/2014/02/25/rust-rfc-stronger-guarantees-for-mutable-borrows/ Inlined here: Today, if you do a mutable borrow of a local variable, you lose the ability to *write* to that variable except through the new reference you just created: let mut x = 3; let p = mut x; x += 1; // Error *p += 1; // OK However, you retain the ability to *read* the original variable: let mut x = 3; let p = mut x; print(x); // OK print(*p); // OK I would like to change the borrow checker rules so that both writes and reads through the original path `x` are illegal while `x` is mutably borrowed. This change is not motivated by soundness, as I believe the current rules are sound. Rather, the motivation is that this change gives strong guarantees to the holder of an `mut` pointer: at present, they can assume that an `mut` referent will not be changed by anyone else. With this change, they can also assume that an `mut` referent will not be read by anyone else. This enable more flexible borrowing rules and a more flexible kind of data parallelism API than what is possible today. It may also help to create more flexible rules around moves of borrowed data. As a side benefit, I personally think it also makes the borrow checker rules more consistent (mutable borrows mean original value is not usable during the mutable borrow, end of story). Let me lead with the motivation. ### Brief overview of my previous data-parallelism proposal In a previous post I outlined a plan for [data parallelism in Rust][dp] based on closure bounds. The rough idea is to leverage the checks that the borrow checker already does for segregating state into mutable-and-non-aliasable and immutable-but-aliasable. This is not only the recipe for creating memory safe programs, but it is also the recipe for data-race freedom: we can permit data to be shared between tasks, so long as it is immutable. The API that I outlined in that previous post was based on a `fork_join` function that took an array of closures. You would use it like this: fn sum(x: [int]) { if x.len() == 0 { return 0; } let mid = x.len() / 2; let mut left = 0; let mut right = 0; fork_join([ || left = sum(x.slice(0, mid)), || right = sum(x.slice(mid, x.len())), ]); return left + right; } The idea of `fork_join` was that it would (potentially) fork into N threads, one for each closure, and execute them in parallel. These closures may access and even mutate state from the containing scope -- the normal borrow checker rules will ensure that, if one closure mutates a variable, the other closures cannot read or write it. In this example, that means that the first closure can mutate `left` so long as the second closure doesn't touch it (and vice versa for `right`). Note that both closures share access to `x`, and this is fine because `x` is immutable. This kind of API isn't safe for all data though. There are things that cannot be shared in this way. One example is `Cell`, which is Rust's way of cheating the mutability rules and making a value that is *always* mutable. If we permitted two threads to touch the same `Cell`, they could both try to read and write it and, since `Cell` does not employ locks, this would not be race free. To avoid these sorts of cases, the closures that you pass to to `fork_join` would be *bounded* by the builtin trait `Share`. As I wrote in [issue 11781][share], the trait `Share` indicates data that is threadsafe when accessed through an `T` reference (i.e., when aliased). Most data is sharable (let `T` stand for some other sharable type): - POD (plain old data) types are forkable, so things like `int` etc. - `T` and `mut T`, because both are immutable when aliased. - `~T` is sharable, because is is not aliasable. - Structs and enums that are composed of sharable data are
Re: [rust-dev] RFC: Importing/exporting macros
This is problematic because name resolutions happens far after macro expansion. I think this could be doable with an extremely limited macro module system, but I think it's not-very-good to have the same path syntax for two incredibly different systems. On Tue, Feb 25, 2014 at 4:39 PM, Sean McArthur smcart...@mozilla.com wrote: Rust now has the ability to import macros from other crates, hurray! However, I'd like to propose adjusting the current way of using them to be more like importing/exporting other symbols of a crate. 1) It's more consistent, makes it easier to find where macros came from. 2) Current usage brings name collisions. Current example: pub mod foo { // assume other macros as well #[macro_export] macro_rules! bar ( ... ) } pub mod baz { // assume other macros as well #[macro_export] macro_rules! bar ( ... ) } mod herp { // i want bar! from foo, and some other macros from baz [phase(syntax)] use super::foo; [phase(syntax)] use super::baz; pub Derp = bar!(); // which bar? is this an ICE? or logic error? } Proposed example: pub mod foo { pub marco_rules! bar ( ... ); } pub mod baz { pub marco_rules! bar ( ... ); pub marco_rules! quux ( ... ); } mod herp { use super::foo::bar!; use super::baz::quux!; // using same name macros, no problem use baz! = super::baz::bar!; pub Derp = bar!(baz!()); } ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Stronger aliasing guarantees about mutable borrows
Is this not already expressible with swap/replace? Is there a big improvement here that I'm missing? On Tue, Feb 25, 2014 at 4:23 PM, Kevin Ballard ke...@sb.org wrote: I too was under the impression that you could not read from a mutably-borrowed location. I am looking forward to the ability to move out of a mut (as long as the value is replaced again), if the issues around task failure and destructors can be solved. -Kevin On Feb 25, 2014, at 12:19 PM, Michael Woerister michaelwoeris...@posteo.de wrote: I'm all for it. In fact, I thought the proposed new rules *already* where the case :-) On 25.02.2014 19:32, Niko Matsakis wrote: I wrote up an RFC. Posted on my blog at: http://smallcultfollowing.com/babysteps/blog/2014/02/25/rust-rfc-stronger-guarantees-for-mutable-borrows/ Inlined here: Today, if you do a mutable borrow of a local variable, you lose the ability to *write* to that variable except through the new reference you just created: let mut x = 3; let p = mut x; x += 1; // Error *p += 1; // OK However, you retain the ability to *read* the original variable: let mut x = 3; let p = mut x; print(x); // OK print(*p); // OK I would like to change the borrow checker rules so that both writes and reads through the original path `x` are illegal while `x` is mutably borrowed. This change is not motivated by soundness, as I believe the current rules are sound. Rather, the motivation is that this change gives strong guarantees to the holder of an `mut` pointer: at present, they can assume that an `mut` referent will not be changed by anyone else. With this change, they can also assume that an `mut` referent will not be read by anyone else. This enable more flexible borrowing rules and a more flexible kind of data parallelism API than what is possible today. It may also help to create more flexible rules around moves of borrowed data. As a side benefit, I personally think it also makes the borrow checker rules more consistent (mutable borrows mean original value is not usable during the mutable borrow, end of story). Let me lead with the motivation. ### Brief overview of my previous data-parallelism proposal In a previous post I outlined a plan for [data parallelism in Rust][dp] based on closure bounds. The rough idea is to leverage the checks that the borrow checker already does for segregating state into mutable-and-non-aliasable and immutable-but-aliasable. This is not only the recipe for creating memory safe programs, but it is also the recipe for data-race freedom: we can permit data to be shared between tasks, so long as it is immutable. The API that I outlined in that previous post was based on a `fork_join` function that took an array of closures. You would use it like this: fn sum(x: [int]) { if x.len() == 0 { return 0; } let mid = x.len() / 2; let mut left = 0; let mut right = 0; fork_join([ || left = sum(x.slice(0, mid)), || right = sum(x.slice(mid, x.len())), ]); return left + right; } The idea of `fork_join` was that it would (potentially) fork into N threads, one for each closure, and execute them in parallel. These closures may access and even mutate state from the containing scope -- the normal borrow checker rules will ensure that, if one closure mutates a variable, the other closures cannot read or write it. In this example, that means that the first closure can mutate `left` so long as the second closure doesn't touch it (and vice versa for `right`). Note that both closures share access to `x`, and this is fine because `x` is immutable. This kind of API isn't safe for all data though. There are things that cannot be shared in this way. One example is `Cell`, which is Rust's way of cheating the mutability rules and making a value that is *always* mutable. If we permitted two threads to touch the same `Cell`, they could both try to read and write it and, since `Cell` does not employ locks, this would not be race free. To avoid these sorts of cases, the closures that you pass to to `fork_join` would be *bounded* by the builtin trait `Share`. As I wrote in [issue 11781][share], the trait `Share` indicates data that is threadsafe when accessed through an `T` reference (i.e., when aliased). Most data is sharable (let `T` stand for some other sharable type): - POD (plain old data) types are forkable, so things like `int` etc. - `T` and `mut T`, because both are immutable when aliased. - `~T` is sharable, because is is not aliasable. - Structs and enums that are composed of sharable data are sharable. - `ARC`, because the reference count is maintained atomically. - The various thread-safe atomic integer intrinsics and so on. Things which are *not* sharable include: - Many types that are unsafely implemented: - `Cell`
Re: [rust-dev] RFC: Stronger aliasing guarantees about mutable borrows
If you can construct the new value independently of the old, sure. But if constructing the new value requires consuming the old, then you can't. -Kevin On Feb 25, 2014, at 3:14 PM, Corey Richardson co...@octayn.net wrote: Is this not already expressible with swap/replace? Is there a big improvement here that I'm missing? On Tue, Feb 25, 2014 at 4:23 PM, Kevin Ballard ke...@sb.org wrote: I too was under the impression that you could not read from a mutably-borrowed location. I am looking forward to the ability to move out of a mut (as long as the value is replaced again), if the issues around task failure and destructors can be solved. -Kevin On Feb 25, 2014, at 12:19 PM, Michael Woerister michaelwoeris...@posteo.de wrote: I'm all for it. In fact, I thought the proposed new rules *already* where the case :-) On 25.02.2014 19:32, Niko Matsakis wrote: I wrote up an RFC. Posted on my blog at: http://smallcultfollowing.com/babysteps/blog/2014/02/25/rust-rfc-stronger-guarantees-for-mutable-borrows/ Inlined here: Today, if you do a mutable borrow of a local variable, you lose the ability to *write* to that variable except through the new reference you just created: let mut x = 3; let p = mut x; x += 1; // Error *p += 1; // OK However, you retain the ability to *read* the original variable: let mut x = 3; let p = mut x; print(x); // OK print(*p); // OK I would like to change the borrow checker rules so that both writes and reads through the original path `x` are illegal while `x` is mutably borrowed. This change is not motivated by soundness, as I believe the current rules are sound. Rather, the motivation is that this change gives strong guarantees to the holder of an `mut` pointer: at present, they can assume that an `mut` referent will not be changed by anyone else. With this change, they can also assume that an `mut` referent will not be read by anyone else. This enable more flexible borrowing rules and a more flexible kind of data parallelism API than what is possible today. It may also help to create more flexible rules around moves of borrowed data. As a side benefit, I personally think it also makes the borrow checker rules more consistent (mutable borrows mean original value is not usable during the mutable borrow, end of story). Let me lead with the motivation. ### Brief overview of my previous data-parallelism proposal In a previous post I outlined a plan for [data parallelism in Rust][dp] based on closure bounds. The rough idea is to leverage the checks that the borrow checker already does for segregating state into mutable-and-non-aliasable and immutable-but-aliasable. This is not only the recipe for creating memory safe programs, but it is also the recipe for data-race freedom: we can permit data to be shared between tasks, so long as it is immutable. The API that I outlined in that previous post was based on a `fork_join` function that took an array of closures. You would use it like this: fn sum(x: [int]) { if x.len() == 0 { return 0; } let mid = x.len() / 2; let mut left = 0; let mut right = 0; fork_join([ || left = sum(x.slice(0, mid)), || right = sum(x.slice(mid, x.len())), ]); return left + right; } The idea of `fork_join` was that it would (potentially) fork into N threads, one for each closure, and execute them in parallel. These closures may access and even mutate state from the containing scope -- the normal borrow checker rules will ensure that, if one closure mutates a variable, the other closures cannot read or write it. In this example, that means that the first closure can mutate `left` so long as the second closure doesn't touch it (and vice versa for `right`). Note that both closures share access to `x`, and this is fine because `x` is immutable. This kind of API isn't safe for all data though. There are things that cannot be shared in this way. One example is `Cell`, which is Rust's way of cheating the mutability rules and making a value that is *always* mutable. If we permitted two threads to touch the same `Cell`, they could both try to read and write it and, since `Cell` does not employ locks, this would not be race free. To avoid these sorts of cases, the closures that you pass to to `fork_join` would be *bounded* by the builtin trait `Share`. As I wrote in [issue 11781][share], the trait `Share` indicates data that is threadsafe when accessed through an `T` reference (i.e., when aliased). Most data is sharable (let `T` stand for some other sharable type): - POD (plain old data) types are forkable, so things like `int` etc. - `T` and `mut T`, because both are immutable when aliased. - `~T` is sharable, because is is not aliasable. - Structs and enums that are composed of sharable data are sharable. -
Re: [rust-dev] RFC: Stronger aliasing guarantees about mutable borrows
Well, you can if you can construct a dummy value to swap in temporarily. I'm pretty sure that's not always possible without venturing into unsafe code (like making an uninit block of the proper size or something). Moreover, nothing stops you from forgetting to swap the value back in so you could just leave the dummy value in there. Finally, it's just way nicer to write than the swap/replace version. Would a mut that could move enable us to write insertion into a growable data structure that might reallocate itself without unsafe code? Something like OwnedVector.push() for instance. On Tue, Feb 25, 2014 at 3:18 PM, Kevin Ballard ke...@sb.org wrote: If you can construct the new value independently of the old, sure. But if constructing the new value requires consuming the old, then you can't. -Kevin On Feb 25, 2014, at 3:14 PM, Corey Richardson co...@octayn.net wrote: Is this not already expressible with swap/replace? Is there a big improvement here that I'm missing? On Tue, Feb 25, 2014 at 4:23 PM, Kevin Ballard ke...@sb.org wrote: I too was under the impression that you could not read from a mutably-borrowed location. I am looking forward to the ability to move out of a mut (as long as the value is replaced again), if the issues around task failure and destructors can be solved. -Kevin On Feb 25, 2014, at 12:19 PM, Michael Woerister michaelwoeris...@posteo.de wrote: I'm all for it. In fact, I thought the proposed new rules *already* where the case :-) On 25.02.2014 19:32, Niko Matsakis wrote: I wrote up an RFC. Posted on my blog at: http://smallcultfollowing.com/babysteps/blog/2014/02/25/rust-rfc-stronger-guarantees-for-mutable-borrows/ Inlined here: Today, if you do a mutable borrow of a local variable, you lose the ability to *write* to that variable except through the new reference you just created: let mut x = 3; let p = mut x; x += 1; // Error *p += 1; // OK However, you retain the ability to *read* the original variable: let mut x = 3; let p = mut x; print(x); // OK print(*p); // OK I would like to change the borrow checker rules so that both writes and reads through the original path `x` are illegal while `x` is mutably borrowed. This change is not motivated by soundness, as I believe the current rules are sound. Rather, the motivation is that this change gives strong guarantees to the holder of an `mut` pointer: at present, they can assume that an `mut` referent will not be changed by anyone else. With this change, they can also assume that an `mut` referent will not be read by anyone else. This enable more flexible borrowing rules and a more flexible kind of data parallelism API than what is possible today. It may also help to create more flexible rules around moves of borrowed data. As a side benefit, I personally think it also makes the borrow checker rules more consistent (mutable borrows mean original value is not usable during the mutable borrow, end of story). Let me lead with the motivation. ### Brief overview of my previous data-parallelism proposal In a previous post I outlined a plan for [data parallelism in Rust][dp] based on closure bounds. The rough idea is to leverage the checks that the borrow checker already does for segregating state into mutable-and-non-aliasable and immutable-but-aliasable. This is not only the recipe for creating memory safe programs, but it is also the recipe for data-race freedom: we can permit data to be shared between tasks, so long as it is immutable. The API that I outlined in that previous post was based on a `fork_join` function that took an array of closures. You would use it like this: fn sum(x: [int]) { if x.len() == 0 { return 0; } let mid = x.len() / 2; let mut left = 0; let mut right = 0; fork_join([ || left = sum(x.slice(0, mid)), || right = sum(x.slice(mid, x.len())), ]); return left + right; } The idea of `fork_join` was that it would (potentially) fork into N threads, one for each closure, and execute them in parallel. These closures may access and even mutate state from the containing scope -- the normal borrow checker rules will ensure that, if one closure mutates a variable, the other closures cannot read or write it. In this example, that means that the first closure can mutate `left` so long as the second closure doesn't touch it (and vice versa for `right`). Note that both closures share access to `x`, and this is fine because `x` is immutable. This kind of API isn't safe for all data though. There are things that cannot be shared in this way. One example is `Cell`, which is Rust's way of cheating the mutability rules and making a value that is *always* mutable. If we permitted two threads to touch
Re: [rust-dev] RFC: Stronger aliasing guarantees about mutable borrows
On Feb 25, 2014, at 4:04 PM, Eric Reed ecr...@cs.washington.edu wrote: Would a mut that could move enable us to write insertion into a growable data structure that might reallocate itself without unsafe code? Something like OwnedVector.push() for instance. The problem with that is you need uninitialized memory that you can move in to (without running drop glue). I don't see how moving from mut will help. Even if rustc can avoid the drop glue when writing to a mut that it already moved out of, there's no way to construct a pre-moved mut that points to the uninitialized memory (and no way to even create uninitialized memory without unsafe). -Kevin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Stronger aliasing guarantees about mutable borrows
True. I guess I was thinking less unsafe code as opposed to no unsafe code. On Tue, Feb 25, 2014 at 4:47 PM, Kevin Ballard ke...@sb.org wrote: On Feb 25, 2014, at 4:04 PM, Eric Reed ecr...@cs.washington.edu wrote: Would a mut that could move enable us to write insertion into a growable data structure that might reallocate itself without unsafe code? Something like OwnedVector.push() for instance. The problem with that is you need uninitialized memory that you can move in to (without running drop glue). I don't see how moving from mut will help. Even if rustc can avoid the drop glue when writing to a mut that it already moved out of, there's no way to construct a pre-moved mut that points to the uninitialized memory (and no way to even create uninitialized memory without unsafe). -Kevin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Alternative to Option types
Hey, I’m not sure how people feel about Option types but there seem to be a few hundred uses in the rust codebase. Wanted to share an idea we use in our custom type system (“Hack”) at Facebook to make it a bit nicer to safely deal with null references. We don’t use Option types directly. I don’t think this adds any theoretical power or new possible efficiency gains, it’s mostly for making the code a bit simpler. Type declarations prefixed with a question mark represent references which might be null. So ‘?Foo' is somewhat like a shorthand for 'OptionFoo’. function demo(?Car $maybe_car, Car $car) {…} We use these like possibly-null pointers. Usually you write an if statement prior to using a value. function demo(?Car $maybe_car, Car $car) { $car-start(); if($maybe_car) { $maybe_car-start(); } } Sometimes we use these in combination with a special function “invariant, an assertion function that throws an exception if a condition is not met: function demo(?Car $car) { invariant($car, ‘Expected non-null car for the demo’); $car-start(); } If you forget to check for null one way or the other, the type-checker complains. This is a static, ahead-of-time check. function demo(?Car $car) { $car-start(); // error } There are some natural annoying edge cases to be covered. class Smash { private ?Car $car; function demo() { if ($this-car) { $this-smashCar(); $this-car-start(); // error } } } A downside of this approach vs. Option is that code written using pattern matching over Option is more easily upgraded to code using pattern matching over Result (or something else). Anyway, we like this feature and I’d be happy to see it adopted elsewhere. Tossing it out there as I don’t know anything about the Rust compiler or how language design decisions get made for it :) -Aran ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Alternative to Option types
I, for one, would really like to see rust steal named and optional arguments from OCaml. They're a huge boon to code readability. On Tue, Feb 25, 2014 at 10:24 PM, Aran Donohue a...@fb.com wrote: Hey, I’m not sure how people feel about Option types but there seem to be a few hundred uses in the rust codebase. Wanted to share an idea we use in our custom type system (“Hack”) at Facebook to make it a bit nicer to safely deal with null references. We don’t use Option types directly. I don’t think this adds any theoretical power or new possible efficiency gains, it’s mostly for making the code a bit simpler. Type declarations prefixed with a question mark represent references which might be null. So ‘?Foo' is somewhat like a shorthand for 'OptionFoo’. function demo(?Car $maybe_car, Car $car) {…} We use these like possibly-null pointers. Usually you write an if statement prior to using a value. function demo(?Car $maybe_car, Car $car) { $car-start(); if($maybe_car) { $maybe_car-start(); } } Sometimes we use these in combination with a special function “invariant, an assertion function that throws an exception if a condition is not met: function demo(?Car $car) { invariant($car, ‘Expected non-null car for the demo’); $car-start(); } If you forget to check for null one way or the other, the type-checker complains. This is a static, ahead-of-time check. function demo(?Car $car) { $car-start(); // error } There are some natural annoying edge cases to be covered. class Smash { private ?Car $car; function demo() { if ($this-car) { $this-smashCar(); $this-car-start(); // error } } } A downside of this approach vs. Option is that code written using pattern matching over Option is more easily upgraded to code using pattern matching over Result (or something else). Anyway, we like this feature and I’d be happy to see it adopted elsewhere. Tossing it out there as I don’t know anything about the Rust compiler or how language design decisions get made for it :) -Aran ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev -- Clark. Key ID : 0x78099922 Fingerprint: B292 493C 51AE F3AB D016 DD04 E5E3 C36F 5534 F907 ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Possible bug? os::args() then split then print
On Tue, Feb 25, 2014 at 11:00 AM, Phil Dawes rustp...@phildawes.net wrote: fn main() { let arr : ~[str] = std::os::args()[1].split_str(::).collect(); std::io::println(first + arr[0]); std::io::println(first again + arr[0]); } I am working on an older version of the compiler that fails to compile this code, giving an error about the reference to the return value of std::os::args() not being valid for the duration of its use. Does let args = std::os::args(); let arr : ~[str] = args[1].split_str(::).collect(); work properly? Ashish ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Alternative to Option types
Turns out Rust's Option type already has all this behavior, so I think we're all on to something :) Option is a little more powerful than nullable pointers because you can have Options of non-pointer values. IIRC, Option~T is actually compressed to be a nullable pointer. I actually really like the ?T syntax, but I'm not sure it's worth special-casing Options. I think it's something macros could handle (convert ?T into OptionT). Like your Hack type system, Rust's type system stops you from using an OptionT in place of a T (they are different types after all). The basic way to convert is a match expression, which is equivalent to: if($maybe_car) { /* Some / non-null case here */ } else { /* None / null case here */ } Leaving the else branch off, i.e. leaving None as None, actually corresponds to either functorial map (Option.map) or monadic bind (Option.and_then) depending on the return type of Some branch. So your example could become: fn demo(maybe_car: Optionmut Car, car: mut Car) { car.start(); maybe_car.map(|car| car.start()); // ignore the resulting option } Rust's Option has it's own version of your invariant function: Option.expect. If the Option is Some, then it returns the value therein. If the Option is None, then it fails and displays a message. Option.unwrap is the same, but with a default message. fn demo(car: Optionmut Car) { let car = car.expect(Expected non-null car for the demo); car.start(); } Your edge case presents an interesting difference between Hack and Rust. In Hack, you know $car is non-null inside the if's consequent, but $car is *still* a nullable pointer ?Car. In Rust, you know car is non-null in the Some branch of a match, but it's not an OptionCar anymore! It's just a Car, so a smashCar method either isn't applicable (it's a method on OptionCars) or it creates a new OptionCar for us and sets it to None (an example of a monadic function for Option). In the later case, we'd use .and_then() to call smashCar and then chain the start call with .map(). The .map() call would safely evaluate to None. Thanks for the input! On Tue, Feb 25, 2014 at 7:24 PM, Aran Donohue a...@fb.com wrote: Hey, I'm not sure how people feel about Option types but there seem to be a few hundred uses in the rust codebase. Wanted to share an idea we use in our custom type system (Hack) at Facebook to make it a bit nicer to safely deal with null references. We don't use Option types directly. I don't think this adds any theoretical power or new possible efficiency gains, it's mostly for making the code a bit simpler. Type declarations prefixed with a question mark represent references which might be null. So '?Foo' is somewhat like a shorthand for 'OptionFoo'. function demo(?Car $maybe_car, Car $car) {...} We use these like possibly-null pointers. Usually you write an if statement prior to using a value. function demo(?Car $maybe_car, Car $car) { $car-start(); if($maybe_car) { $maybe_car-start(); } } Sometimes we use these in combination with a special function invariant, an assertion function that throws an exception if a condition is not met: function demo(?Car $car) { invariant($car, 'Expected non-null car for the demo'); $car-start(); } If you forget to check for null one way or the other, the type-checker complains. This is a static, ahead-of-time check. function demo(?Car $car) { $car-start(); // error } There are some natural annoying edge cases to be covered. class Smash { private ?Car $car; function demo() { if ($this-car) { $this-smashCar(); $this-car-start(); // error } } } A downside of this approach vs. Option is that code written using pattern matching over Option is more easily upgraded to code using pattern matching over Result (or something else). Anyway, we like this feature and I'd be happy to see it adopted elsewhere. Tossing it out there as I don't know anything about the Rust compiler or how language design decisions get made for it :) -Aran ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Alternative to Option types
Turns out Option.and_then is literally Option's monadic bind. Both do-notation and Haskell's list comprehensions (which generalize to monads and I think are equivalent to Scala's for-comprehensions) actually just desugar into calls to the monad's bind and return functions (Option's return is just |x| Some(x) in Rust). I'm fairly certain Rust's macros can handle both notational forms. In general, monads require higher-kinded types because for a type to be a monad it must take a type variable. That is, OptionT and ListT could be monads, but int and TcpSocket can't be monads. So imagine we wanted to define a trait Monad in Rust. It'd look something like: trait MonadT { fn return(t: T) - SelfT; fn bindU(mt: SelfT, f: |T| - SelfU) - SelfU; } Notice how Self takes a type parameter? That's not legal in current Rust. We'd need to make sure that types implemented Monad take the right number of type variables. This is where 'kinds' come in. Kinds are to types as types are to values. Concrete types (those that don't take parameters) have kind *. A type that has one type variable has kind * - *, and so on. Kinds like * - * are called 'higher-kinds' and the types with those kinds are 'higher-kinded' types. Turns out Monad requires types of kind * - *. That's why Rust can't have general monads until we add higher kinded types. On Tue, Feb 25, 2014 at 8:01 PM, Ziad Hatahet hata...@gmail.com wrote: On Tue, Feb 25, 2014 at 7:24 PM, Aran Donohue a...@fb.com wrote: Anyway, we like this feature and I'd be happy to see it adopted elsewhere. There are few languages out there that take an approach like this, including Kotlin and Fantom. I agree it is a cool feature; however, the Option type is more general, and pattern matching is not the only way to deal with Option variables. map/map_or, and/and_then, or/or_else are some of the methods that can be called on Option in Rust, while still avoiding pattern matching. Referring to your `demo` function: // Rust syntax fn demo(c: Car, maybe_car: OptionCar) { c.start() maybe_car.map(|car| car.start()); } I am personally in favor of having something like Scala's monadic `for` construct. Apparently this feature needs Higher Kinded Types to be implemented in the compiler first. There has been a couple of Rust macro implementations that offer a stop gap though: https://mail.mozilla.org/pipermail/rust-dev/2013-May/004176.html -- Ziad ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Possible bug? os::args() then split then print
Hi Ashish, Yes that works fine. Splitting out 'args' into a separate variable fixes the behaviour. So this is a lifetime issue and the latest compiler isn't picking it up? Thanks, Phil On Wed, Feb 26, 2014 at 4:23 AM, Ashish Myles marci...@gmail.com wrote: On Tue, Feb 25, 2014 at 11:00 AM, Phil Dawes rustp...@phildawes.netwrote: fn main() { let arr : ~[str] = std::os::args()[1].split_str(::).collect(); std::io::println(first + arr[0]); std::io::println(first again + arr[0]); } I am working on an older version of the compiler that fails to compile this code, giving an error about the reference to the return value of std::os::args() not being valid for the duration of its use. Does let args = std::os::args(); let arr : ~[str] = args[1].split_str(::).collect(); work properly? Ashish ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Possible bug? os::args() then split then print
This definitely seems to be a bug. If you can, you should file this at https://github.com/mozilla/rust/issues. -Kevin On Feb 25, 2014, at 10:12 PM, Phil Dawes rustp...@phildawes.net wrote: Hi Ashish, Yes that works fine. Splitting out 'args' into a separate variable fixes the behaviour. So this is a lifetime issue and the latest compiler isn't picking it up? Thanks, Phil On Wed, Feb 26, 2014 at 4:23 AM, Ashish Myles marci...@gmail.com wrote: On Tue, Feb 25, 2014 at 11:00 AM, Phil Dawes rustp...@phildawes.net wrote: fn main() { let arr : ~[str] = std::os::args()[1].split_str(::).collect(); std::io::println(first + arr[0]); std::io::println(first again + arr[0]); } I am working on an older version of the compiler that fails to compile this code, giving an error about the reference to the return value of std::os::args() not being valid for the duration of its use. Does let args = std::os::args(); let arr : ~[str] = args[1].split_str(::).collect(); work properly? Ashish ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev smime.p7s Description: S/MIME cryptographic signature ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Importing/exporting macros
Agreed. Exporting macros feels like a hack. Importing macros feels like a hack. Global namespaces are a pain. Macros on the whole feel like a second class citizen of the language. I’m not talking about writing them - I’m perfectly fine about that kind of ugliness – I’m referring to the client side usability. I would steer clear from forcing them on the users of my libraries. ~Brendan On 26 Feb 2014, at 8:39 am, Sean McArthur smcart...@mozilla.com wrote: Rust now has the ability to import macros from other crates, hurray! However, I'd like to propose adjusting the current way of using them to be more like importing/exporting other symbols of a crate. 1) It's more consistent, makes it easier to find where macros came from. 2) Current usage brings name collisions. Current example: pub mod foo { // assume other macros as well #[macro_export] macro_rules! bar ( ... ) } pub mod baz { // assume other macros as well #[macro_export] macro_rules! bar ( ... ) } mod herp { // i want bar! from foo, and some other macros from baz [phase(syntax)] use super::foo; [phase(syntax)] use super::baz; pub Derp = bar!(); // which bar? is this an ICE? or logic error? } Proposed example: pub mod foo { pub marco_rules! bar ( ... ); } pub mod baz { pub marco_rules! bar ( ... ); pub marco_rules! quux ( ... ); } mod herp { use super::foo::bar!; use super::baz::quux!; // using same name macros, no problem use baz! = super::baz::bar!; pub Derp = bar!(baz!()); } ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev