Re: [rust-dev] the inter-play of struct type impl, traits, & type params

2013-11-06 Thread Niko Matsakis
On Tue, Nov 05, 2013 at 08:53:45PM -0800, Ziad Hatahet wrote:
> This relieves one form writing wrapper classes in order for certain
> structs to adhere to particular interfaces.

Partially, yes. Where this breaks down is if you have a type from one
crate and an interface from another. We can't help you there, though
you can often workaround this problem by wrapping the type in a struct
that you created, and defining the interface on that struct type
instead.


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


Re: [rust-dev] the inter-play of struct type impl, traits, & type params

2013-11-05 Thread Ziad Hatahet
Gotcha. But it is still pretty flexible in that you are not bound to the
impls that were originally defined on the type (e.g. like C++/Java where
the list of interfaces implemented by a class are fixed). This relieves one
form writing wrapper classes in order for certain structs to adhere to
particular interfaces.

--
Ziad


On Tue, Nov 5, 2013 at 8:25 PM, Steven Blenkinsop wrote:

> Here you own the trait "Double". Doesn't work if you were trying to
> implement a trait you hadn't just defined. The specific examples you
> mentioned were Clone and Drop, so that wouldn't work.
>
>
> On Tuesday, November 5, 2013, Ziad Hatahet wrote:
>
>> The following seems to work:
>>
>> trait Double {
>> fn double(&self) -> Self;
>> }
>>
>> impl Double for int {
>> fn double(&self) -> int {
>> *self * 2
>> }
>> }
>>
>> fn main() {
>> let x = 2;
>> println!("{}", x.double()); // prints "4"
>> }
>>
>>
>>
>> --
>> Ziad
>>
>>
>> On Tue, Nov 5, 2013 at 1:29 PM, Steven Blenkinsop wrote:
>>
>>> As long as "you" are the person who owns the type, yeah, but I suspect
>>> that's not what you mean. Coherence requires that you only implement traits
>>> for types if you own either the trait or the type (or both). You can't
>>> implement a 3rd party trait for a 3rd party type, since then there could be
>>> multiple such implementations for a given (trait, type) pair, and coherence
>>> would be broken.
>>>
>>>
>>> On Tue, Nov 5, 2013 at 2:28 PM, Ziad Hatahet  wrote:
>>>
 On Tue, Nov 5, 2013 at 9:17 AM, Patrick Walton wrote:

> On 11/5/13 2:44 AM, spir wrote:
>
>> Why not just add a declaration of the trait at the top of the struct
>> type def?
>>
>> struct PairList : Iterable {
>>
>
> You can implement traits on types that aren't structs.



 Isn't another effect of this is the ability to "monkey-patch" structs
 to implement extra methods or traits? E.g. you can later in implement a
 to_str() method for a type, or implement certain traits, like Clone or 
 Drop.


 --
 Ziad


 ___
 Rust-dev mailing list
 Rust-dev@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] the inter-play of struct type impl, traits, & type params

2013-11-05 Thread Steven Blenkinsop
Here you own the trait "Double". Doesn't work if you were trying to
implement a trait you hadn't just defined. The specific examples you
mentioned were Clone and Drop, so that wouldn't work.

On Tuesday, November 5, 2013, Ziad Hatahet wrote:

> The following seems to work:
>
> trait Double {
> fn double(&self) -> Self;
> }
>
> impl Double for int {
> fn double(&self) -> int {
> *self * 2
> }
> }
>
> fn main() {
> let x = 2;
> println!("{}", x.double()); // prints "4"
> }
>
>
>
> --
> Ziad
>
>
> On Tue, Nov 5, 2013 at 1:29 PM, Steven Blenkinsop 
> 
> > wrote:
>
>> As long as "you" are the person who owns the type, yeah, but I suspect
>> that's not what you mean. Coherence requires that you only implement traits
>> for types if you own either the trait or the type (or both). You can't
>> implement a 3rd party trait for a 3rd party type, since then there could be
>> multiple such implementations for a given (trait, type) pair, and coherence
>> would be broken.
>>
>>
>> On Tue, Nov 5, 2013 at 2:28 PM, Ziad Hatahet 
>> 
>> > wrote:
>>
>>> On Tue, Nov 5, 2013 at 9:17 AM, Patrick Walton 
>>> 
>>> > wrote:
>>>
 On 11/5/13 2:44 AM, spir wrote:

> Why not just add a declaration of the trait at the top of the struct
> type def?
>
> struct PairList : Iterable {
>

 You can implement traits on types that aren't structs.
>>>
>>>
>>>
>>> Isn't another effect of this is the ability to "monkey-patch" structs to
>>> implement extra methods or traits? E.g. you can later in implement a
>>> to_str() method for a type, or implement certain traits, like Clone or Drop.
>>>
>>>
>>> --
>>> Ziad
>>>
>>>
>>> ___
>>> Rust-dev mailing list
>>> Rust-dev@mozilla.org >> '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] the inter-play of struct type impl, traits, & type params

2013-11-05 Thread Ziad Hatahet
The following seems to work:

trait Double {
fn double(&self) -> Self;
}

impl Double for int {
fn double(&self) -> int {
*self * 2
}
}

fn main() {
let x = 2;
println!("{}", x.double()); // prints "4"
}



--
Ziad


On Tue, Nov 5, 2013 at 1:29 PM, Steven Blenkinsop wrote:

> As long as "you" are the person who owns the type, yeah, but I suspect
> that's not what you mean. Coherence requires that you only implement traits
> for types if you own either the trait or the type (or both). You can't
> implement a 3rd party trait for a 3rd party type, since then there could be
> multiple such implementations for a given (trait, type) pair, and coherence
> would be broken.
>
>
> On Tue, Nov 5, 2013 at 2:28 PM, Ziad Hatahet  wrote:
>
>> On Tue, Nov 5, 2013 at 9:17 AM, Patrick Walton wrote:
>>
>>> On 11/5/13 2:44 AM, spir wrote:
>>>
 Why not just add a declaration of the trait at the top of the struct
 type def?

 struct PairList : Iterable {

>>>
>>> You can implement traits on types that aren't structs.
>>
>>
>>
>> Isn't another effect of this is the ability to "monkey-patch" structs to
>> implement extra methods or traits? E.g. you can later in implement a
>> to_str() method for a type, or implement certain traits, like Clone or Drop.
>>
>>
>> --
>> Ziad
>>
>>
>> ___
>> Rust-dev mailing list
>> Rust-dev@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] the inter-play of struct type impl, traits, & type params

2013-11-05 Thread Steven Blenkinsop
As long as "you" are the person who owns the type, yeah, but I suspect
that's not what you mean. Coherence requires that you only implement traits
for types if you own either the trait or the type (or both). You can't
implement a 3rd party trait for a 3rd party type, since then there could be
multiple such implementations for a given (trait, type) pair, and coherence
would be broken.


On Tue, Nov 5, 2013 at 2:28 PM, Ziad Hatahet  wrote:

> On Tue, Nov 5, 2013 at 9:17 AM, Patrick Walton wrote:
>
>> On 11/5/13 2:44 AM, spir wrote:
>>
>>> Why not just add a declaration of the trait at the top of the struct
>>> type def?
>>>
>>> struct PairList : Iterable {
>>>
>>
>> You can implement traits on types that aren't structs.
>
>
>
> Isn't another effect of this is the ability to "monkey-patch" structs to
> implement extra methods or traits? E.g. you can later in implement a
> to_str() method for a type, or implement certain traits, like Clone or Drop.
>
>
> --
> Ziad
>
>
> ___
> Rust-dev mailing list
> Rust-dev@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] the inter-play of struct type impl, traits, & type params

2013-11-05 Thread Ziad Hatahet
On Tue, Nov 5, 2013 at 9:17 AM, Patrick Walton  wrote:

> On 11/5/13 2:44 AM, spir wrote:
>
>> Why not just add a declaration of the trait at the top of the struct
>> type def?
>>
>> struct PairList : Iterable {
>>
>
> You can implement traits on types that aren't structs.



Isn't another effect of this is the ability to "monkey-patch" structs to
implement extra methods or traits? E.g. you can later in implement a
to_str() method for a type, or implement certain traits, like Clone or Drop.


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


Re: [rust-dev] the inter-play of struct type impl, traits, & type params

2013-11-05 Thread spir

On 11/05/2013 06:17 PM, Patrick Walton wrote:

On 11/5/13 2:44 AM, spir wrote:


That you very much for this complete answer, Patrick. Things are clearer.

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


Re: [rust-dev] the inter-play of struct type impl, traits, & type params

2013-11-05 Thread Patrick Walton

On 11/5/13 2:44 AM, spir wrote:

Why not just add a declaration of the trait at the top of the struct
type def?

struct PairList : Iterable {


You can implement traits on types that aren't structs.


* either the methods inside the struct def:

struct PairList {
fn push (&self, key:Key, val:Val) {...}
}


That seems somewhat ad-hoc IMHO, because you can implement traits on 
types that aren't structs.




* or a simple form outside the struct def:

fn PairList.push (&self, key:Key, val:Val) {...}

It is stated somewhere that the impl section nicely separates the fields
from the implementation, but this is a question of taste: one could
trivially reply this section "invents" a strange notion of
implementation (after all, data fields also are implementation, or
rather also definition), and forces to tell apart things that logically
fit together. Anyway, it's a question of perspective... I'd vote for the
second form above, because it is a kind of intermediate choice. Another
advantage is it gives a name to the method ("PairList.push").


We considered the second form, but rejected it, because if you had 
generic type parameters you'd have to repeat them over and over.



Also, I'm not clear about whether "impl for trait" sections form a kind
of namespace. Can there be methods with equal names in diverse such
sections (and/or in in th impl section or section not related to
traits)? If yes, then it would be in my view a bad idea. Instead, make a
kind of standard naming scheme for trait methods.
Else, what do such sections mean?


I'm not sure what this means.


As shown above, for a struct type with type params, we have to repeat
the said type params in the impl section's headline, and this in fact
twice! (I had a hard time with that point.) These repetitions make no
sense, in my view, since the type param belongs to the struct type
anyway, esp the one after "impl"; but this one repetition precisely is
where to declare traits on type params... see below. I could live with
the repetition after the struct type name, as if the type param belonged
to the name of the struct type:

impl PairList {

(but as said I would happily forget about impl sections altogether)


There's a big difference between:

impl SomeTrait for Foo { ... }

And:

impl SomeTrait for Foo { ... }

We want to be able to tell the difference between the two at parse time.


There is certainly a way to use traits in an opposite manner: they
represent functionalities of which we may know they are available when
we use other features or types of this or that kind. Currently, traits
act conversely, as a constant barrier to usage and expression. With
traits as they are (used), it looks like everything is forbidden by
default, and we have to discover and explicitely authorise any single
bit of functionality.


Rust doesn't have C++-style ad-hoc templates; instead it requires that 
you use concepts in all circumstances. There are two reasons for this: 
(a) to fix the error message problems of C++ templates; (b) to allow 
functionality to be added to existing types and used in templates 
without the C++ *argument-dependent lookup*. Given that C++ is heavily 
moving toward concepts because the error message problems at least seem 
intractable without them, I'm personally pretty happy with the decision 
that we made. It requires more organization up front, but the user 
experience of the language becomes so much nicer.



I love it that a range of "prelude" features are available in standard.
A tiny improvement would be that we don't even need to prefix everything
with "std::". (In the code above, I had to declare "use std:fmt").
Instead, just as every prelude feature is available as if we had
explicitely imported it, make every (sub)module of std pretend to be at
the root of the library. Meaning, whenever the language does not find
x::y, have it search std:x:y.
This would be particularly appreciated for traits which, as it seems,
we'll have to deal with *very* much.


We used to do this, but we stopped. The reasons have to do with making 
imports tractable and the fact that we didn't want to wire "std" into 
the compiler more than it needs to be.



Now, have a look at [http://static.rust-lang.org/doc/0.8/std/vec.html]:
it is by me a webpage long of 50 screens (I use rather big fonts,
right); I did not count the functions, but there may be more than 200
probably. And this is nearly a plain list, most funcs are undocumented
or just with a short sentence. Actually, most of them seem redondant,
there are tons of versions of the same features, depending on various
variants.


The `vec` module does need to be cleaned up, agreed.


I guess much of this mess is due to a kind of over-engineering
related in part to traits, or to their current usage in Rust. It seems
the combination of traits, and their combinations with other sources of
complication such as type params, add barriers to usage and expression.


I would caution against drawing too much of

[rust-dev] the inter-play of struct type impl, traits, & type params

2013-11-05 Thread spir

Hello,

New to Rust. Is there (already) a list for mutual help in the usage of Rust? If 
not, I guess it may be worth having one, distinct from the dev list, even if the 
language is a moving target, even for people who rather intend, at terms, to 
participate in the development. It is in fact even more needed due precisely to 
the constant change of the lang, to the fact it is mostly unknown, and to the 
state of the docs.
In the meanwhile... see below. Also please pardon wrong ideas or statements: I 
am presently discovering the language. (Also, english is a foreign lang for me.)


As an exercise in learning the language, I am trying various ways to implement 
sparse arrays (association list, trie, "modulo table" = hash table w/o hash), 
the aim being to determine the nr of entries from which it is worth switching to 
a more complicated version. But I'm far from there yet, stumbling on diverse 
issues right for the simplest bits of code. Below, I'm talking of the 
interrelation between struct type declaration & impl, type params, and traits.


type Key = uint;
struct PairList {
   ...
}
impl PairList {
...
}
impl PairList for Iterable {
...
}


=== trait implementation ===

A first point which I find annoying is the splitting of impl for traits a struct 
explicitely implements. This means that each time we need to use a generic func 
for the *usage* of an *instance* of a type, we have to modify this type's 
*definition* with a new impl section for the corresponding trait(s) required by 
the generic feature. Or do I misunderstand? (This, even if the the trait is 
actually implemented, I mean the methods exist, or am I wrong again?) I find 
that exagerated.

Why not just add a declaration of the trait at the top of the struct type def?

struct PairList : Iterable {


=== impl itself ===

As a side note, I also do not understand the purpose of the impl section 
altogether. I would be happy with:


* either the methods inside the struct def:

struct PairList {
   fn push (&self, key:Key, val:Val) {...}
}

* or a simple form outside the struct def:

fn PairList.push (&self, key:Key, val:Val) {...}

It is stated somewhere that the impl section nicely separates the fields from 
the implementation, but this is a question of taste: one could trivially reply 
this section "invents" a strange notion of implementation (after all, data 
fields also are implementation, or rather also definition), and forces to tell 
apart things that logically fit together. Anyway, it's a question of 
perspective... I'd vote for the second form above, because it is a kind of 
intermediate choice. Another advantage is it gives a name to the method 
("PairList.push").



=== the meaning of impl for trait sections ===

Also, I'm not clear about whether "impl for trait" sections form a kind of 
namespace. Can there be methods with equal names in diverse such sections 
(and/or in in th impl section or section not related to traits)? If yes, then it 
would be in my view a bad idea. Instead, make a kind of standard naming scheme 
for trait methods.

Else, what do such sections mean?


=== impl & type params ===

As shown above, for a struct type with type params, we have to repeat the said 
type params in the impl section's headline, and this in fact twice! (I had a 
hard time with that point.) These repetitions make no sense, in my view, since 
the type param belongs to the struct type anyway, esp the one after "impl"; but 
this one repetition precisely is where to declare traits on type params... see 
below. I could live with the repetition after the struct type name, as if the 
type param belonged to the name of the struct type:


impl PairList {

(but as said I would happily forget about impl sections altogether)


=== traits used ===

For programmer feedback (read: debug) I need to write out pair-lists (indeed). 
An issue is that the Val type is a parameter. Since any form of structured 
output itself requires a format (if only '?') and such formats are traits (! 
why?), I need to declare this trait ("fmt::Default") as belonging to Val --yes, 
the type param... But where? I had to search for a while before stepping on the 
right place: as written above right after "impl" itself.
The logical place to make this declaration would be the concerned method, here 
'write'. But the said method does not take any Val instance as input, just self: 
so that there is no place there to declare that Val implements fmt::Default. Or 
how are we to do it?



=== universal traits ===

A distinct but related issue is this trait fmt::Default is supposed universal. 
Could type params have those universal traits? so that we don't have to declare 
them. Or better, they are not traits.



=== everything is a trait ===

Apparently, in the latest dev of Rust, about everything becomes a trait. This 
gets crazy ;-). I guess it is wrong in that it over-complicates the language, 
and there is no limit. Moreover, these layers of complication *compose*, since