Re: [rust-dev] Proposal: Change Parametric Polymorphism Declaration Syntax
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
``` 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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