[rust-dev] Possible bug? os::args() then split then print

2014-02-25 Thread Phil Dawes
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

2014-02-25 Thread Brian Anderson

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?

2014-02-25 Thread Frank Huang
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?

2014-02-25 Thread Alex Crichton
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

2014-02-25 Thread Niko Matsakis
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

2014-02-25 Thread Eric Reed
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

2014-02-25 Thread Michael Woerister
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

2014-02-25 Thread Kevin Ballard
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

2014-02-25 Thread Sean McArthur
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

2014-02-25 Thread Gábor Lehel
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

2014-02-25 Thread Corey Richardson
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

2014-02-25 Thread Corey Richardson
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

2014-02-25 Thread Kevin Ballard
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

2014-02-25 Thread Eric Reed
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

2014-02-25 Thread Kevin Ballard
 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

2014-02-25 Thread Eric Reed
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

2014-02-25 Thread Aran Donohue
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

2014-02-25 Thread Clark Gaebel
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

2014-02-25 Thread Ashish Myles
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

2014-02-25 Thread Eric Reed
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

2014-02-25 Thread Eric Reed
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

2014-02-25 Thread Phil Dawes
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

2014-02-25 Thread Kevin Ballard
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

2014-02-25 Thread Brendan Zabarauskas
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