Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-04 Thread Niko Matsakis
On Sun, Feb 02, 2014 at 10:30:51AM +0100, Benjamin Herr wrote:
 ... while C# apparently compromises and puts the type parameters between
 the function name and value parameter list, but leaves the bounds for
 later:
 
  public static bool ContainsT(IEnumerableT collection, T item) 
where T : IComparableT;

I have actually been meaning to suggest this for Rust, most likely as
an addition to the current syntax. The reasoning is that if we were to
generalize our traits into the equivalent of Haskell's
multi-parameter type classes, there are things that the current
syntax cannot express. Also I think it reads better if there are many
bounds. But I'll expand in a separate e-mail, rather than tying the
discussion to this thread, which is about Corey's proposal.


Niko
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-03 Thread Gábor Lehel
Just because Any is a trait doesn't mean it doesn't break parametricity.
Look at this:

http://static.rust-lang.org/doc/master/src/std/home/rustbuild/src/rust-buildbot/slave/doc/build/src/libstd/any.rs.html#37-63

Because we have `implT: 'static Any for T`, it can be used with *any
type* (except borrowed data), including type parameters, whether or not
they declare the `T: Any` bound explicitly (which is essentially redundant
in this situation).

The proper thing would be for the compiler to generate an `impl Any for
MyType` for each individual type separately, rather than a single generic
impl which is valid for all types.

I also think we should guarantee parametricity for safe code and make
`size_of` an unsafe fn. Its legitimate uses in unsafe code (e.g. smart
pointers) are well encapsulated and don't expose parametricity violations,
and I don't believe safe code has a legitimate reason to use it (does it?).


On Sun, Feb 2, 2014 at 3:27 AM, Eric Reed ecr...@cs.washington.edu wrote:

 I'm going to respond to Any and size_of separately because there's a
 significant difference IMO.

 It's true that Any and trait bounds on type parameters in general can let
 function behavior depend on the passed type, but only in the specific
 behavior defined by the trait. Everything that's not a trait function is
 still independent of the passed type (contrast this with a setup where this
 wasn't true. `fn fooA() - int' could return 2i for int and spin up a
 tetris game then crash for uint). Any just happens to be powerful enough to
 allow complete variance, which is expected since it's just dynamic typing,
 but there's an important distinction still: behavior variance because of
 Any *is* part of the function because you need to do explicit type tests.

 I wasn't aware of mem::size_of before, but I'm rather annoyed to find out
 we've started adding bare A - B functions since it breaks parametricity.
 I'd much rather put size_of in a trait, at which point it's just a weaker
 version of Any.
 Being able to tell how a function's behavior might vary just from the type
 signature is a very nice property, and I'd like Rust to keep it.

 Now, onto monomorphization.
 I agree that distinguishing static and dynamic dispatch is important for
 performance characterization, but static dispatch != monomorphization (or
 if it currently does, then it probably shouldn't) because not all
 statically dispatched code needs to be monomorphizied. Consider a function
 like this:

 fn fooA, B(ox: Option~A, f: |~A| - ~B) - Option~B {
 match ox {
 Some(x) = Some(f(x)),
 None = None,
 }
 }

 It's quite generic, but AFAIK there's no need to monomorphize it for
 static dispatch. It uses a constant amount of stack space (not counting
 what `f' uses when called) and could run the exact same code for any types
 A or B (check discriminant, potentially call a function pointer, and
 return). I would guess most cases require monomorphization, but I consider
 universal monomorphization a way of implementing static dispatch (as
 opposed to partial monomorphization).
 I agree that understanding monomorphization is important for understanding
 the performance characteristics of code generated by *rustc*, but rustc !=
 Rust.
 Unless universal monomorphization for static dispatch makes its way into
 the Rust language spec, I'm going to consider it an implementation detail
 for rustc.



 On Sat, Feb 1, 2014 at 3:31 PM, Corey Richardson co...@octayn.net wrote:

 On Sat, Feb 1, 2014 at 6:24 PM, Eric Reed ecr...@cs.washington.edu
 wrote:
  Responses inlined.
 
 
  Hey all,
 
  bjz and I have worked out a nice proposal[0] for a slight syntax
  change, reproduced here. It is a breaking change to the syntax, but it
  is one that I think brings many benefits.
 
  Summary
  ===
 
  Change the following syntax:
 
  ```
  struct FooT, U { ... }
  implT, U TraitT for FooT, U { ... }
  fn fooT, U(...) { ... }
  ```
 
  to:
 
  ```
  forallT, U struct Foo { ... }
  forallT, U impl TraitT for FooT, U { ... }
  forallT, U fn foo(...) { ... }
  ```
 
  The Problem
  ===
 
  The immediate, and most pragmatic, problem is that in today's Rust one
  cannot
  easily search for implementations of a trait. Why? `grep 'impl Clone'`
 is
  itself not sufficient, since many types have parametric polymorphism.
 Now
  I
  need to come up with some sort of regex that can handle this. An easy
  first-attempt is `grep 'impl(.*?)? Clone'` but that is quite
  inconvenient to
  type and remember. (Here I ignore the issue of tooling, as I do not
 find
  the
  argument of But a tool can do it! valid in language design.)
 
 
  I think what I've done in the past was just `grep impl | grep Clone'.
 
 
  A deeper, more pedagogical problem, is the mismatch between how `struct
  Foo... { ... }` is read and how it is actually treated. The
  straightforward,
  left-to-right reading says There is a struct Foo which, given the
 types
  ...
  has the members  This 

Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-03 Thread Eric Reed
Actually this isn't the case.

fn fooT: Any(t: T) - TypeId {
t.get_type_id()
}

compiles just fine, but

fn barT(t: T) - TypeId {
t.get_type_id()
}

fails with error: instantiating a type parameter with incompatible type
`T`, which does not fulfill `'static`. Just T does not imply T:
'static, so parametricity is not violated.

I had the same thought about making size_of and friends unsafe functions. I
think that might be a reasonable idea.


On Mon, Feb 3, 2014 at 5:35 AM, Gábor Lehel glaebho...@gmail.com wrote:

 Just because Any is a trait doesn't mean it doesn't break parametricity.
 Look at this:


 http://static.rust-lang.org/doc/master/src/std/home/rustbuild/src/rust-buildbot/slave/doc/build/src/libstd/any.rs.html#37-63

 Because we have `implT: 'static Any for T`, it can be used with *any
 type* (except borrowed data), including type parameters, whether or not
 they declare the `T: Any` bound explicitly (which is essentially redundant
 in this situation).

 The proper thing would be for the compiler to generate an `impl Any for
 MyType` for each individual type separately, rather than a single generic
 impl which is valid for all types.

 I also think we should guarantee parametricity for safe code and make
 `size_of` an unsafe fn. Its legitimate uses in unsafe code (e.g. smart
 pointers) are well encapsulated and don't expose parametricity violations,
 and I don't believe safe code has a legitimate reason to use it (does it?).


 On Sun, Feb 2, 2014 at 3:27 AM, Eric Reed ecr...@cs.washington.eduwrote:

 I'm going to respond to Any and size_of separately because there's a
 significant difference IMO.

 It's true that Any and trait bounds on type parameters in general can let
 function behavior depend on the passed type, but only in the specific
 behavior defined by the trait. Everything that's not a trait function is
 still independent of the passed type (contrast this with a setup where this
 wasn't true. `fn fooA() - int' could return 2i for int and spin up a
 tetris game then crash for uint). Any just happens to be powerful enough to
 allow complete variance, which is expected since it's just dynamic typing,
 but there's an important distinction still: behavior variance because of
 Any *is* part of the function because you need to do explicit type tests.

 I wasn't aware of mem::size_of before, but I'm rather annoyed to find out
 we've started adding bare A - B functions since it breaks parametricity.
 I'd much rather put size_of in a trait, at which point it's just a weaker
 version of Any.
 Being able to tell how a function's behavior might vary just from the
 type signature is a very nice property, and I'd like Rust to keep it.

 Now, onto monomorphization.
 I agree that distinguishing static and dynamic dispatch is important for
 performance characterization, but static dispatch != monomorphization (or
 if it currently does, then it probably shouldn't) because not all
 statically dispatched code needs to be monomorphizied. Consider a function
 like this:

 fn fooA, B(ox: Option~A, f: |~A| - ~B) - Option~B {
 match ox {
 Some(x) = Some(f(x)),
 None = None,
 }
 }

 It's quite generic, but AFAIK there's no need to monomorphize it for
 static dispatch. It uses a constant amount of stack space (not counting
 what `f' uses when called) and could run the exact same code for any types
 A or B (check discriminant, potentially call a function pointer, and
 return). I would guess most cases require monomorphization, but I consider
 universal monomorphization a way of implementing static dispatch (as
 opposed to partial monomorphization).
 I agree that understanding monomorphization is important for
 understanding the performance characteristics of code generated by *rustc*,
 but rustc != Rust.
 Unless universal monomorphization for static dispatch makes its way into
 the Rust language spec, I'm going to consider it an implementation detail
 for rustc.



 On Sat, Feb 1, 2014 at 3:31 PM, Corey Richardson co...@octayn.netwrote:

 On Sat, Feb 1, 2014 at 6:24 PM, Eric Reed ecr...@cs.washington.edu
 wrote:
  Responses inlined.
 
 
  Hey all,
 
  bjz and I have worked out a nice proposal[0] for a slight syntax
  change, reproduced here. It is a breaking change to the syntax, but it
  is one that I think brings many benefits.
 
  Summary
  ===
 
  Change the following syntax:
 
  ```
  struct FooT, U { ... }
  implT, U TraitT for FooT, U { ... }
  fn fooT, U(...) { ... }
  ```
 
  to:
 
  ```
  forallT, U struct Foo { ... }
  forallT, U impl TraitT for FooT, U { ... }
  forallT, U fn foo(...) { ... }
  ```
 
  The Problem
  ===
 
  The immediate, and most pragmatic, problem is that in today's Rust one
  cannot
  easily search for implementations of a trait. Why? `grep 'impl
 Clone'` is
  itself not sufficient, since many types have parametric polymorphism.
 Now
  I
  need to come up with some sort of regex that can handle this. An easy
  first-attempt is `grep 

Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-03 Thread Daniel Micay
On Mon, Feb 3, 2014 at 5:20 PM, Eric Reed ecr...@cs.washington.edu wrote:
 Actually this isn't the case.

 fn fooT: Any(t: T) - TypeId {
 t.get_type_id()
 }

 compiles just fine, but

 fn barT(t: T) - TypeId {
 t.get_type_id()
 }

 fails with error: instantiating a type parameter with incompatible type
 `T`, which does not fulfill `'static`. Just T does not imply T:
 'static, so parametricity is not violated.

 I had the same thought about making size_of and friends unsafe functions. I
 think that might be a reasonable idea.

The 'static bound is there as a workaround for an implementation
limitation. In all likelihood, it will no longer be required in the
future as it has no fundamental relation to reflection.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-03 Thread Gábor Lehel
On Mon, Feb 3, 2014 at 11:20 PM, Eric Reed ecr...@cs.washington.edu wrote:

 Actually this isn't the case.

 fn fooT: Any(t: T) - TypeId {
 t.get_type_id()
 }

 compiles just fine, but

 fn barT(t: T) - TypeId {
 t.get_type_id()
 }

 fails with error: instantiating a type parameter with incompatible type
 `T`, which does not fulfill `'static`. Just T does not imply T:
 'static, so parametricity is not violated.


'static is not even a trait per se (as far as I understand it), it merely
states the lifetime which data must be valid for. I would not expect this
to imply oh, and you can also try casting it to any type. I'm not sure
what a precise definition of parametricity is that we could apply here, but
I'd be very surprised if this flies. It should mean something like only
information that is provided may be used, not if no information is
provided, nothing may be assumed, but if even a little information is
provided, well feel free to do whatever you like.



 I had the same thought about making size_of and friends unsafe functions.
 I think that might be a reasonable idea.


 On Mon, Feb 3, 2014 at 5:35 AM, Gábor Lehel glaebho...@gmail.com wrote:

 Just because Any is a trait doesn't mean it doesn't break parametricity.
 Look at this:


 http://static.rust-lang.org/doc/master/src/std/home/rustbuild/src/rust-buildbot/slave/doc/build/src/libstd/any.rs.html#37-63

 Because we have `implT: 'static Any for T`, it can be used with *any
 type* (except borrowed data), including type parameters, whether or not
 they declare the `T: Any` bound explicitly (which is essentially redundant
 in this situation).

 The proper thing would be for the compiler to generate an `impl Any for
 MyType` for each individual type separately, rather than a single generic
 impl which is valid for all types.

 I also think we should guarantee parametricity for safe code and make
 `size_of` an unsafe fn. Its legitimate uses in unsafe code (e.g. smart
 pointers) are well encapsulated and don't expose parametricity violations,
 and I don't believe safe code has a legitimate reason to use it (does it?).


 On Sun, Feb 2, 2014 at 3:27 AM, Eric Reed ecr...@cs.washington.eduwrote:

 I'm going to respond to Any and size_of separately because there's a
 significant difference IMO.

 It's true that Any and trait bounds on type parameters in general can
 let function behavior depend on the passed type, but only in the specific
 behavior defined by the trait. Everything that's not a trait function is
 still independent of the passed type (contrast this with a setup where this
 wasn't true. `fn fooA() - int' could return 2i for int and spin up a
 tetris game then crash for uint). Any just happens to be powerful enough to
 allow complete variance, which is expected since it's just dynamic typing,
 but there's an important distinction still: behavior variance because of
 Any *is* part of the function because you need to do explicit type tests.

 I wasn't aware of mem::size_of before, but I'm rather annoyed to find
 out we've started adding bare A - B functions since it breaks
 parametricity.
 I'd much rather put size_of in a trait, at which point it's just a
 weaker version of Any.
 Being able to tell how a function's behavior might vary just from the
 type signature is a very nice property, and I'd like Rust to keep it.

 Now, onto monomorphization.
 I agree that distinguishing static and dynamic dispatch is important for
 performance characterization, but static dispatch != monomorphization (or
 if it currently does, then it probably shouldn't) because not all
 statically dispatched code needs to be monomorphizied. Consider a function
 like this:

 fn fooA, B(ox: Option~A, f: |~A| - ~B) - Option~B {
 match ox {
 Some(x) = Some(f(x)),
 None = None,
 }
 }

 It's quite generic, but AFAIK there's no need to monomorphize it for
 static dispatch. It uses a constant amount of stack space (not counting
 what `f' uses when called) and could run the exact same code for any types
 A or B (check discriminant, potentially call a function pointer, and
 return). I would guess most cases require monomorphization, but I consider
 universal monomorphization a way of implementing static dispatch (as
 opposed to partial monomorphization).
 I agree that understanding monomorphization is important for
 understanding the performance characteristics of code generated by *rustc*,
 but rustc != Rust.
 Unless universal monomorphization for static dispatch makes its way into
 the Rust language spec, I'm going to consider it an implementation detail
 for rustc.



 On Sat, Feb 1, 2014 at 3:31 PM, Corey Richardson co...@octayn.netwrote:

 On Sat, Feb 1, 2014 at 6:24 PM, Eric Reed ecr...@cs.washington.edu
 wrote:
  Responses inlined.
 
 
  Hey all,
 
  bjz and I have worked out a nice proposal[0] for a slight syntax
  change, reproduced here. It is a breaking change to the syntax, but
 it
  is one that I think brings many benefits.
 
  Summary
  

Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-02 Thread Benjamin Herr

On Sun, 2014-02-02 at 14:45 +1300, Nick Cameron wrote:

 - The change adds boilerplate and nomenclature that is likely
 unfamiliar to our target audience - 'for all' is well known to
 functional programmers, but I believe that is not true for most users
 of C++ (or Java). Being closer to the C++/Java syntax for generics is
 probably more 'intuitive


So instead of 'for all', use 'template', and we're closer to C++ syntax
than ever!

templateT: typename, U: typename
struct Foo { ... }

templateT: typename, U: typename
impl TraitT for FooT, U { ... }

templateT: typename, U: typename
fn foo(...) { ... }

;-)

fwiw, like C++, Java generic methods also put the  type parameter list
in front of the function signature rather than behind the function name:

public static T extends ComparableT
int countGreaterThan(T[] anArray, T elem) { ... } 

... while C# apparently compromises and puts the type parameters between
the function name and value parameter list, but leaves the bounds for
later:

 public static bool ContainsT(IEnumerableT collection, T item) 
   where T : IComparableT;

Neither approach translates too well into Rust, but that Rust is almost
the odd one out here makes me sympathetic to the desire to avoid
breaking up particularly function declarations between the name and the
value parameter list too much, in spite of the familiarity argument.

Of course, like everything else, that has to be balanced with avoiding
superficial but far-reaching overhauls of the language at the eleventh
hour. Alas!


-benh




___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-02 Thread György Andrasek

On 02/01/2014 11:39 PM, Corey Richardson wrote:

```
forallT, U struct Foo { ... }
forallT, U impl TraitT for FooT, U { ... }
forallT, U fn foo(...) { ... }
```


Why not

```
fn foo: pub unsafe T, U = (f: |T| - U, arg: T) - U { f(arg) }
struct foo: T, U = { ... }
impl Foo: T, U = TraitT { ... }
```

Can we please not put more stuff in front of the identifier? Have we ran 
out of space after it?  What will this look like once the types start 
looking like `templatetypename KeyFromValue, typename Hash, typename 
Pred, typename SuperMeta,typename TagList, typename Category class 
hashed_index`? Do we really need all that in front of a function name?



The immediate, and most pragmatic, problem is that in today's Rust one cannot
easily search for implementations of a trait. Why?


Because the only existing Rust parser is geared towards a native Rust 
compiler, not a non-Rust IDE. That's the problem, not `grep`, and syntax 
changes won't help unless you want to redesign the language to be 
completely regex-compatible. Write a C-bindable parser, plug it into 
`ack`, `ctags` and a couple of IDEs, and everyone will be happy.



(Here I ignore the issue of tooling, as I do not find the
argument of But a tool can do it! valid in language design.)


Then why have such a parsing-oriented grammar in the first place? 
Following this logic, Rust should look more like Haskell, with a Hello 
Kitty binop `(=^.^=)`. (I swear I've seen this in real code somewhere)



___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-02 Thread Jason Fager
I'm not a huge fan of this proposal.  It makes declarations longer, and it
removes the visual consistency of FooT,U everywhere, which I think
introduces its own pedagogical issue.

The recent addition of default type parameters, though, makes me think
there's a reasonable change that increases consistency and shortens
declarations in a few common cases.

From what I understand, the reason we can't just have

impl TraitT for FooT,U

is because it's ambiguous whether T and U are intended to be concrete or
generic type names; i.e.,

implT TraitT for FooT,U

tells the compiler that we expect U to be a concrete type name.

Our new default type parameter declarations look like:

struct FooT,U=Bar

So what if to actually make generic types concrete, we always used the '='?

struct FooT,U=Bar
impl TraitT for FooT, U=Derp

This saves a character over 'implT TraitT for FooT, Derp', solves the
greppability problem, and makes intuitive sense given how defaults are
declared.

It also has a nice parallel with how ':' is used - ':' adds restrictions,
'=' fully locks in place.  So what is today something like

implT:Ord TraitT for FooT, Derp

would become

impl TraitT:Ord for FooT, U=Derp

The rule would be that the first use of a type variable T would introduce
its bounds, so for instance:

impl TraitT:Ord for FooZ:Clone, U=Derp

would be fine, and

impl TraitT for FooT:Clone, U=Derp

would be an error.

More nice fallout:

struct FooA,B
impl FooA,B=Bar {
fn one(a: A) - B
fn two(a: A) - B
fn three(a: A) - B
}

means that if I ever want to go back and change the name of Bar, I only
have to do it in one place, or if Bar is actually some complicated type, I
only had to write it once, like a little local typedef.

I'm sure this has some glaring obvious flaw I'm not thinking of.  It would
be nice to have less syntax for these declarations, but honestly I'm ok
with how it is now.














On Sat, Feb 1, 2014 at 5:39 PM, Corey Richardson co...@octayn.net wrote:

 Hey all,

 bjz and I have worked out a nice proposal[0] for a slight syntax
 change, reproduced here. It is a breaking change to the syntax, but it
 is one that I think brings many benefits.

 Summary
 ===

 Change the following syntax:

 ```
 struct FooT, U { ... }
 implT, U TraitT for FooT, U { ... }
 fn fooT, U(...) { ... }
 ```

 to:

 ```
 forallT, U struct Foo { ... }
 forallT, U impl TraitT for FooT, U { ... }
 forallT, U fn foo(...) { ... }
 ```

 The Problem
 ===

 The immediate, and most pragmatic, problem is that in today's Rust one
 cannot
 easily search for implementations of a trait. Why? `grep 'impl Clone'` is
 itself not sufficient, since many types have parametric polymorphism. Now I
 need to come up with some sort of regex that can handle this. An easy
 first-attempt is `grep 'impl(.*?)? Clone'` but that is quite
 inconvenient to
 type and remember. (Here I ignore the issue of tooling, as I do not find
 the
 argument of But a tool can do it! valid in language design.)

 A deeper, more pedagogical problem, is the mismatch between how `struct
 Foo... { ... }` is read and how it is actually treated. The
 straightforward,
 left-to-right reading says There is a struct Foo which, given the types
 ...
 has the members  This might lead one to believe that `Foo` is a single
 type, but it is not. `Fooint` (that is, type `Foo` instantiated with type
 `int`) is not the same type as `Foounit` (that is, type `Foo`
 instantiated
 with type `uint`). Of course, with a small amount of experience or a very
 simple explanation, that becomes obvious.

 Something less obvious is the treatment of functions. What does `fn
 foo...(...) { ... }` say? There is a function foo which, given types ...
 and arguments ..., does the following computation: ... is not very
 adequate.
 It leads one to believe there is a *single* function `foo`, whereas there
 is
 actually a single `foo` for every substitution of type parameters! This
 also
 holds for implementations (both of traits and of inherent methods).

 Another minor problem is that nicely formatting long lists of type
 parameters
 or type parameters with many bounds is difficult.

 Proposed Solution
 =

 Introduce a new keyword, `forall`. This choice of keyword reads very well
 and
 will not conflict with any identifiers in code which follows the [style
 guide](https://github.com/mozilla/rust/wiki/Note-style-guide).

 Change the following declarations from

 ```
 struct FooT, U { ... }
 implT, U TraitT for FooT, U { ... }
 fn fooT, U(...) { ... }
 ```

 to:

 ```
 forallT, U struct Foo { ... }
 forallT, U impl TraitT for FooT, U { ... }
 forallT, U fn foo(...) { ... }
 ```

 These read very well. for all types T and U, there is a struct Foo ...,
 for
 all types T and U, there is a function foo ..., etc. These reflect that
 there
 are in fact multiple functions `foo` and structs `Foo` and implementations
 of
 `Trait`, due to monomorphization.


 [0]:
 

Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-02 Thread Benjamin Striegel
After sleeping on it I'm not convinced that this would be a net improvement
over our current situation. With a few caveats I'm really rather happy with
the syntax as it is.


On Sun, Feb 2, 2014 at 8:55 AM, Jason Fager jfa...@gmail.com wrote:

 I'm not a huge fan of this proposal.  It makes declarations longer, and it
 removes the visual consistency of FooT,U everywhere, which I think
 introduces its own pedagogical issue.

 The recent addition of default type parameters, though, makes me think
 there's a reasonable change that increases consistency and shortens
 declarations in a few common cases.

 From what I understand, the reason we can't just have

 impl TraitT for FooT,U

 is because it's ambiguous whether T and U are intended to be concrete or
 generic type names; i.e.,

 implT TraitT for FooT,U

 tells the compiler that we expect U to be a concrete type name.

 Our new default type parameter declarations look like:

 struct FooT,U=Bar

 So what if to actually make generic types concrete, we always used the '='?

 struct FooT,U=Bar
 impl TraitT for FooT, U=Derp

 This saves a character over 'implT TraitT for FooT, Derp', solves
 the greppability problem, and makes intuitive sense given how defaults are
 declared.

 It also has a nice parallel with how ':' is used - ':' adds restrictions,
 '=' fully locks in place.  So what is today something like

 implT:Ord TraitT for FooT, Derp

 would become

 impl TraitT:Ord for FooT, U=Derp

 The rule would be that the first use of a type variable T would introduce
 its bounds, so for instance:

 impl TraitT:Ord for FooZ:Clone, U=Derp

 would be fine, and

 impl TraitT for FooT:Clone, U=Derp

 would be an error.

 More nice fallout:

 struct FooA,B
 impl FooA,B=Bar {
 fn one(a: A) - B
 fn two(a: A) - B
 fn three(a: A) - B
 }

 means that if I ever want to go back and change the name of Bar, I only
 have to do it in one place, or if Bar is actually some complicated type, I
 only had to write it once, like a little local typedef.

 I'm sure this has some glaring obvious flaw I'm not thinking of.  It would
 be nice to have less syntax for these declarations, but honestly I'm ok
 with how it is now.














 On Sat, Feb 1, 2014 at 5:39 PM, Corey Richardson co...@octayn.net wrote:

 Hey all,

 bjz and I have worked out a nice proposal[0] for a slight syntax
 change, reproduced here. It is a breaking change to the syntax, but it
 is one that I think brings many benefits.

 Summary
 ===

 Change the following syntax:

 ```
 struct FooT, U { ... }
 implT, U TraitT for FooT, U { ... }
 fn fooT, U(...) { ... }
 ```

 to:

 ```
 forallT, U struct Foo { ... }
 forallT, U impl TraitT for FooT, U { ... }
 forallT, U fn foo(...) { ... }
 ```

 The Problem
 ===

 The immediate, and most pragmatic, problem is that in today's Rust one
 cannot
 easily search for implementations of a trait. Why? `grep 'impl Clone'` is
 itself not sufficient, since many types have parametric polymorphism. Now
 I
 need to come up with some sort of regex that can handle this. An easy
 first-attempt is `grep 'impl(.*?)? Clone'` but that is quite
 inconvenient to
 type and remember. (Here I ignore the issue of tooling, as I do not find
 the
 argument of But a tool can do it! valid in language design.)

 A deeper, more pedagogical problem, is the mismatch between how `struct
 Foo... { ... }` is read and how it is actually treated. The
 straightforward,
 left-to-right reading says There is a struct Foo which, given the types
 ...
 has the members  This might lead one to believe that `Foo` is a
 single
 type, but it is not. `Fooint` (that is, type `Foo` instantiated with
 type
 `int`) is not the same type as `Foounit` (that is, type `Foo`
 instantiated
 with type `uint`). Of course, with a small amount of experience or a very
 simple explanation, that becomes obvious.

 Something less obvious is the treatment of functions. What does `fn
 foo...(...) { ... }` say? There is a function foo which, given types
 ...
 and arguments ..., does the following computation: ... is not very
 adequate.
 It leads one to believe there is a *single* function `foo`, whereas there
 is
 actually a single `foo` for every substitution of type parameters! This
 also
 holds for implementations (both of traits and of inherent methods).

 Another minor problem is that nicely formatting long lists of type
 parameters
 or type parameters with many bounds is difficult.

 Proposed Solution
 =

 Introduce a new keyword, `forall`. This choice of keyword reads very well
 and
 will not conflict with any identifiers in code which follows the [style
 guide](https://github.com/mozilla/rust/wiki/Note-style-guide).

 Change the following declarations from

 ```
 struct FooT, U { ... }
 implT, U TraitT for FooT, U { ... }
 fn fooT, U(...) { ... }
 ```

 to:

 ```
 forallT, U struct Foo { ... }
 forallT, U impl TraitT for FooT, U { ... }
 forallT, U fn foo(...) { ... }
 ```

 These read very 

Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-02 Thread Matthieu Monrocq
On Sun, Feb 2, 2014 at 6:08 PM, Benjamin Striegel ben.strie...@gmail.comwrote:

 After sleeping on it I'm not convinced that this would be a net
 improvement over our current situation. With a few caveats I'm really
 rather happy with the syntax as it is.


 On Sun, Feb 2, 2014 at 8:55 AM, Jason Fager jfa...@gmail.com wrote:

 I'm not a huge fan of this proposal.  It makes declarations longer, and
 it removes the visual consistency of FooT,U everywhere, which I think
 introduces its own pedagogical issue.

 The recent addition of default type parameters, though, makes me think
 there's a reasonable change that increases consistency and shortens
 declarations in a few common cases.

 From what I understand, the reason we can't just have

 impl TraitT for FooT,U

 is because it's ambiguous whether T and U are intended to be concrete or
 generic type names; i.e.,

 implT TraitT for FooT,U

 tells the compiler that we expect U to be a concrete type name.

 Our new default type parameter declarations look like:

 struct FooT,U=Bar

 So what if to actually make generic types concrete, we always used the
 '='?

 struct FooT,U=Bar
 impl TraitT for FooT, U=Derp

 This saves a character over 'implT TraitT for FooT, Derp', solves
 the greppability problem, and makes intuitive sense given how defaults are
 declared.

 It also has a nice parallel with how ':' is used - ':' adds restrictions,
 '=' fully locks in place.  So what is today something like

 implT:Ord TraitT for FooT, Derp

 would become

 impl TraitT:Ord for FooT, U=Derp

 The rule would be that the first use of a type variable T would introduce
 its bounds, so for instance:

 impl TraitT:Ord for FooZ:Clone, U=Derp

 would be fine, and

 impl TraitT for FooT:Clone, U=Derp

 would be an error.

 More nice fallout:

 struct FooA,B
 impl FooA,B=Bar {
 fn one(a: A) - B
 fn two(a: A) - B
 fn three(a: A) - B
 }

 means that if I ever want to go back and change the name of Bar, I only
 have to do it in one place, or if Bar is actually some complicated type, I
 only had to write it once, like a little local typedef.

 I'm sure this has some glaring obvious flaw I'm not thinking of.  It
 would be nice to have less syntax for these declarations, but honestly I'm
 ok with how it is now.














 On Sat, Feb 1, 2014 at 5:39 PM, Corey Richardson co...@octayn.netwrote:

 Hey all,

 bjz and I have worked out a nice proposal[0] for a slight syntax
 change, reproduced here. It is a breaking change to the syntax, but it
 is one that I think brings many benefits.

 Summary
 ===

 Change the following syntax:

 ```
 struct FooT, U { ... }
 implT, U TraitT for FooT, U { ... }
 fn fooT, U(...) { ... }
 ```

 to:

 ```
 forallT, U struct Foo { ... }
 forallT, U impl TraitT for FooT, U { ... }
 forallT, U fn foo(...) { ... }
 ```


From a readability point of view, I am afraid this might be awkward though.

Coming from a C++, I have welcome the switch from `typedef` to `using`
(aliases) because of alignment issues; consider:

typedef std::mapint, std::string MapType;
typedef std::vectorstd::pairint, std::string VectorType;

vs

using MapType = std::mapint, std::string;
using VectorType = std::vectorstd::pairint, std::string;

In the latter, the entities being declared are at a constant offset from
the left-hand margin; and close too; whereas in the former, the eyes are
strained as they keep looking for what is declared.


And now, let's look at your proposal:

fn foo(a: int, b: int) - int { }

fn fooT, U(a: T, b: U) - T { }

forallT, U fn foo(a: T, b: U) - T { }

See how forall causes a bump that forces you to start looking where
that name is ? It was so smooth until then !


So, it might be a net win in terms of grep-ability, but to be honest it
seems LESS readable to me.

-- Matthieu


 The Problem
 ===

 The immediate, and most pragmatic, problem is that in today's Rust one
 cannot
 easily search for implementations of a trait. Why? `grep 'impl Clone'` is
 itself not sufficient, since many types have parametric polymorphism.
 Now I
 need to come up with some sort of regex that can handle this. An easy
 first-attempt is `grep 'impl(.*?)? Clone'` but that is quite
 inconvenient to
 type and remember. (Here I ignore the issue of tooling, as I do not find
 the
 argument of But a tool can do it! valid in language design.)

 A deeper, more pedagogical problem, is the mismatch between how `struct
 Foo... { ... }` is read and how it is actually treated. The
 straightforward,
 left-to-right reading says There is a struct Foo which, given the types
 ...
 has the members  This might lead one to believe that `Foo` is a
 single
 type, but it is not. `Fooint` (that is, type `Foo` instantiated with
 type
 `int`) is not the same type as `Foounit` (that is, type `Foo`
 instantiated
 with type `uint`). Of course, with a small amount of experience or a very
 simple explanation, that becomes obvious.

 Something less obvious is the treatment of functions. What 

Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-02 Thread Corey Richardson
Also after sleeping on it I'm not as big of a fan of this proposal.
But, I find the idea raised earlier of having generic blocks to
group implementations etc that have the same implementation nice.
Fully backwards compat though, so I'm not going to worry about it.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Corey Richardson
Hey all,

bjz and I have worked out a nice proposal[0] for a slight syntax
change, reproduced here. It is a breaking change to the syntax, but it
is one that I think brings many benefits.

Summary
===

Change the following syntax:

```
struct FooT, U { ... }
implT, U TraitT for FooT, U { ... }
fn fooT, U(...) { ... }
```

to:

```
forallT, U struct Foo { ... }
forallT, U impl TraitT for FooT, U { ... }
forallT, U fn foo(...) { ... }
```

The Problem
===

The immediate, and most pragmatic, problem is that in today's Rust one cannot
easily search for implementations of a trait. Why? `grep 'impl Clone'` is
itself not sufficient, since many types have parametric polymorphism. Now I
need to come up with some sort of regex that can handle this. An easy
first-attempt is `grep 'impl(.*?)? Clone'` but that is quite inconvenient to
type and remember. (Here I ignore the issue of tooling, as I do not find the
argument of But a tool can do it! valid in language design.)

A deeper, more pedagogical problem, is the mismatch between how `struct
Foo... { ... }` is read and how it is actually treated. The straightforward,
left-to-right reading says There is a struct Foo which, given the types ...
has the members  This might lead one to believe that `Foo` is a single
type, but it is not. `Fooint` (that is, type `Foo` instantiated with type
`int`) is not the same type as `Foounit` (that is, type `Foo` instantiated
with type `uint`). Of course, with a small amount of experience or a very
simple explanation, that becomes obvious.

Something less obvious is the treatment of functions. What does `fn
foo...(...) { ... }` say? There is a function foo which, given types ...
and arguments ..., does the following computation: ... is not very adequate.
It leads one to believe there is a *single* function `foo`, whereas there is
actually a single `foo` for every substitution of type parameters! This also
holds for implementations (both of traits and of inherent methods).

Another minor problem is that nicely formatting long lists of type parameters
or type parameters with many bounds is difficult.

Proposed Solution
=

Introduce a new keyword, `forall`. This choice of keyword reads very well and
will not conflict with any identifiers in code which follows the [style
guide](https://github.com/mozilla/rust/wiki/Note-style-guide).

Change the following declarations from

```
struct FooT, U { ... }
implT, U TraitT for FooT, U { ... }
fn fooT, U(...) { ... }
```

to:

```
forallT, U struct Foo { ... }
forallT, U impl TraitT for FooT, U { ... }
forallT, U fn foo(...) { ... }
```

These read very well. for all types T and U, there is a struct Foo ..., for
all types T and U, there is a function foo ..., etc. These reflect that there
are in fact multiple functions `foo` and structs `Foo` and implementations of
`Trait`, due to monomorphization.


[0]: 
http://cmr.github.io/blog/2014/02/01/polymorphic-declaration-syntax-in-rust/
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Kevin Ballard
On Feb 1, 2014, at 2:39 PM, Corey Richardson co...@octayn.net wrote:

 The immediate, and most pragmatic, problem is that in today's Rust one cannot
 easily search for implementations of a trait. Why? `grep 'impl Clone'` is
 itself not sufficient, since many types have parametric polymorphism. Now I
 need to come up with some sort of regex that can handle this. An easy
 first-attempt is `grep 'impl(.*?)? Clone'` but that is quite inconvenient to
 type and remember. (Here I ignore the issue of tooling, as I do not find the
 argument of But a tool can do it! valid in language design.)

Putting your other arguments aside, I am not convinced by the grep argument.
With the syntax as it is today, I use `grep 'impl.*Clone'` if I want to find 
Clone
impls. Yes, it can match more than just Clone impls. But that's true too even 
with this
change. At the very least, any sort of multiline comment or string can contain 
text that
matches even the most rigorously specified grep. The only way to truly 
guarantee you're
only matching real impls is to actually parse the file with a real parser.

-Kevin
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Scott Lawrence

May as well throw my 2 cents in.

This is a pretty nice idea (I've always found 'implT' to be particularly 
confusing anyway). It does loose a nice property, though. Previously, there 
was a nice parallelism between


struct FooT

and

let foo: FooT

and so the syntax was quite obvious for beginners. The extra complexity of 
forall kills this. Of course, one could write


forallT:K,L struct FooT {

but that's just ugly.

On Sat, 1 Feb 2014, Corey Richardson wrote:


Hey all,

bjz and I have worked out a nice proposal[0] for a slight syntax
change, reproduced here. It is a breaking change to the syntax, but it
is one that I think brings many benefits.

Summary
===

Change the following syntax:

```
struct FooT, U { ... }
implT, U TraitT for FooT, U { ... }
fn fooT, U(...) { ... }
```

to:

```
forallT, U struct Foo { ... }
forallT, U impl TraitT for FooT, U { ... }
forallT, U fn foo(...) { ... }
```

The Problem
===

The immediate, and most pragmatic, problem is that in today's Rust one cannot
easily search for implementations of a trait. Why? `grep 'impl Clone'` is
itself not sufficient, since many types have parametric polymorphism. Now I
need to come up with some sort of regex that can handle this. An easy
first-attempt is `grep 'impl(.*?)? Clone'` but that is quite inconvenient to
type and remember. (Here I ignore the issue of tooling, as I do not find the
argument of But a tool can do it! valid in language design.)

A deeper, more pedagogical problem, is the mismatch between how `struct
Foo... { ... }` is read and how it is actually treated. The straightforward,
left-to-right reading says There is a struct Foo which, given the types ...
has the members  This might lead one to believe that `Foo` is a single
type, but it is not. `Fooint` (that is, type `Foo` instantiated with type
`int`) is not the same type as `Foounit` (that is, type `Foo` instantiated
with type `uint`). Of course, with a small amount of experience or a very
simple explanation, that becomes obvious.

Something less obvious is the treatment of functions. What does `fn
foo...(...) { ... }` say? There is a function foo which, given types ...
and arguments ..., does the following computation: ... is not very adequate.
It leads one to believe there is a *single* function `foo`, whereas there is
actually a single `foo` for every substitution of type parameters! This also
holds for implementations (both of traits and of inherent methods).

Another minor problem is that nicely formatting long lists of type parameters
or type parameters with many bounds is difficult.

Proposed Solution
=

Introduce a new keyword, `forall`. This choice of keyword reads very well and
will not conflict with any identifiers in code which follows the [style
guide](https://github.com/mozilla/rust/wiki/Note-style-guide).

Change the following declarations from

```
struct FooT, U { ... }
implT, U TraitT for FooT, U { ... }
fn fooT, U(...) { ... }
```

to:

```
forallT, U struct Foo { ... }
forallT, U impl TraitT for FooT, U { ... }
forallT, U fn foo(...) { ... }
```

These read very well. for all types T and U, there is a struct Foo ..., for
all types T and U, there is a function foo ..., etc. These reflect that there
are in fact multiple functions `foo` and structs `Foo` and implementations of
`Trait`, due to monomorphization.


[0]: 
http://cmr.github.io/blog/2014/02/01/polymorphic-declaration-syntax-in-rust/
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev



--
Scott Lawrence
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Benjamin Striegel
First of all, why a new keyword? Reusing `for` here would be totally
unambiguous. :P And also save us from creating the precedent of multi-word
keywords.

Secondly, currently Rust has a philosophy of use-follows-declaration (i.e.
the syntax for using something mirrors the syntax for declaring it). This
would eliminate that.

Thirdly, I've actually been thinking about something like this for quite a
while. The reason is that our function signatures are LOOONG, and I've
always thought that it would be great to be able to declare the type
parameters above the function, in an attribute or something. But you could
just as easily split after your closing  for the same effect. If people
are fine with ditching use-follows-declaration, then this could be pretty
nice.


On Sat, Feb 1, 2014 at 5:39 PM, Corey Richardson co...@octayn.net wrote:

 Hey all,

 bjz and I have worked out a nice proposal[0] for a slight syntax
 change, reproduced here. It is a breaking change to the syntax, but it
 is one that I think brings many benefits.

 Summary
 ===

 Change the following syntax:

 ```
 struct FooT, U { ... }
 implT, U TraitT for FooT, U { ... }
 fn fooT, U(...) { ... }
 ```

 to:

 ```
 forallT, U struct Foo { ... }
 forallT, U impl TraitT for FooT, U { ... }
 forallT, U fn foo(...) { ... }
 ```

 The Problem
 ===

 The immediate, and most pragmatic, problem is that in today's Rust one
 cannot
 easily search for implementations of a trait. Why? `grep 'impl Clone'` is
 itself not sufficient, since many types have parametric polymorphism. Now I
 need to come up with some sort of regex that can handle this. An easy
 first-attempt is `grep 'impl(.*?)? Clone'` but that is quite
 inconvenient to
 type and remember. (Here I ignore the issue of tooling, as I do not find
 the
 argument of But a tool can do it! valid in language design.)

 A deeper, more pedagogical problem, is the mismatch between how `struct
 Foo... { ... }` is read and how it is actually treated. The
 straightforward,
 left-to-right reading says There is a struct Foo which, given the types
 ...
 has the members  This might lead one to believe that `Foo` is a single
 type, but it is not. `Fooint` (that is, type `Foo` instantiated with type
 `int`) is not the same type as `Foounit` (that is, type `Foo`
 instantiated
 with type `uint`). Of course, with a small amount of experience or a very
 simple explanation, that becomes obvious.

 Something less obvious is the treatment of functions. What does `fn
 foo...(...) { ... }` say? There is a function foo which, given types ...
 and arguments ..., does the following computation: ... is not very
 adequate.
 It leads one to believe there is a *single* function `foo`, whereas there
 is
 actually a single `foo` for every substitution of type parameters! This
 also
 holds for implementations (both of traits and of inherent methods).

 Another minor problem is that nicely formatting long lists of type
 parameters
 or type parameters with many bounds is difficult.

 Proposed Solution
 =

 Introduce a new keyword, `forall`. This choice of keyword reads very well
 and
 will not conflict with any identifiers in code which follows the [style
 guide](https://github.com/mozilla/rust/wiki/Note-style-guide).

 Change the following declarations from

 ```
 struct FooT, U { ... }
 implT, U TraitT for FooT, U { ... }
 fn fooT, U(...) { ... }
 ```

 to:

 ```
 forallT, U struct Foo { ... }
 forallT, U impl TraitT for FooT, U { ... }
 forallT, U fn foo(...) { ... }
 ```

 These read very well. for all types T and U, there is a struct Foo ...,
 for
 all types T and U, there is a function foo ..., etc. These reflect that
 there
 are in fact multiple functions `foo` and structs `Foo` and implementations
 of
 `Trait`, due to monomorphization.


 [0]:
 http://cmr.github.io/blog/2014/02/01/polymorphic-declaration-syntax-in-rust/
 ___
 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] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Tim Kuehn
On Sat, Feb 1, 2014 at 3:06 PM, Benjamin Striegel ben.strie...@gmail.comwrote:

 Another point in favor of this plan is that it would eliminate the need to
 put type parameters directly after the `impl`, which to be honest *is*
 pretty weird and inconsistent with the rest of the language. But I'm still
 not sure how I feel about the look of it:

 for T: Clone+Eq, U fn foo(t: T, u: U) - (T, U) {

 If you choose *not* to wrap after the type parameters there, you're really
 obscuring what the heck you're trying to declare.

 Heck, maybe what we're really asking for is for the ability to have
 generic blocks within which type parameters can be declared once:

 for T: Clone+Eq, U {
 fn foo(t: T, u: U) - (T, U) {

 ...but that's even *more* boilerplate!

 It'd mirror how impls work, though, which would be nice. It could be
optional.










 On Sat, Feb 1, 2014 at 5:59 PM, Benjamin Striegel 
 ben.strie...@gmail.comwrote:

  Yes, and I don't have a solution for that.

 Well, it's not like we don't already stumble here a bit, what with
 requiring :: instead of just . Not sure how much other people value the
 consistency here.


 On Sat, Feb 1, 2014 at 5:58 PM, Corey Richardson co...@octayn.netwrote:

 On Sat, Feb 1, 2014 at 5:55 PM, Benjamin Striegel
 ben.strie...@gmail.com wrote:
  First of all, why a new keyword? Reusing `for` here would be totally
  unambiguous. :P And also save us from creating the precedent of
 multi-word
  keywords.
 

 I'd be equally happy with for instead of forall.

  Secondly, currently Rust has a philosophy of use-follows-declaration
 (i.e.
  the syntax for using something mirrors the syntax for declaring it).
 This
  would eliminate that.
 

 Yes, and I don't have a solution for that.




 ___
 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] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Vladimir Lushnikov
Placing type bounds before the name of the thing you are trying to declare
feels unnatural to me. And the generic block is far too much boilerplate!

How about supporting type aliases as Scala does? So you write:

  type MyT = Clone + Eq
  fn fooMyT, U(t: T, u: U) - …

and the 'type' is just an alias for any type that has Clone + Eq?

Obviously the above only solves repeating yourself for complex type
constraints.

Also, reusing 'for' would be confusing as well, because you expect a loop
there, not a generic type bound. How about 'any':

any T: Clone + Eq, U fn foo (t: T, u: U) - …

?


On Sat, Feb 1, 2014 at 11:06 PM, Benjamin Striegel
ben.strie...@gmail.comwrote:

 Another point in favor of this plan is that it would eliminate the need to
 put type parameters directly after the `impl`, which to be honest *is*
 pretty weird and inconsistent with the rest of the language. But I'm still
 not sure how I feel about the look of it:

 for T: Clone+Eq, U fn foo(t: T, u: U) - (T, U) {

 If you choose *not* to wrap after the type parameters there, you're really
 obscuring what the heck you're trying to declare.

 Heck, maybe what we're really asking for is for the ability to have
 generic blocks within which type parameters can be declared once:

 for T: Clone+Eq, U {
 fn foo(t: T, u: U) - (T, U) {

 ...but that's even *more* boilerplate!




 On Sat, Feb 1, 2014 at 5:59 PM, Benjamin Striegel 
 ben.strie...@gmail.comwrote:

  Yes, and I don't have a solution for that.

 Well, it's not like we don't already stumble here a bit, what with
 requiring :: instead of just . Not sure how much other people value the
 consistency here.


 On Sat, Feb 1, 2014 at 5:58 PM, Corey Richardson co...@octayn.netwrote:

 On Sat, Feb 1, 2014 at 5:55 PM, Benjamin Striegel
 ben.strie...@gmail.com wrote:
  First of all, why a new keyword? Reusing `for` here would be totally
  unambiguous. :P And also save us from creating the precedent of
 multi-word
  keywords.
 

 I'd be equally happy with for instead of forall.

  Secondly, currently Rust has a philosophy of use-follows-declaration
 (i.e.
  the syntax for using something mirrors the syntax for declaring it).
 This
  would eliminate that.
 

 Yes, and I don't have a solution for that.




 ___
 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] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Benjamin Striegel
 How about supporting type aliases as Scala does?

In theory I think that should be achievable today, using trait inheritance:

trait MyT : Clone, Eq {}

...at least, I *think* we allow multiple trait inheritance. Not sure what
the syntax is!


On Sat, Feb 1, 2014 at 6:12 PM, Vladimir Lushnikov 
vladi...@slate-project.org wrote:

 Placing type bounds before the name of the thing you are trying to declare
 feels unnatural to me. And the generic block is far too much boilerplate!

 How about supporting type aliases as Scala does? So you write:

   type MyT = Clone + Eq
   fn fooMyT, U(t: T, u: U) - ...

 and the 'type' is just an alias for any type that has Clone + Eq?

 Obviously the above only solves repeating yourself for complex type
 constraints.

 Also, reusing 'for' would be confusing as well, because you expect a loop
 there, not a generic type bound. How about 'any':

 any T: Clone + Eq, U fn foo (t: T, u: U) - ...

 ?


 On Sat, Feb 1, 2014 at 11:06 PM, Benjamin Striegel ben.strie...@gmail.com
  wrote:

 Another point in favor of this plan is that it would eliminate the need
 to put type parameters directly after the `impl`, which to be honest *is*
 pretty weird and inconsistent with the rest of the language. But I'm still
 not sure how I feel about the look of it:

 for T: Clone+Eq, U fn foo(t: T, u: U) - (T, U) {

 If you choose *not* to wrap after the type parameters there, you're
 really obscuring what the heck you're trying to declare.

 Heck, maybe what we're really asking for is for the ability to have
 generic blocks within which type parameters can be declared once:

 for T: Clone+Eq, U {
 fn foo(t: T, u: U) - (T, U) {

 ...but that's even *more* boilerplate!




 On Sat, Feb 1, 2014 at 5:59 PM, Benjamin Striegel ben.strie...@gmail.com
  wrote:

  Yes, and I don't have a solution for that.

 Well, it's not like we don't already stumble here a bit, what with
 requiring :: instead of just . Not sure how much other people value the
 consistency here.


 On Sat, Feb 1, 2014 at 5:58 PM, Corey Richardson co...@octayn.netwrote:

 On Sat, Feb 1, 2014 at 5:55 PM, Benjamin Striegel
 ben.strie...@gmail.com wrote:
  First of all, why a new keyword? Reusing `for` here would be totally
  unambiguous. :P And also save us from creating the precedent of
 multi-word
  keywords.
 

 I'd be equally happy with for instead of forall.

  Secondly, currently Rust has a philosophy of use-follows-declaration
 (i.e.
  the syntax for using something mirrors the syntax for declaring it).
 This
  would eliminate that.
 

 Yes, and I don't have a solution for that.




 ___
 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] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Scott Lawrence

It seems to use a '+' instead of ','.

On Sat, 1 Feb 2014, Benjamin Striegel wrote:


How about supporting type aliases as Scala does?


In theory I think that should be achievable today, using trait inheritance:

   trait MyT : Clone, Eq {}

...at least, I *think* we allow multiple trait inheritance. Not sure what
the syntax is!


On Sat, Feb 1, 2014 at 6:12 PM, Vladimir Lushnikov 
vladi...@slate-project.org wrote:


Placing type bounds before the name of the thing you are trying to declare
feels unnatural to me. And the generic block is far too much boilerplate!

How about supporting type aliases as Scala does? So you write:

  type MyT = Clone + Eq
  fn fooMyT, U(t: T, u: U) - ...

and the 'type' is just an alias for any type that has Clone + Eq?

Obviously the above only solves repeating yourself for complex type
constraints.

Also, reusing 'for' would be confusing as well, because you expect a loop
there, not a generic type bound. How about 'any':

any T: Clone + Eq, U fn foo (t: T, u: U) - ...

?


On Sat, Feb 1, 2014 at 11:06 PM, Benjamin Striegel ben.strie...@gmail.com

wrote:



Another point in favor of this plan is that it would eliminate the need
to put type parameters directly after the `impl`, which to be honest *is*
pretty weird and inconsistent with the rest of the language. But I'm still
not sure how I feel about the look of it:

for T: Clone+Eq, U fn foo(t: T, u: U) - (T, U) {

If you choose *not* to wrap after the type parameters there, you're
really obscuring what the heck you're trying to declare.

Heck, maybe what we're really asking for is for the ability to have
generic blocks within which type parameters can be declared once:

for T: Clone+Eq, U {
fn foo(t: T, u: U) - (T, U) {

...but that's even *more* boilerplate!




On Sat, Feb 1, 2014 at 5:59 PM, Benjamin Striegel ben.strie...@gmail.com

wrote:



Yes, and I don't have a solution for that.


Well, it's not like we don't already stumble here a bit, what with
requiring :: instead of just . Not sure how much other people value the
consistency here.


On Sat, Feb 1, 2014 at 5:58 PM, Corey Richardson co...@octayn.netwrote:


On Sat, Feb 1, 2014 at 5:55 PM, Benjamin Striegel
ben.strie...@gmail.com wrote:

First of all, why a new keyword? Reusing `for` here would be totally
unambiguous. :P And also save us from creating the precedent of

multi-word

keywords.



I'd be equally happy with for instead of forall.


Secondly, currently Rust has a philosophy of use-follows-declaration

(i.e.

the syntax for using something mirrors the syntax for declaring it).

This

would eliminate that.



Yes, and I don't have a solution for that.






___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev








--
Scott Lawrence
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Corey Richardson
On Sat, Feb 1, 2014 at 6:12 PM, Vladimir Lushnikov
vladi...@slate-project.org wrote:
 Also, reusing 'for' would be confusing as well, because you expect a loop
 there, not a generic type bound. How about 'any':


any is a super useful identifier and is already used. I do not want to
reserve it.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Eric Summers

 ```
 forallT, U struct Foo { ... }
 forallT, U impl TraitT for FooT, U { ... }
 forallT, U fn foo(...) { ... }
 ```


I’m new to rust, so maybe this doesn’t make sense, but would it make sense to 
have a variation of this syntax to make implementing related traits and 
functions more DRY?  Essentially allow the for all to be shared.  While I’ve 
been skimming code to learn Rust, I noticed trait restrictions in particular 
seem to be repeated a lot in functions and traits that are related to each 
other.

forallT:ByteStream, U {
impl BinaryEncoderT for MyStructU { … }
impl BinaryDecoderT for MyStructU { … }
}

I also like how it breaks across lines:

forallT, U
struct Foo {
...
}

It looks like someone else suggested this while I was typing, but I like the 
aesthetics of it.

-Eric
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Corey Richardson
On Sat, Feb 1, 2014 at 6:24 PM, Eric Reed ecr...@cs.washington.edu wrote:
 Responses inlined.


 Hey all,

 bjz and I have worked out a nice proposal[0] for a slight syntax
 change, reproduced here. It is a breaking change to the syntax, but it
 is one that I think brings many benefits.

 Summary
 ===

 Change the following syntax:

 ```
 struct FooT, U { ... }
 implT, U TraitT for FooT, U { ... }
 fn fooT, U(...) { ... }
 ```

 to:

 ```
 forallT, U struct Foo { ... }
 forallT, U impl TraitT for FooT, U { ... }
 forallT, U fn foo(...) { ... }
 ```

 The Problem
 ===

 The immediate, and most pragmatic, problem is that in today's Rust one
 cannot
 easily search for implementations of a trait. Why? `grep 'impl Clone'` is
 itself not sufficient, since many types have parametric polymorphism. Now
 I
 need to come up with some sort of regex that can handle this. An easy
 first-attempt is `grep 'impl(.*?)? Clone'` but that is quite
 inconvenient to
 type and remember. (Here I ignore the issue of tooling, as I do not find
 the
 argument of But a tool can do it! valid in language design.)


 I think what I've done in the past was just `grep impl | grep Clone'.


 A deeper, more pedagogical problem, is the mismatch between how `struct
 Foo... { ... }` is read and how it is actually treated. The
 straightforward,
 left-to-right reading says There is a struct Foo which, given the types
 ...
 has the members  This might lead one to believe that `Foo` is a
 single
 type, but it is not. `Fooint` (that is, type `Foo` instantiated with
 type
 `int`) is not the same type as `Foounit` (that is, type `Foo`
 instantiated
 with type `uint`). Of course, with a small amount of experience or a very
 simple explanation, that becomes obvious.


 I strongly disagree with this reasoning.
 There IS only one type Foo. It's a type constructor with kind * - * (where
 * means proper type).
 Fooint and Foouint are two different applications of Foo and are proper
 types (i.e. *) because Foo is * - * and both int and uint are *.
 Regarding people confusing Foo, Fooint and Foouint, I think the proposed
 forallT struct Foo {...} syntax is actually more confusing.
 With the current syntax, it's never legal to write Foo without type
 parameters, but with the proposed syntax it would be.


I've yet to see a proposal for HKT, but with them that interpretation
would be valid and indeed make this proposal's argument weaker.


 Something less obvious is the treatment of functions. What does `fn
 foo...(...) { ... }` say? There is a function foo which, given types
 ...
 and arguments ..., does the following computation: ... is not very
 adequate.
 It leads one to believe there is a *single* function `foo`, whereas there
 is
 actually a single `foo` for every substitution of type parameters! This
 also
 holds for implementations (both of traits and of inherent methods).


 Again, I strongly disagree here.
 There IS only one function foo. Some of it's arguments are types. foo's
 behavior *does not change* based on the type parameters because of
 parametricity.
 That the compiler monomporphizes generic functions is just an implementation
 detail and doesn't change the semantics of the function.


It can if it uses Any, size_of, etc. eddyb had integers in the
typesystem by using size_of and [u8, ..N]. Anything using the
properties of types or the tydescs *will* change for each
instantiation.


 Another minor problem is that nicely formatting long lists of type
 parameters
 or type parameters with many bounds is difficult.


 I'm not sure how this proposal would address this problem. All of your
 proposed examples are longer than the current syntax equivalents.


The idea is there is an obvious place to insert a newline (after the
forall), though bjz would have to comment more on that.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Brian Anderson

On 02/01/2014 02:59 PM, Benjamin Striegel wrote:

 Yes, and I don't have a solution for that.

Well, it's not like we don't already stumble here a bit, what with 
requiring :: instead of just . Not sure how much other people 
value the consistency here.


Yeah, the existing solution is bad, and also rare. If changing the 
declaration might happen then you might as well make another minor 
change for consistency, possibly for the better.





On Sat, Feb 1, 2014 at 5:58 PM, Corey Richardson co...@octayn.net 
mailto:co...@octayn.net wrote:


On Sat, Feb 1, 2014 at 5:55 PM, Benjamin Striegel
ben.strie...@gmail.com mailto:ben.strie...@gmail.com wrote:
 First of all, why a new keyword? Reusing `for` here would be totally
 unambiguous. :P And also save us from creating the precedent of
multi-word
 keywords.


I'd be equally happy with for instead of forall.

 Secondly, currently Rust has a philosophy of
use-follows-declaration (i.e.
 the syntax for using something mirrors the syntax for declaring
it). This
 would eliminate that.


Yes, and I don't have a solution for that.




___
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] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Corey Richardson
On Sat, Feb 1, 2014 at 6:31 PM, Corey Richardson co...@octayn.net wrote:
 On Sat, Feb 1, 2014 at 6:24 PM, Eric Reed ecr...@cs.washington.edu wrote:
 Again, I strongly disagree here.
 There IS only one function foo. Some of it's arguments are types. foo's
 behavior *does not change* based on the type parameters because of
 parametricity.
 That the compiler monomporphizes generic functions is just an implementation
 detail and doesn't change the semantics of the function.


 It can if it uses Any, size_of, etc. eddyb had integers in the
 typesystem by using size_of and [u8, ..N]. Anything using the
 properties of types or the tydescs *will* change for each
 instantiation.


Furthermore, I don't considered monomorphic instantiation to be an
implementation detail. Without it the difference between trait objects
and generics is nonsensical, and iirc there's code that depends on the
addresses of different instantiations being different (though I might
be confusing that with statics). It's also important to understanding
the performance characteristics of Rust, esp binary size and why
metadata is so huge.

It's a vital detail to understanding Rust, and any use of it needs to
consider it. If it is indeed considered an implementation detail, it's
probably the most important implementation detail I've seen in
anything. Given Rust's target market, it'd be irresponsible to ignore
it...
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread comex
On Sat, Feb 1, 2014 at 5:39 PM, Corey Richardson co...@octayn.net wrote:
 A deeper, more pedagogical problem, is the mismatch between how `struct
 Foo... { ... }` is read and how it is actually treated. The straightforward,
 left-to-right reading says There is a struct Foo which, given the types ...
 has the members 

I read struct Foo... { ... } the same way as fn foo(...) - 
 In the latter case, given some value parameters, I get a return
value; in the former, given some type parameters, I get a struct.  On
the contrary, I would find the idea that forallT fn is specified
with fn::T, like in C++ (template typename T) relatively
confusing.

For bulk generics I would rather have the concept of a generic module
than just copy the generic arguments onto each item.  (For that
matter, I think I'd like to have traits on modules or something like
that, so that you can have something like a list trait which comes
with a type for the list and a type for its iterator, without having
to write two generic parameters on everything.  But that's a different
story.)

Also, I think the syntax for generics is verbose enough as it is; I'd
rather see it shortened than lengthened.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Eric Summers

 
 forallT:ByteStream, U {
   impl BinaryEncoderT for MyStructU { … }
   impl BinaryDecoderT for MyStructU { … }
 }

comex mentioned the idea of a generic module.  That would be interesting.  I 
like that idea better then this.

 
 I also like how it breaks across lines:
 
 forallT, U
 struct Foo {
 …
 }
 

I guess it currently breaks ok for long type params:
implT, U
TraitT 
for FooT,U {
...
}

I think the grep issue will be solved by libsyntax being integrated in text 
editor plugins.

-Eric
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Armin Ronacher

Hi,

On 01/02/2014 22:58, Corey Richardson wrote:

I'd be equally happy with for instead of forall.
+1 on not using forall, it sounds confusing and is actually quite a bit to type 
considering how frequent these things are.


As an alternative to for I would want to throw be and use into the mix. 
be is currently already reserved, but not sure how well it sounds.



Regards,
Armin

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Nick Cameron
I prefer the existing syntax.

- As pointed out above, there are solutions to the non-grep-ability.

- The change adds boilerplate and nomenclature that is likely unfamiliar to
our target audience - 'for all' is well known to functional programmers,
but I believe that is not true for most users of C++ (or Java). Being
closer to the C++/Java syntax for generics is probably more 'intuitive'.

- I do not think generics imply polymorphic implementation - C++
programmers are used to generics having monomorphic implementations.

- Starting an item definition with the most important keyword is nice and
we would lose that - currently it is easy to scan down the start of lines
and see that something is a fn, impl, struct, etc. With the change you just
see that something is generic or not, which is not what you are interested
in when scanning. Put another way, I believe this change prioritises
automatic search (grep, which can be fixed) over visual search (which
cannot).

(I do agree that formatting lists of type params is difficult)

Cheers, Nick


On Sun, Feb 2, 2014 at 11:39 AM, Corey Richardson co...@octayn.net wrote:

 Hey all,

 bjz and I have worked out a nice proposal[0] for a slight syntax
 change, reproduced here. It is a breaking change to the syntax, but it
 is one that I think brings many benefits.

 Summary
 ===

 Change the following syntax:

 ```
 struct FooT, U { ... }
 implT, U TraitT for FooT, U { ... }
 fn fooT, U(...) { ... }
 ```

 to:

 ```
 forallT, U struct Foo { ... }
 forallT, U impl TraitT for FooT, U { ... }
 forallT, U fn foo(...) { ... }
 ```

 The Problem
 ===

 The immediate, and most pragmatic, problem is that in today's Rust one
 cannot
 easily search for implementations of a trait. Why? `grep 'impl Clone'` is
 itself not sufficient, since many types have parametric polymorphism. Now I
 need to come up with some sort of regex that can handle this. An easy
 first-attempt is `grep 'impl(.*?)? Clone'` but that is quite
 inconvenient to
 type and remember. (Here I ignore the issue of tooling, as I do not find
 the
 argument of But a tool can do it! valid in language design.)

 A deeper, more pedagogical problem, is the mismatch between how `struct
 Foo... { ... }` is read and how it is actually treated. The
 straightforward,
 left-to-right reading says There is a struct Foo which, given the types
 ...
 has the members  This might lead one to believe that `Foo` is a single
 type, but it is not. `Fooint` (that is, type `Foo` instantiated with type
 `int`) is not the same type as `Foounit` (that is, type `Foo`
 instantiated
 with type `uint`). Of course, with a small amount of experience or a very
 simple explanation, that becomes obvious.

 Something less obvious is the treatment of functions. What does `fn
 foo...(...) { ... }` say? There is a function foo which, given types ...
 and arguments ..., does the following computation: ... is not very
 adequate.
 It leads one to believe there is a *single* function `foo`, whereas there
 is
 actually a single `foo` for every substitution of type parameters! This
 also
 holds for implementations (both of traits and of inherent methods).

 Another minor problem is that nicely formatting long lists of type
 parameters
 or type parameters with many bounds is difficult.

 Proposed Solution
 =

 Introduce a new keyword, `forall`. This choice of keyword reads very well
 and
 will not conflict with any identifiers in code which follows the [style
 guide](https://github.com/mozilla/rust/wiki/Note-style-guide).

 Change the following declarations from

 ```
 struct FooT, U { ... }
 implT, U TraitT for FooT, U { ... }
 fn fooT, U(...) { ... }
 ```

 to:

 ```
 forallT, U struct Foo { ... }
 forallT, U impl TraitT for FooT, U { ... }
 forallT, U fn foo(...) { ... }
 ```

 These read very well. for all types T and U, there is a struct Foo ...,
 for
 all types T and U, there is a function foo ..., etc. These reflect that
 there
 are in fact multiple functions `foo` and structs `Foo` and implementations
 of
 `Trait`, due to monomorphization.


 [0]:
 http://cmr.github.io/blog/2014/02/01/polymorphic-declaration-syntax-in-rust/
 ___
 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] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Eric Reed
I'm going to respond to Any and size_of separately because there's a
significant difference IMO.

It's true that Any and trait bounds on type parameters in general can let
function behavior depend on the passed type, but only in the specific
behavior defined by the trait. Everything that's not a trait function is
still independent of the passed type (contrast this with a setup where this
wasn't true. `fn fooA() - int' could return 2i for int and spin up a
tetris game then crash for uint). Any just happens to be powerful enough to
allow complete variance, which is expected since it's just dynamic typing,
but there's an important distinction still: behavior variance because of
Any *is* part of the function because you need to do explicit type tests.

I wasn't aware of mem::size_of before, but I'm rather annoyed to find out
we've started adding bare A - B functions since it breaks parametricity.
I'd much rather put size_of in a trait, at which point it's just a weaker
version of Any.
Being able to tell how a function's behavior might vary just from the type
signature is a very nice property, and I'd like Rust to keep it.

Now, onto monomorphization.
I agree that distinguishing static and dynamic dispatch is important for
performance characterization, but static dispatch != monomorphization (or
if it currently does, then it probably shouldn't) because not all
statically dispatched code needs to be monomorphizied. Consider a function
like this:

fn fooA, B(ox: Option~A, f: |~A| - ~B) - Option~B {
match ox {
Some(x) = Some(f(x)),
None = None,
}
}

It's quite generic, but AFAIK there's no need to monomorphize it for static
dispatch. It uses a constant amount of stack space (not counting what `f'
uses when called) and could run the exact same code for any types A or B
(check discriminant, potentially call a function pointer, and return). I
would guess most cases require monomorphization, but I consider universal
monomorphization a way of implementing static dispatch (as opposed to
partial monomorphization).
I agree that understanding monomorphization is important for understanding
the performance characteristics of code generated by *rustc*, but rustc !=
Rust.
Unless universal monomorphization for static dispatch makes its way into
the Rust language spec, I'm going to consider it an implementation detail
for rustc.



On Sat, Feb 1, 2014 at 3:31 PM, Corey Richardson co...@octayn.net wrote:

 On Sat, Feb 1, 2014 at 6:24 PM, Eric Reed ecr...@cs.washington.edu
 wrote:
  Responses inlined.
 
 
  Hey all,
 
  bjz and I have worked out a nice proposal[0] for a slight syntax
  change, reproduced here. It is a breaking change to the syntax, but it
  is one that I think brings many benefits.
 
  Summary
  ===
 
  Change the following syntax:
 
  ```
  struct FooT, U { ... }
  implT, U TraitT for FooT, U { ... }
  fn fooT, U(...) { ... }
  ```
 
  to:
 
  ```
  forallT, U struct Foo { ... }
  forallT, U impl TraitT for FooT, U { ... }
  forallT, U fn foo(...) { ... }
  ```
 
  The Problem
  ===
 
  The immediate, and most pragmatic, problem is that in today's Rust one
  cannot
  easily search for implementations of a trait. Why? `grep 'impl Clone'`
 is
  itself not sufficient, since many types have parametric polymorphism.
 Now
  I
  need to come up with some sort of regex that can handle this. An easy
  first-attempt is `grep 'impl(.*?)? Clone'` but that is quite
  inconvenient to
  type and remember. (Here I ignore the issue of tooling, as I do not find
  the
  argument of But a tool can do it! valid in language design.)
 
 
  I think what I've done in the past was just `grep impl | grep Clone'.
 
 
  A deeper, more pedagogical problem, is the mismatch between how `struct
  Foo... { ... }` is read and how it is actually treated. The
  straightforward,
  left-to-right reading says There is a struct Foo which, given the types
  ...
  has the members  This might lead one to believe that `Foo` is a
  single
  type, but it is not. `Fooint` (that is, type `Foo` instantiated with
  type
  `int`) is not the same type as `Foounit` (that is, type `Foo`
  instantiated
  with type `uint`). Of course, with a small amount of experience or a
 very
  simple explanation, that becomes obvious.
 
 
  I strongly disagree with this reasoning.
  There IS only one type Foo. It's a type constructor with kind * - *
 (where
  * means proper type).
  Fooint and Foouint are two different applications of Foo and are
 proper
  types (i.e. *) because Foo is * - * and both int and uint are *.
  Regarding people confusing Foo, Fooint and Foouint, I think the
 proposed
  forallT struct Foo {...} syntax is actually more confusing.
  With the current syntax, it's never legal to write Foo without type
  parameters, but with the proposed syntax it would be.
 

 I've yet to see a proposal for HKT, but with them that interpretation
 would be valid and indeed make this proposal's argument weaker.

 
  Something less 

Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Daniel Micay
On Sat, Feb 1, 2014 at 9:27 PM, Eric Reed ecr...@cs.washington.edu wrote:

 I wasn't aware of mem::size_of before, but I'm rather annoyed to find out
 we've started adding bare A - B functions since it breaks parametricity.
 I'd much rather put size_of in a trait, at which point it's just a weaker
 version of Any.

You do realize how widely used size_of is, right? I don't this it
makes sense to say we've *started* adding this stuff when being able
to get the size/alignment has pretty much always been there.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Patrick Walton

On 2/1/14 6:43 PM, Daniel Micay wrote:

On Sat, Feb 1, 2014 at 9:27 PM, Eric Reed ecr...@cs.washington.edu wrote:


I wasn't aware of mem::size_of before, but I'm rather annoyed to find out
we've started adding bare A - B functions since it breaks parametricity.
I'd much rather put size_of in a trait, at which point it's just a weaker
version of Any.


You do realize how widely used size_of is, right? I don't this it
makes sense to say we've *started* adding this stuff when being able
to get the size/alignment has pretty much always been there.


`transmute()` breaks parametricity too, which is annoying to me because 
you can get C++-template-expansion-style errors in translation time 
(transmute called on types of different sizes). I proposed changing it 
to a dynamic runtime failure if the types had different sizes, which 
eliminates ad-hoc templates leaking into our trait system, but that met 
with extremely strong objections from pretty much everyone.


Patrick


___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Daniel Micay
On Sat, Feb 1, 2014 at 9:46 PM, Patrick Walton pcwal...@mozilla.com wrote:
 On 2/1/14 6:43 PM, Daniel Micay wrote:

 On Sat, Feb 1, 2014 at 9:27 PM, Eric Reed ecr...@cs.washington.edu
 wrote:


 I wasn't aware of mem::size_of before, but I'm rather annoyed to find out
 we've started adding bare A - B functions since it breaks parametricity.
 I'd much rather put size_of in a trait, at which point it's just a weaker
 version of Any.


 You do realize how widely used size_of is, right? I don't this it
 makes sense to say we've *started* adding this stuff when being able
 to get the size/alignment has pretty much always been there.


 `transmute()` breaks parametricity too, which is annoying to me because you
 can get C++-template-expansion-style errors in translation time (transmute
 called on types of different sizes). I proposed changing it to a dynamic
 runtime failure if the types had different sizes, which eliminates ad-hoc
 templates leaking into our trait system, but that met with extremely strong
 objections from pretty much everyone.

 Patrick

This could be restricted to `unsafe` code by making reflection
features `unsafe` and mandating that safe functions must compile for
types meeting the bounds.

The `size_of` functionality is absolutely required to have any hope of
writing smart pointers and containers in the library, without using ~T
and ~[T] as the sole allocators.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Patrick Walton

On 2/1/14 6:50 PM, Daniel Micay wrote:

This could be restricted to `unsafe` code by making reflection
features `unsafe` and mandating that safe functions must compile for
types meeting the bounds.

The `size_of` functionality is absolutely required to have any hope of
writing smart pointers and containers in the library, without using ~T
and ~[T] as the sole allocators.


Oh, don't worry, I'm not proposing removing either transmute or sizeof. 
Just saying it bugs the theorist in me. :)


Patrick

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Eric Reed
Well there's only 260 uses of the string size_of in rustc's src/
according to grep and only 3 uses of size_of in servo according to
GitHub, so I think you may be overestimating its usage.

Either way, I'm not proposing we get rid of size_of. I just think we should
put it in an automatically derived trait instead of defining a function on
all types.
Literally the only thing that would change would be code like this:

fn fooT(t: T) {
let size = mem::size_of(t);
}

would have to be changed to:

fn fooT: SizeOf(t: T) {
let size = SizeOf::size_of(t); // or t.size_of()
}

Is that really so bad?
Now the function's type signature documents that the function's behavior
depends on the size of the type.
If you see a signature like `fn fooT(t: T)', then you know that it
doesn't.
There's no additional performance overhead and it makes size_of like other
intrinsic operators (+, ==, etc.).

I seriously don't see what downside this could possibly have.



On Sat, Feb 1, 2014 at 6:43 PM, Daniel Micay danielmi...@gmail.com wrote:

 On Sat, Feb 1, 2014 at 9:27 PM, Eric Reed ecr...@cs.washington.edu
 wrote:
 
  I wasn't aware of mem::size_of before, but I'm rather annoyed to find out
  we've started adding bare A - B functions since it breaks parametricity.
  I'd much rather put size_of in a trait, at which point it's just a weaker
  version of Any.

 You do realize how widely used size_of is, right? I don't this it
 makes sense to say we've *started* adding this stuff when being able
 to get the size/alignment has pretty much always been there.

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Daniel Micay
On Sat, Feb 1, 2014 at 10:12 PM, Eric Reed ecr...@cs.washington.edu wrote:
 Well there's only 260 uses of the string size_of in rustc's src/ according
 to grep and only 3 uses of size_of in servo according to GitHub, so I
 think you may be overestimating its usage.

The number of calls to `size_of` isn't a useful metric. It's the
building block required to allocate memory (vectors, unique pointers)
and in the slice iterators (to perform pointer arithmetic). If it
requires a bound, then so will any code using a slice iterator.

 Either way, I'm not proposing we get rid of size_of. I just think we should
 put it in an automatically derived trait instead of defining a function on
 all types.
 Literally the only thing that would change would be code like this:

 fn fooT(t: T) {
 let size = mem::size_of(t);
 }

 would have to be changed to:

 fn fooT: SizeOf(t: T) {
 let size = SizeOf::size_of(t); // or t.size_of()
 }

 Is that really so bad?

Yes, it is.

 Now the function's type signature documents that the function's behavior
 depends on the size of the type.
 If you see a signature like `fn fooT(t: T)', then you know that it
 doesn't.
 There's no additional performance overhead and it makes size_of like other
 intrinsic operators (+, ==, etc.).

The operators are not implemented for every type as they are for `size_of`.

 I seriously don't see what downside this could possibly have.

Using unique pointers, vectors and even slice iterators will require a
semantically irrelevant `SizeOf` bound. Whether or not you allocate a
unique pointer to store a value internally shouldn't be part of the
function signature.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax

2014-02-01 Thread Huon Wilson

On 02/02/14 14:18, Daniel Micay wrote:

On Sat, Feb 1, 2014 at 10:12 PM, Eric Reed ecr...@cs.washington.edu wrote:

Well there's only 260 uses of the string size_of in rustc's src/ according
to grep and only 3 uses of size_of in servo according to GitHub, so I
think you may be overestimating its usage.

The number of calls to `size_of` isn't a useful metric. It's the
building block required to allocate memory (vectors, unique pointers)
and in the slice iterators (to perform pointer arithmetic). If it
requires a bound, then so will any code using a slice iterator.


Either way, I'm not proposing we get rid of size_of. I just think we should
put it in an automatically derived trait instead of defining a function on
all types.
Literally the only thing that would change would be code like this:

fn fooT(t: T) {
 let size = mem::size_of(t);
}

would have to be changed to:

fn fooT: SizeOf(t: T) {
 let size = SizeOf::size_of(t); // or t.size_of()
}

Is that really so bad?

Yes, it is.


Now the function's type signature documents that the function's behavior
depends on the size of the type.
If you see a signature like `fn fooT(t: T)', then you know that it
doesn't.
There's no additional performance overhead and it makes size_of like other
intrinsic operators (+, ==, etc.).

The operators are not implemented for every type as they are for `size_of`.


I seriously don't see what downside this could possibly have.

Using unique pointers, vectors and even slice iterators will require a
semantically irrelevant `SizeOf` bound. Whether or not you allocate a
unique pointer to store a value internally shouldn't be part of the
function signature.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


To add to this, a SizeOf bound would be essentially equivalent to the 
Sized bound from DST, and I believe experimentation a while ago decided 
that requiring Sized is the common case (or, at least, so common that it 
would be extremely annoying to require it be explicit).



Huon
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev