Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-17 Thread Eric Summers

I thought that the RFC for a virtual fn alternative pushed a couple days ago by 
Bill Myers looked interesting:
https://github.com/bill-myers/rfcs/blob/5e62f881421fc6aa34e85ffc5b2a91a7d370/active/-oop-with-enums.md

I can’t tell if it is elegant or an evil contortion of existing Rust features 
though.  I’m curious what people think of it since it is much different then 
the other proposals out there.

Eric

On Mar 17, 2014, at 3:19 PM, Jan Klesnil  wrote:

> Hi,
> 
> I've just read your proposal. It is pretty similar to an idea I had over the 
> weekend. However, there is one thing I want to ask about. But I will present 
> my idea because it may be the case that I misunderstood some part from your 
> proposal.
> 
> My idea was to introduce few orthogonal concepts and use them together to 
> solve the DOM problem:
> 
> 1) single static inheritance and static cast to base types
> 2) virtual struct WITHOUT any virtual methods
> 3) dynamic cast to derived type or implemented trait for virtual structs
> 
> Structs that are declared virtual will have a hidden pointer to some 
> vtable-like structure that allows dynamic casting to derived types and to 
> traits. So the layout is similar to C++'s virtual classes, but there are no 
> virtual methods. Instead, you would be able to cast to any implemented trait 
> dynamically. If I understand your proposal correctly, it is the same as the 
> Fat relation.
> 
> I see that this Fat relation is absolutely doable, but I was not able 
> to come up with any efficient solution and I see performance of the dynamic 
> cast as very important property. Otherwise the feature will be very useful.
> 
> My baseline solution was to build hashtable for every crate with key of pair 
> (T,U) and search the hashtables when the dynamic cast is requested. That was 
> just a proof that it is doable because it is not efficient solution. I also 
> expect that some v-table structure can be generated for each virtual struct 
> as far as we know all the implemented traits. (E.g., at link time for entire 
> crate.) But when I considered implementing traits for virtual struct from 
> different crate, it became more difficult and I stopped examining the problem.
> 
> So my questions would be:
> Did I understood the meaning of the Fat<> relation correctly?
> 
> Is the Fat<> relation already implemented? Or is there a proposal for the 
> implementation somewhere?
> 
> J
> 
> On 03/15/2014 05:30 AM, Micah Chalmer wrote:
>> I wrote up an alternative proposal that I think, if I’m understanding them 
>> correctly, meets all the requirements.  I submitted it as an RFC, so 
>> discussion of it is probably better put on github on the mailing list, but 
>> in case anyone interested is watching this thread and not watching the RFCs:
>> 
>> https://github.com/rust-lang/rfcs/pull/9
>> 
>> -Micah
>> 
>> ___
>> Rust-dev mailing list
>> Rust-dev@mozilla.org
>> https://mail.mozilla.org/listinfo/rust-dev
>> 
> ___
> Rust-dev mailing list
> Rust-dev@mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-17 Thread Jan Klesnil

Hi,

I've just read your proposal. It is pretty similar to an idea I had over 
the weekend. However, there is one thing I want to ask about. But I will 
present my idea because it may be the case that I misunderstood some 
part from your proposal.


My idea was to introduce few orthogonal concepts and use them together 
to solve the DOM problem:


1) single static inheritance and static cast to base types
2) virtual struct WITHOUT any virtual methods
3) dynamic cast to derived type or implemented trait for virtual structs

Structs that are declared virtual will have a hidden pointer to some 
vtable-like structure that allows dynamic casting to derived types and 
to traits. So the layout is similar to C++'s virtual classes, but there 
are no virtual methods. Instead, you would be able to cast to any 
implemented trait dynamically. If I understand your proposal correctly, 
it is the same as the Fat relation.


I see that this Fat relation is absolutely doable, but I was not 
able to come up with any efficient solution and I see performance of the 
dynamic cast as very important property. Otherwise the feature will be 
very useful.


My baseline solution was to build hashtable for every crate with key of 
pair (T,U) and search the hashtables when the dynamic cast is requested. 
That was just a proof that it is doable because it is not efficient 
solution. I also expect that some v-table structure can be generated for 
each virtual struct as far as we know all the implemented traits. (E.g., 
at link time for entire crate.) But when I considered implementing 
traits for virtual struct from different crate, it became more difficult 
and I stopped examining the problem.


So my questions would be:
Did I understood the meaning of the Fat<> relation correctly?

Is the Fat<> relation already implemented? Or is there a proposal for 
the implementation somewhere?


J

On 03/15/2014 05:30 AM, Micah Chalmer wrote:

I wrote up an alternative proposal that I think, if I’m understanding them 
correctly, meets all the requirements.  I submitted it as an RFC, so discussion 
of it is probably better put on github on the mailing list, but in case anyone 
interested is watching this thread and not watching the RFCs:

https://github.com/rust-lang/rfcs/pull/9

-Micah

___
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] "Virtual fn" is a bad idea

2014-03-14 Thread Micah Chalmer
I wrote up an alternative proposal that I think, if I’m understanding them 
correctly, meets all the requirements.  I submitted it as an RFC, so discussion 
of it is probably better put on github on the mailing list, but in case anyone 
interested is watching this thread and not watching the RFCs:

https://github.com/rust-lang/rfcs/pull/9

-Micah

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-14 Thread Tobias Müller
Ziad Hatahet  wrote:
> Kind of off-topic, but there is a heated discussion on the D language
> forums about why having non-virtual base class methods by default is a bad 
> idea:
> 
>  href="http://forum.dlang.org/thread/lfqoan$5qq$1...@digitalmars.com";>http://forum.dlang.org/thread/lfqoan$5qq$1...@digitalmars.com
> 
> Also comes up here:  href="http://forum.dlang.org/thread/zkmunpiikmrezbzme...@forum.dlang.org";>http://forum.dlang.org/thread/zkmunpiikmrezbzme...@forum.dlang.org

I've just read the entire thread (~250 posts by now) and the discussion is
mainly about pro/cons of breaking changes to the language, not about the
feature itself.

The conclusion of that thread seems to be
- Almost everyone agrees that non-virtual (=final) by default is a _good_
thing.
- The lead developers feel that it's not worth a breaking change.
- Many users don't agree with that decision.

Where did you find a point against non-virtual by default? (Except that
it's a breaking change, of course)

Tobi

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-13 Thread Ziad Hatahet
Kind of off-topic, but there is a heated discussion on the D language
forums about why having non-virtual base class methods by default is a bad
idea:

http://forum.dlang.org/thread/lfqoan$5qq$1...@digitalmars.com

Also comes up here:
http://forum.dlang.org/thread/zkmunpiikmrezbzme...@forum.dlang.org
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-13 Thread Matthieu Monrocq
Hi Eric,

Coming back on memory; I presented two designs:

- in the first one, you have a tag at each level of the hierarchy, which
indeed uses more memory for deep hierarchies but means that a type only
knows about its immediate children

- in the second one, you have a tag only at the root of the hierarchy,
which should use exactly as much memory as a v-table pointer (the fact
there is no v-table does not matter)

Regarding the boilerplate methods, my experience with LLVM is that with
virtual the root describes the interface and each descendant implements it
whereas in this system the root implements the interface for each and every
descendant... This can be alleviated by only dispatching to the immediate
descendants (and let them dispatch further) which is more compatible with
the memory-heavy design but also means multiple jumps at each call; not
nice.

However, once the interface is defined, user code should rarely have to go
and inspect the hierarchy by itself; this kind of "down-casting" should be
limited, as it is with regular inheritance in other languages.

-- Matthieu



On Thu, Mar 13, 2014 at 7:49 PM, Eric Summers  wrote:

> Thinking about this a bit more, maybe the memory cost could go away with
> tagged pointers.  That is easier to do on a 64-bit platform though.
>
> Eric
>
> On Mar 13, 2014, at 1:37 PM, Eric Summers  wrote:
>
> > Yes, but with tags you pay the cost even if Option is None.
> >
> > Eric
> >
> > On Mar 13, 2014, at 1:33 PM, Daniel Micay  wrote:
> >
> >> On 13/03/14 02:25 PM, Eric Summers wrote:
> >>> Also this approach uses more memory.  At least a byte per pointer and
> >>> maybe more with padding.  In most cases like this you would prefer to
> >>> use a vtable instead of tags to reduce the memory footprint.
> >>>
> >>> Eric
> >>
> >> A vtable uses memory too. Either it uses a fat pointer or adds at least
> >> one pointer to the object.
> >>
> >
> > ___
> > Rust-dev mailing list
> > Rust-dev@mozilla.org
> > https://mail.mozilla.org/listinfo/rust-dev
>
> ___
> Rust-dev mailing list
> Rust-dev@mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-13 Thread Eric Summers
Thinking about this a bit more, maybe the memory cost could go away with tagged 
pointers.  That is easier to do on a 64-bit platform though.

Eric

On Mar 13, 2014, at 1:37 PM, Eric Summers  wrote:

> Yes, but with tags you pay the cost even if Option is None.
> 
> Eric
> 
> On Mar 13, 2014, at 1:33 PM, Daniel Micay  wrote:
> 
>> On 13/03/14 02:25 PM, Eric Summers wrote:
>>> Also this approach uses more memory.  At least a byte per pointer and
>>> maybe more with padding.  In most cases like this you would prefer to
>>> use a vtable instead of tags to reduce the memory footprint.
>>> 
>>> Eric
>> 
>> A vtable uses memory too. Either it uses a fat pointer or adds at least
>> one pointer to the object.
>> 
> 
> ___
> 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] "Virtual fn" is a bad idea

2014-03-13 Thread Eric Summers
A really out there solution to reduce memory may be to use a Cap’n Proto style 
arena that uses offsets instead of pointers, but I’m sure there are a lot of 
difficult problems with that.

Eric 

On Mar 13, 2014, at 1:37 PM, Eric Summers  wrote:

> Yes, but with tags you pay the cost even if Option is None.
> 
> Eric
> 
> On Mar 13, 2014, at 1:33 PM, Daniel Micay  wrote:
> 
>> On 13/03/14 02:25 PM, Eric Summers wrote:
>>> Also this approach uses more memory.  At least a byte per pointer and
>>> maybe more with padding.  In most cases like this you would prefer to
>>> use a vtable instead of tags to reduce the memory footprint.
>>> 
>>> Eric
>> 
>> A vtable uses memory too. Either it uses a fat pointer or adds at least
>> one pointer to the object.
>> 
> 
> ___
> 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] "Virtual fn" is a bad idea

2014-03-13 Thread Eric Summers
Yes, but with tags you pay the cost even if Option is None.

Eric

On Mar 13, 2014, at 1:33 PM, Daniel Micay  wrote:

> On 13/03/14 02:25 PM, Eric Summers wrote:
>> Also this approach uses more memory.  At least a byte per pointer and
>> maybe more with padding.  In most cases like this you would prefer to
>> use a vtable instead of tags to reduce the memory footprint.
>> 
>> Eric
> 
> A vtable uses memory too. Either it uses a fat pointer or adds at least
> one pointer to the object.
> 

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-13 Thread Daniel Micay
On 13/03/14 02:25 PM, Eric Summers wrote:
> Also this approach uses more memory.  At least a byte per pointer and
> maybe more with padding.  In most cases like this you would prefer to
> use a vtable instead of tags to reduce the memory footprint.
> 
> Eric

A vtable uses memory too. Either it uses a fat pointer or adds at least
one pointer to the object.



signature.asc
Description: OpenPGP digital signature
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-13 Thread Eric Summers
Also this approach uses more memory.  At least a byte per pointer and maybe 
more with padding.  In most cases like this you would prefer to use a vtable 
instead of tags to reduce the memory footprint.

Eric

On Mar 13, 2014, at 1:17 PM, Eric Summers  wrote:

> Matthieu,
> 
> I tried to model something similar this way.  Sometimes the extra pattern 
> matching gets tedious with this approach.  You also end up with a lot of 
> constructors with similar names.  I also found myself  writing a lot of 
> trivial function wrappers around constructors.  Of course there are benefits 
> to a non-extensible system like this.  For instance, you can tell if you have 
> addressed every case in a match statement.
> 
> Someone on IRC mentioned that a feature similar to Haskell pattern synonyms 
> may make it less awkward to use these enum wrappers.
> 
> Eric
> 
> On Mar 13, 2014, at 12:56 PM, Matthieu Monrocq  
> wrote:
> 
>> And of course I forgot to reply to the list at large... sorry :x
>>  
>> -- Matthieu
>> 
>> 
>> On Wed, Mar 12, 2014 at 8:48 PM, Matthieu Monrocq 
>>  wrote:
>> 
>> 
>> 
>> On Tue, Mar 11, 2014 at 10:18 PM, Patrick Walton  
>> wrote:
>> On 3/11/14 2:15 PM, Maciej Piechotka wrote:
>> Could you elaborate on DOM? I saw it referred a few times but I haven't
>> seen any details. I wrote simple bindings to libxml2 dom
>> (https://github.com/uzytkownik/xml-rs - warning - I wrote it while I was
>> learning ruby) and I don't think there was a problem of OO - main
>> problem was mapping libxml memory management and rust's one [I gave up
>> with namespaces but with native rust dom implementation it would be
>> possible to solve in nicer way]. Of course - I might've been at too
>> early stage.
>> 
>> You need:
>> 
>> 1. One-word pointers to each DOM node, not two. Every DOM node has 5 
>> pointers inside (parent, first child, last child, next sibling, previous 
>> sibling). Using trait objects would 10 words, not 5 words, and would 
>> constitute a large memory regression over current browser engines.
>> 
>> 2. Access to fields common to every instance of a trait without virtual 
>> dispatch. Otherwise the browser will be at a significant performance 
>> disadvantage relative to other engines.
>> 
>> 3. Downcasting and upcasting.
>> 
>> 4. Inheritance with the prefix property, to allow for (2).
>> 
>> If anyone has alternative proposals that handle these constraints that are 
>> more orthogonal and are pleasant to use, then I'm happy to hear them. I'm 
>> just saying that dismissing the feature out of hand is not productive.
>> 
>> 
>> Patrick
>> 
>> 
>> Please excuse me, I need some kind of visualization here, so I concocted a 
>> simple tree:
>> 
>> // So, in pseudo C++, let's imagine a DOM tree
>> struct Element { Element *parent, *prevSib, *nextSib, *firstChild, 
>> *lastChild; uint leftPos, topPos, height, width; bool hidden; };
>> struct Block: Element { BlockProperties blockP; }; struct Div: Block {};
>> struct Inline: Element { InlineProperties inlineP; }; struct Span: Inline {};
>> 
>> 
>> Now, I'll be basically mimicking the way LLVM structures its AST, since the 
>> LLVM AST achieves dynamic casting without RTTI. Note that this has a very 
>> specific downside: the hierarchy is NOT extensible.
>> 
>> // And now in Rust (excuse my poor syntax/errors)
>> enum ElementChild<'r> { ChildBlock(&'r Block), ChildInline(&'r Inline) }
>> 
>> struct Element {
>> child: Option<&'self ElementChild<'self>>;
>> parent: &'self Element;
>> prevSib, nextSib, firstChild, lastChild: Option<&'self Element>;
>> leftPos, topPos, height, width: uint;
>> hidden: bool;
>> }
>> 
>> 
>> enum BlockChild<'r> { ChildDiv(&'r Div) }
>> 
>> struct Block {
>> elementBase: Element;
>> child: Option<&'self BlockChild<'self>>;
>> blockP: BlockProperties;
>> }
>> 
>> struct Div { blockBase: Block; }
>> 
>> 
>> enum InlineChild<'r> { ChildSpan(&'r Span) }
>> 
>> struct Inline {
>> elementBase: Element;
>> child: Option<&'self InlineChild<'self>>;
>> inlineP: InlineProperties;
>> }
>> 
>> struct Span { inlineBase: Inline; }
>> 
>> 
>> Let us review our objectives:
>> 
>> (1) One word to each DOM element: check => Option<&'r Element>
>> 
>> (2) Direct access to a field, without indirection: check => 
>> span.inlineBase.elementBase.hidden
>> 
>> (3) Downcast and upcasting: check => downcast is done by matching: 
>> match(element.child) { ChildBlock(&'r block) => /* act on block */, 
>> ChildInline(&'r inline) => /* act on inline */); upcast is just accessing 
>> the "base" field.
>> 
>> (4) Inheritance with the prefix property => not necessary, (2) is already 
>> satisfied.
>> 
>> 
>> Note on (3): multiple bases are allowed easily, it's one field per base.
>> 
>> 
>> In order to reduce the foot-print; avoiding having a "child" field at each 
>> level of the hierarchy might be beneficial. In this case, only the final 
>> classes are considered in ElementChild
>> 
>> enum ElementChild<'r> { ChildDiv(&

Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-13 Thread Eric Summers
Matthieu,

I tried to model something similar this way.  Sometimes the extra pattern 
matching gets tedious with this approach.  You also end up with a lot of 
constructors with similar names.  I also found myself  writing a lot of trivial 
function wrappers around constructors.  Of course there are benefits to a 
non-extensible system like this.  For instance, you can tell if you have 
addressed every case in a match statement.

Someone on IRC mentioned that a feature similar to Haskell pattern synonyms may 
make it less awkward to use these enum wrappers.

Eric

On Mar 13, 2014, at 12:56 PM, Matthieu Monrocq  
wrote:

> And of course I forgot to reply to the list at large... sorry :x
>  
> -- Matthieu
> 
> 
> On Wed, Mar 12, 2014 at 8:48 PM, Matthieu Monrocq 
>  wrote:
> 
> 
> 
> On Tue, Mar 11, 2014 at 10:18 PM, Patrick Walton  wrote:
> On 3/11/14 2:15 PM, Maciej Piechotka wrote:
> Could you elaborate on DOM? I saw it referred a few times but I haven't
> seen any details. I wrote simple bindings to libxml2 dom
> (https://github.com/uzytkownik/xml-rs - warning - I wrote it while I was
> learning ruby) and I don't think there was a problem of OO - main
> problem was mapping libxml memory management and rust's one [I gave up
> with namespaces but with native rust dom implementation it would be
> possible to solve in nicer way]. Of course - I might've been at too
> early stage.
> 
> You need:
> 
> 1. One-word pointers to each DOM node, not two. Every DOM node has 5 pointers 
> inside (parent, first child, last child, next sibling, previous sibling). 
> Using trait objects would 10 words, not 5 words, and would constitute a large 
> memory regression over current browser engines.
> 
> 2. Access to fields common to every instance of a trait without virtual 
> dispatch. Otherwise the browser will be at a significant performance 
> disadvantage relative to other engines.
> 
> 3. Downcasting and upcasting.
> 
> 4. Inheritance with the prefix property, to allow for (2).
> 
> If anyone has alternative proposals that handle these constraints that are 
> more orthogonal and are pleasant to use, then I'm happy to hear them. I'm 
> just saying that dismissing the feature out of hand is not productive.
> 
> 
> Patrick
> 
> 
> Please excuse me, I need some kind of visualization here, so I concocted a 
> simple tree:
> 
> // So, in pseudo C++, let's imagine a DOM tree
> struct Element { Element *parent, *prevSib, *nextSib, *firstChild, 
> *lastChild; uint leftPos, topPos, height, width; bool hidden; };
> struct Block: Element { BlockProperties blockP; }; struct Div: Block {};
> struct Inline: Element { InlineProperties inlineP; }; struct Span: Inline {};
> 
> 
> Now, I'll be basically mimicking the way LLVM structures its AST, since the 
> LLVM AST achieves dynamic casting without RTTI. Note that this has a very 
> specific downside: the hierarchy is NOT extensible.
> 
> // And now in Rust (excuse my poor syntax/errors)
> enum ElementChild<'r> { ChildBlock(&'r Block), ChildInline(&'r Inline) }
> 
> struct Element {
> child: Option<&'self ElementChild<'self>>;
> parent: &'self Element;
> prevSib, nextSib, firstChild, lastChild: Option<&'self Element>;
> leftPos, topPos, height, width: uint;
> hidden: bool;
> }
> 
> 
> enum BlockChild<'r> { ChildDiv(&'r Div) }
> 
> struct Block {
> elementBase: Element;
> child: Option<&'self BlockChild<'self>>;
> blockP: BlockProperties;
> }
> 
> struct Div { blockBase: Block; }
> 
> 
> enum InlineChild<'r> { ChildSpan(&'r Span) }
> 
> struct Inline {
> elementBase: Element;
> child: Option<&'self InlineChild<'self>>;
> inlineP: InlineProperties;
> }
> 
> struct Span { inlineBase: Inline; }
> 
> 
> Let us review our objectives:
> 
> (1) One word to each DOM element: check => Option<&'r Element>
> 
> (2) Direct access to a field, without indirection: check => 
> span.inlineBase.elementBase.hidden
> 
> (3) Downcast and upcasting: check => downcast is done by matching: 
> match(element.child) { ChildBlock(&'r block) => /* act on block */, 
> ChildInline(&'r inline) => /* act on inline */); upcast is just accessing the 
> "base" field.
> 
> (4) Inheritance with the prefix property => not necessary, (2) is already 
> satisfied.
> 
> 
> Note on (3): multiple bases are allowed easily, it's one field per base.
> 
> 
> In order to reduce the foot-print; avoiding having a "child" field at each 
> level of the hierarchy might be beneficial. In this case, only the final 
> classes are considered in ElementChild
> 
> enum ElementChild<'r> { ChildDiv(&'r Div), ChildSpan(&'r Span) }
> 
> And then downcasting to &'r Block is achieved by:
> 
> match(element.final) { ChildDiv(&'r div) => Some(&'r div.blockBase), _ => 
> None }
> 
> 
> I would note that this does not make use of traits at all; the analysis is 
> only based on Patrick's list of objectives which I guess is incomplete and I 
> was lacking a realistic example so it might not address the full scope of 

Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-13 Thread Matthieu Monrocq
And of course I forgot to reply to the list at large... sorry :x

-- Matthieu


On Wed, Mar 12, 2014 at 8:48 PM, Matthieu Monrocq <
matthieu.monr...@gmail.com> wrote:

>
>
>
> On Tue, Mar 11, 2014 at 10:18 PM, Patrick Walton wrote:
>
>> On 3/11/14 2:15 PM, Maciej Piechotka wrote:
>>
>>> Could you elaborate on DOM? I saw it referred a few times but I haven't
>>> seen any details. I wrote simple bindings to libxml2 dom
>>> (https://github.com/uzytkownik/xml-rs - warning - I wrote it while I was
>>> learning ruby) and I don't think there was a problem of OO - main
>>> problem was mapping libxml memory management and rust's one [I gave up
>>> with namespaces but with native rust dom implementation it would be
>>> possible to solve in nicer way]. Of course - I might've been at too
>>> early stage.
>>>
>>
>> You need:
>>
>> 1. One-word pointers to each DOM node, not two. Every DOM node has 5
>> pointers inside (parent, first child, last child, next sibling, previous
>> sibling). Using trait objects would 10 words, not 5 words, and would
>> constitute a large memory regression over current browser engines.
>>
>> 2. Access to fields common to every instance of a trait without virtual
>> dispatch. Otherwise the browser will be at a significant performance
>> disadvantage relative to other engines.
>>
>> 3. Downcasting and upcasting.
>>
>> 4. Inheritance with the prefix property, to allow for (2).
>>
>> If anyone has alternative proposals that handle these constraints that
>> are more orthogonal and are pleasant to use, then I'm happy to hear them.
>> I'm just saying that dismissing the feature out of hand is not productive.
>>
>>
>> Patrick
>>
>>
> Please excuse me, I need some kind of visualization here, so I concocted a
> simple tree:
>
> // So, in pseudo C++, let's imagine a DOM tree
> struct Element { Element *parent, *prevSib, *nextSib, *firstChild,
> *lastChild; uint leftPos, topPos, height, width; bool hidden; };
> struct Block: Element { BlockProperties blockP; }; struct Div: Block {};
> struct Inline: Element { InlineProperties inlineP; }; struct Span: Inline
> {};
>
>
> Now, I'll be basically mimicking the way LLVM structures its AST, since
> the LLVM AST achieves dynamic casting without RTTI. Note that this has a
> very specific downside: the hierarchy is NOT extensible.
>
> // And now in Rust (excuse my poor syntax/errors)
> enum ElementChild<'r> { ChildBlock(&'r Block), ChildInline(&'r Inline) }
>
> struct Element {
> child: Option<&'self ElementChild<'self>>;
> parent: &'self Element;
> prevSib, nextSib, firstChild, lastChild: Option<&'self Element>;
> leftPos, topPos, height, width: uint;
> hidden: bool;
> }
>
>
> enum BlockChild<'r> { ChildDiv(&'r Div) }
>
> struct Block {
> elementBase: Element;
> child: Option<&'self BlockChild<'self>>;
> blockP: BlockProperties;
> }
>
> struct Div { blockBase: Block; }
>
>
> enum InlineChild<'r> { ChildSpan(&'r Span) }
>
> struct Inline {
> elementBase: Element;
> child: Option<&'self InlineChild<'self>>;
> inlineP: InlineProperties;
> }
>
> struct Span { inlineBase: Inline; }
>
>
> Let us review our objectives:
>
> (1) One word to each DOM element: check => Option<&'r Element>
>
> (2) Direct access to a field, without indirection: check =>
> span.inlineBase.elementBase.hidden
>
> (3) Downcast and upcasting: check => downcast is done by matching:
> match(element.child) { ChildBlock(&'r block) => /* act on block */,
> ChildInline(&'r inline) => /* act on inline */); upcast is just accessing
> the "base" field.
>
> (4) Inheritance with the prefix property => not necessary, (2) is already
> satisfied.
>
>
> Note on (3): multiple bases are allowed easily, it's one field per base.
>
>
> In order to reduce the foot-print; avoiding having a "child" field at each
> level of the hierarchy might be beneficial. In this case, only the final
> classes are considered in ElementChild
>
> enum ElementChild<'r> { ChildDiv(&'r Div), ChildSpan(&'r Span) }
>
> And then downcasting to &'r Block is achieved by:
>
> match(element.final) { ChildDiv(&'r div) => Some(&'r div.blockBase), _ =>
> None }
>
>
> I would note that this does not make use of traits at all; the analysis is
> only based on Patrick's list of objectives which I guess is incomplete and
> I was lacking a realistic example so it might not address the full scope of
> the problem...
>
> ... still, for CLOSED hierarchies, the use of traits should not be
> necessary, although it might be very convenient.
>
> -- Matthieu.
>
>
>>  ___
>> 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] "Virtual fn" is a bad idea

2014-03-13 Thread Patrick Walton

On 3/13/14 6:00 AM, Benjamin Striegel wrote:

Is it correct for me to assume that, even if accepted, virtual things
will be behind a feature flag for 1.0? If so, then I think that will be
enough friction to cause library authors to favor traits instead,
especially if users of virtual-using-libraries would have to turn on the
feature flag as well.


Yes, I think that's almost certain.

I think, based on the feedback, that the idea needs some time to bake 
anyhow.


Patrick

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-13 Thread Benjamin Striegel
Is it correct for me to assume that, even if accepted, virtual things will
be behind a feature flag for 1.0? If so, then I think that will be enough
friction to cause library authors to favor traits instead, especially if
users of virtual-using-libraries would have to turn on the feature flag as
well.


On Thu, Mar 13, 2014 at 12:34 AM, comex  wrote:

> Small comments:
>
> - C++ RTTI is known for being slow, because dynamic_cast has to
> traverse the inheritance tree to decide whether the requested type is
> in there.  LLVM and I think something else I've seen (V8?) improve on
> it by having a master enum of class IDs and then just testing whether
> the object's class ID is between the beginning and end of the list of
> subclasses of the requested one.  As long as this is about
> performance, I think it would be nice to do that instead of using an
> implementation people are going to be motivated to replace with custom
> code anyway.  It would require some kind of enum-based syntax to be
> able to enumerate all the subclasses in one compilation unit, but in
> my opinion that would be an improvement in some ways.  For instance,
> it would be more sane to implement pattern matching for - maybe not
> very important for DOM nodes, but perhaps other things.
>
> (While not as commonly faulted, virtual methods themselves are also
> something of a worst case compared to situations where the compiler
> might know in superclass X - either because the code was written using
> pattern matching or because of some slightly fancy magic - that the
> class is either a Y or a Z, the only two subclasses, and use regular
> branches with inlining, instead of having to go with a full-blown
> indirect jump for everything that differs between subclasses.)
>
> - Alternately, if a C++-like interface is really the right answer...
> for the reasons mentioned elsewhere in the thread (orthogonality/more
> than one way to do it, bad interfaces, and all that), it should still
> be heavily discouraged.  That is, only a small number of projects with
> pressing performance needs similar to this particular object tree
> scenario ought to be using it.  But in that case, I don't think it's
> necessary to make it "nice".  In fact, I think it should be nasty: if
> people think like me (...but I don't design serious libraries...),
> then feature gates requiring one line of code to get past are not
> going to convince them to rethink their design; they will just
> bludgeon through them in order to write Java code in Rust.  Servo can
> live with one part of it using nasty macros instead of nice language
> features.
>
> And in C, in my opinion, it's not even particularly nasty even without
> macros.  I appreciate that Rust would need macros to ensure
> compile-time safety, but it can't be that bad...
> ___
> 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] "Virtual fn" is a bad idea

2014-03-12 Thread comex
Small comments:

- C++ RTTI is known for being slow, because dynamic_cast has to
traverse the inheritance tree to decide whether the requested type is
in there.  LLVM and I think something else I've seen (V8?) improve on
it by having a master enum of class IDs and then just testing whether
the object's class ID is between the beginning and end of the list of
subclasses of the requested one.  As long as this is about
performance, I think it would be nice to do that instead of using an
implementation people are going to be motivated to replace with custom
code anyway.  It would require some kind of enum-based syntax to be
able to enumerate all the subclasses in one compilation unit, but in
my opinion that would be an improvement in some ways.  For instance,
it would be more sane to implement pattern matching for - maybe not
very important for DOM nodes, but perhaps other things.

(While not as commonly faulted, virtual methods themselves are also
something of a worst case compared to situations where the compiler
might know in superclass X - either because the code was written using
pattern matching or because of some slightly fancy magic - that the
class is either a Y or a Z, the only two subclasses, and use regular
branches with inlining, instead of having to go with a full-blown
indirect jump for everything that differs between subclasses.)

- Alternately, if a C++-like interface is really the right answer...
for the reasons mentioned elsewhere in the thread (orthogonality/more
than one way to do it, bad interfaces, and all that), it should still
be heavily discouraged.  That is, only a small number of projects with
pressing performance needs similar to this particular object tree
scenario ought to be using it.  But in that case, I don't think it's
necessary to make it "nice".  In fact, I think it should be nasty: if
people think like me (...but I don't design serious libraries...),
then feature gates requiring one line of code to get past are not
going to convince them to rethink their design; they will just
bludgeon through them in order to write Java code in Rust.  Servo can
live with one part of it using nasty macros instead of nice language
features.

And in C, in my opinion, it's not even particularly nasty even without
macros.  I appreciate that Rust would need macros to ensure
compile-time safety, but it can't be that bad...
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Patrick Walton

On 3/12/14 2:59 PM, Daniel Micay wrote:

Traits aren't really any simpler than this. Templates don't produce nice
errors and require the type checker to redo work on each instantiation,
but I don't think the implementation/specification is more complex.


Templates are more complex because of what happens on substitution 
failure (enabling all of the `static_assert` tricks), as well as 
(partial) template specialization. Furthermore, traits are limited to 
affecting what methods are called (notwithstanding a couple of our 
"kinds"), while templates have a much less constrained notion of what 
things substitutions affect. The latter is what allows all of the 
template metaprogramming tricks that are simply impossible in Rust (for 
a reason).



preprocessor


Macros are more complex than a text-based preprocessor. I understand how
`cpp` works but the macro implementation (hygiene algorithm, etc.) is
something I would need to read about quite a bit.


I guess it's more complexity, but I'm not about to apologize for not 
using cpp. They lead to far less complexity in code. #include and 
#define (for include guards) are not necessary in Rust the same way they 
are in C++.



implicit numeric coercions


We do have generic literals...


Not generic literals in the sense that is usually meant: it only means 
that integer and float literals can be assigned to any type. What Rust 
has is much simpler than arbitrary automatic promotions and demotions of 
non-literal values.



implicit pointer coercions


We have these. & and &mut coerce to * and *mut, sometimes. There's
sometimes automatic coercion to slices too.


What I meant was rules around cv-qualification. I guess &mut coerces to 
&, but that's quite necessary.


Anyway, some of the unsafe pointer stuff may be going away.


overloadable coercions


Auto-dereference/auto-reference can do pretty surprising things and I
don't really understand the algorithm involved. Overloadable coercions
are explicitly specified and the rules are pretty simple.


The algorithm in Rust is really simple: you dereference all the way 
down, then try one reference (immutable or mutable), then stop. Go has 
essentially the same algorithm and people like its simplicity.


Without something like autoderef/autoref, methods become so inconvenient 
to use as to be a non-starter. Note that C++ has autoref on the `this` 
pointer, because, well, you have to have it.



argument-dependent lookup


This is quite similar to looking up a method based on the in-scope traits.


Not at all! Argument-dependent lookup searches namespaces that were not 
imported at the call site.


Take the example from Wikipedia. Rust has nothing like this for 
unqualified function calls:


namespace NS {
class A {};
void f( A *&, int ) {}
}
int main() {
NS::A *a;
f( a, 0 );//calls NS::f
}


non-type template parameters


This is a proposed feature for Rust, and it seems likely that we'll get
associated constants. Integer type parameters are pretty much just sugar
for that.


In Rust's implementation, they might be. Not in C++, where they're a 
thing separate from associated constants (which C++ *also* has).



volatile


Rust has this via intrinsics.


It isn't a qualification on pointers in the type system. Simpler.


constexpr


We do have syntax extensions, and CTFE is an often proposed feature. I
don't know how likely it is that we'll get it.


CTFE in Rust would not have the ad-hoc set of rules specifying what you 
can and can't do like C++ does. It would just be a conservative 
extension of the macro system.



runtime type information


We have std::reflect, a type_id intrinsic and the venerable TyDesc.


True. I want to get rid of most if not all of those.


capture clauses


We need something like this for unboxed closures unless we change the
current semantics from an implicit non-first-class by-ref capture.


No, it would just work the same way proc works.


`->` syntax


Auto-dereference is more complex.


Not if you consider that autoderef is a replacement for both `->` *and* 
the implicit coercions in C++. Two birds with one stone, with no extra 
syntax.



multiple inheritance


We do have multiple trait inheritance... and AFAIK supertraits are
intended to work with trait objects.


Multiple inheritance is implemented with a subtle 
pointers-to-multiple-vtables scheme in C++ that many projects avoid 
because of its complexity. It necessitates virtual inheritance as a 
separate thing from normal inheritance. Trait objects are much simpler 
to implement, because we just pack the vtable next to the object. 
Supertrait makes this scheme no more complex.



pointer-to-member-functions


We'll have this too AFAIK. How will first-class methods mix with single
inheritance?


No, we won't have it. Under UFCS, first-class methods would just work 
the same way: they don't bind the this pointer.



the subtle rules around "const", the `mutable` keyword


Rust

Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Richard Gomes
I'm actually confused about what "object inheritance" means in Rust.

I understand that Rust makes a very clear separation between behaviour
(traits) and data (structs). So, when I saw mentions to "virtual
structs" implementing or not implementing virtual functions, I had the
/sensation/ that these very distinct concepts are starting to get mixed
in ways that I find a bit confusing from the user's perspective.

Thanks

Richard Gomes
http://rgomes.info
http://www.linkedin.com/in/rgomes
mobile: +44(77)9955-6813
inum : +883(5100)0800-9804
sip:rgo...@ippi.fr

On 12/03/14 19:33, Daniel Micay wrote:
> On 12/03/14 09:21 AM, Niko Matsakis wrote:
>> I personally think that offering some kind of virtual structs fits
>> completely within Rust. We've always tried to avoid "one size fits
>> all" thinking -- in real life there are performance tradeoffs, and you
>> often can't cover the entire space with a single design. This is why
>> we offer multiple pointer types, closures vs procs, and so forth.
> Rust is already a large language, and the interactions between many of
> the features are subtle or poorly defined. There's a complexity cost for
> every feature that's added. It gets harder for a single programmer to
> learn the language and makes it less feasible for even an experienced
> Rust programmer to grasp it all. The compiler will have more bugs, so
> the safety guarantee won't be as strong.
>
> Variadic generics, optional/keyword parameters, higher-kinded types,
> single inheritance, refinement types, dynamically sized types,
> compile-time function evaluation, generic literals and more are all
> proposed as useful features. I think there's the potential for Rust to
> be a more complex language than C++, if it's not already.
>
>> In general, I hope that Rust programmers will reach for traits first.
> I think we can expect that programmers will reach for familiar concepts,
> and for many (most?) that will mean using inheritance. It will change
> how code is written in Rust, and will be seen in many third party libraries.
>
> I never plan on using the feature and I'll certainly avoid libraries
> requiring me to use object inheritance and override methods. Others will
> make heavy use of this feature. When I'm writing C++, I rarely find
> libraries using what I consider to be a sane subset of the language.
> When there isn't a Boost library for it, I just end up using a C library
> and building a C++11 wrapper around it myself. I can definitely see this
> happening to Rust if it picks up controversial features like object
> inheritance.
>
>
>
> ___
> 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] "Virtual fn" is a bad idea

2014-03-12 Thread Nathan Myers

On 03/12/2014 08:17 AM, Patrick Walton wrote:

On 3/12/14 3:29 AM, Nathan Myers wrote:

Given such primitives, esoteric constructions like virtual inheritance
could be left to ambitious users.


We did sketch a macro-based solution for this that was basically what
you said. It involved an `rtti!()` macro that allowed construction of
vtables per object and structs, as well as an `family!()` macro that
allowed you to downcast and upcast. But it was very complex, with lots
of moving parts. At the end of the day you need some things to be built
in to the language if you want them to be nice.


This is interesting because it means the work is half done.
Results of such an effort divide more or less neatly into

 - essentials
 - hacks around language limitations to implement essentials
 - presentation hacks to make the construct usable by normal people

There's no getting around the first one; the complexity is in the
library or in the compiler.  The latter two help to identify what
to add to the language core to make such a library practical.

The complexity of the features to eliminate the hacks would tend
to be much smaller than of the hacks themselves, and no larger
than pulling the whole into the core language. It would be tempting,
then, to generalize the new features to support more of the common
usage patterns (e.g. delegation), and it's a matter of project
discipline to know where to stop.  Rust doesn't lack project
discipline.

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Daniel Micay
> templates without concepts

Traits aren't really any simpler than this. Templates don't produce nice
errors and require the type checker to redo work on each instantiation,
but I don't think the implementation/specification is more complex.

> preprocessor

Macros are more complex than a text-based preprocessor. I understand how
`cpp` works but the macro implementation (hygiene algorithm, etc.) is
something I would need to read about quite a bit.

> implicit numeric coercions

We do have generic literals...

> implicit pointer coercions

We have these. & and &mut coerce to * and *mut, sometimes. There's
sometimes automatic coercion to slices too.

> overloadable coercions

Auto-dereference/auto-reference can do pretty surprising things and I
don't really understand the algorithm involved. Overloadable coercions
are explicitly specified and the rules are pretty simple.

> argument-dependent lookup

This is quite similar to looking up a method based on the in-scope traits.

> non-type template parameters

This is a proposed feature for Rust, and it seems likely that we'll get
associated constants. Integer type parameters are pretty much just sugar
for that.

> volatile

Rust has this via intrinsics.

> constexpr

We do have syntax extensions, and CTFE is an often proposed feature. I
don't know how likely it is that we'll get it.

> runtime type information

We have std::reflect, a type_id intrinsic and the venerable TyDesc.

> allocators

This is also proposed.

> capture clauses

We need something like this for unboxed closures unless we change the
current semantics from an implicit non-first-class by-ref capture.

> `->` syntax

Auto-dereference is more complex.

> multiple inheritance

We do have multiple trait inheritance... and AFAIK supertraits are
intended to work with trait objects.

> pointer-to-member-functions

We'll have this too AFAIK. How will first-class methods mix with single
inheritance?

> the subtle rules around "const", the `mutable` keyword

Rust's support for mutability is better, but it's better in part because
it's a more sophisticated system. `const` is dead simple when compared
to inherited-mutability-but-sometimes-not-really (& &mut, non-Freeze
types like Cell/RefCell, etc.).

> the implicit `this` pointer and the `enable_shared_from_this` that you
need, `const` member functions

We have the complexity of `self` being special and allowing certain
pointer sigil qualifications.

> default arguments

This is another proposed feature for Rust, and one I also really dislike.

> exceptions

You can't catch failure, but it's not really less complex at a language
level. It makes the libraries much simpler since exception safety isn't
a thing.

> Without single inheritance, how do you solve the problems outlined in
> this thread?

I don't think Rust needs to support every kind of object system
efficiently at a language level. I would only want it to pick a good one
and support that (like trait objects) rather than trying to make the
compiler directly support any foreign object system efficiently.

In my opinion, supporting another object system would be good for Servo
(or another browser engine) and bad for the language elsewhere... I can
see why having an efficient DOM is important, but it doesn't make me not
hate this feature.

I don't think making COM/gobject incredibly efficient is a valid use
case because both are terrible legacy technologies and both are already
slow.



signature.asc
Description: OpenPGP digital signature
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Patrick Walton

On 3/12/14 12:33 PM, Daniel Micay wrote:

Rust is already a large language, and the interactions between many of
the features are subtle or poorly defined.


Citation? Like what?


There's a complexity cost for
every feature that's added. It gets harder for a single programmer to
learn the language and makes it less feasible for even an experienced
Rust programmer to grasp it all. The compiler will have more bugs, so
the safety guarantee won't be as strong.

Variadic generics, optional/keyword parameters, higher-kinded types,
single inheritance, refinement types, dynamically sized types,
compile-time function evaluation, generic literals and more are all
proposed as useful features. I think there's the potential for Rust to
be a more complex language than C++, if it's not already.


Rust is not a more complex language than C++. That's hyperbolic. Today 
we don't have single inheritance, templates without concepts, the 
preprocessor, the implicit numeric coercions, implicit pointer 
coercions, overloadable coercions, argument-dependent lookup, non-type 
template parameters, volatile, constexpr, rvalue references, 
constructors (including `explicit`), runtime type information, 
allocators, capture clauses, copy constructors, many overloaded 
operators (e.g. assignment), `->` syntax, the lexer hack, multiple 
inheritance, pointer-to-member-functions, the subtle rules around 
"const", "protected", "goto", the SFINAE rule, the implicit `this` 
pointer and the `enable_shared_from_this` that you need, `const` member 
functions, the `mutable` keyword, the ternary operator, `nullptr`, 
default arguments, friends, exceptions, variable-length arrays, 
preincrement/postincrement operators, the `sizeof` keyword, custom 
braced initializer syntax, the C-style `for` syntax, constructor 
initializer lists, `static` variables, and unnamed namespaces. Just to 
name a few.


Without single inheritance, how do you solve the problems outlined in 
this thread?


Patrick

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Daniel Micay
On 12/03/14 09:21 AM, Niko Matsakis wrote:
> I personally think that offering some kind of virtual structs fits
> completely within Rust. We've always tried to avoid "one size fits
> all" thinking -- in real life there are performance tradeoffs, and you
> often can't cover the entire space with a single design. This is why
> we offer multiple pointer types, closures vs procs, and so forth.

Rust is already a large language, and the interactions between many of
the features are subtle or poorly defined. There's a complexity cost for
every feature that's added. It gets harder for a single programmer to
learn the language and makes it less feasible for even an experienced
Rust programmer to grasp it all. The compiler will have more bugs, so
the safety guarantee won't be as strong.

Variadic generics, optional/keyword parameters, higher-kinded types,
single inheritance, refinement types, dynamically sized types,
compile-time function evaluation, generic literals and more are all
proposed as useful features. I think there's the potential for Rust to
be a more complex language than C++, if it's not already.

> In general, I hope that Rust programmers will reach for traits first.

I think we can expect that programmers will reach for familiar concepts,
and for many (most?) that will mean using inheritance. It will change
how code is written in Rust, and will be seen in many third party libraries.

I never plan on using the feature and I'll certainly avoid libraries
requiring me to use object inheritance and override methods. Others will
make heavy use of this feature. When I'm writing C++, I rarely find
libraries using what I consider to be a sane subset of the language.
When there isn't a Boost library for it, I just end up using a C library
and building a C++11 wrapper around it myself. I can definitely see this
happening to Rust if it picks up controversial features like object
inheritance.



signature.asc
Description: OpenPGP digital signature
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Tommi
I'm sorry for being kind of off-topic here, but whatever you decide on this 
matter, I'd still like to be able to emulate multiple-inheritance using the 
following idiom (which requires being able to say that a trait method is 
private or, preferably, why don't we make trait methods private by default):

trait Inflate {
priv fn get_radius<'s>(&'s mut self) -> &'s mut int;

fn inflate_by(&mut self, amount: int) {
*self.get_radius() += amount;
}
// ... rest of the implementation ...
}

trait Flatten {
priv fn getRadius<'s>(&'s mut self) -> &'s mut int;

fn release_all_air(&mut self) {
*self.getRadius() = 0;
}
// ... rest of the implementation ...
}

struct Balloon {
radius: int
}

impl Inflate for Balloon {
priv fn get_radius<'s>(&'s mut self) -> &'s mut int {
&mut self.radius
}
}

impl Flatten for Balloon {
priv fn getRadius<'s>(&'s mut self) -> &'s mut int {
&mut self.radius
}
}

fn main() {
let mut b = Balloon { radius: 123 };
b.inflate_by(10);
b.release_all_air();
// b.get_radius(); // ERROR: get_radius is private
// b.getRadius();  // ERROR: getRadius is private
}

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Patrick Walton

On 3/12/14 7:16 AM, Bill Myers wrote:

However, the extensibility of trait objects comes at the cost of fat
pointers, which can be a problem if you have a lot of pointers.


This is fixable without introducing virtual functions, by adding a
way to express "Struct and vtable for impl Trait for Struct" and
"thin pointer to Struct and vtable for impl Trait for Struct" (or by
using an indirect pointer, i.e. ~~Trait or Rc<~Trait>).


I don't understand the first option--isn't that basically "virtual 
struct"? The second has overhead even worse than the fat pointer: two 
allocations.


Patrick

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Patrick Walton

On 3/12/14 2:24 AM, Maciej Piechotka wrote:

+ impl with potentially partial methods? Is the 'all nodes consuming
same amount of memory' too much memory?


Yes, that's too much memory. You see this in rustc actually. rustc uses 
a similar structure and AST nodes take up too much memory, leading to 
large memory usage of the compiler.


I also don't see how your solution allows nice access to 
element-specific fields if you statically know you have an `Element`.


Patrick

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Patrick Walton

On 3/12/14 3:29 AM, Nathan Myers wrote:

Given such primitives, esoteric constructions like virtual inheritance
could be left to ambitious users.


We did sketch a macro-based solution for this that was basically what 
you said. It involved an `rtti!()` macro that allowed construction of 
vtables per object and structs, as well as an `family!()` macro that 
allowed you to downcast and upcast. But it was very complex, with lots 
of moving parts. At the end of the day you need some things to be built 
in to the language if you want them to be nice.


Patrick

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Bill Myers
> However, the extensibility of trait objects comes at the cost of fat
> pointers, which can be a problem if you have a lot of pointers.

This is fixable without introducing virtual functions, by adding a way to 
express "Struct and vtable for impl Trait for Struct" and "thin pointer to 
Struct and vtable for impl Trait for Struct" (or by using an indirect pointer, 
i.e. ~~Trait or Rc<~Trait>).

> It also implies that downcasting isn't really possible, at least not
> cheaply, because there is no notion of the "actual type" of a
> particular object.

I don't understand this.

You can downcast trait pointers to struct pointers just fine, since you can put 
whatever information needed in the trait impl vtable (such as a typeid).

Sure, you can't "downcast" a struct to a struct, but that's the whole point of 
structs.

The idea of a struct is that one is referring to something of EXACTLY that 
type, and so downcasting makes no sense; when one wants a "variable" type one 
uses a trait and then you can (attempt to) downcast to concrete structs.

One can of course introduce "virtual struct"s which are no longer exactly of 
that type but are now virtual, but that just overlaps the role of traits.
> (As an aside, I am personally happier to see virtual structs than to> see 
> traits extending structs or traits extending a `HasPrefix` trait,> as was 
> included in previous designs. Both of those approaches mean> that the trait 
> is no longer "pure interface", and if you write> "generic" code against that 
> trait, you're actually coding at least> partially against a fixed 
> implementation, not an interface.)

I think traits inheriting structs is a better design, because you can have 
multiple traits inheriting the same struct.

For example, let's say you are modelling GUI widgets which need both input 
handling and drawing support.

With traits inheriting structs, you can have several traits, one for input 
handling, 
one for drawing in memory, one for drawing with OpenGL, etc., while with 
virtual functions (and without multiple inheritance) you have to put everything 
together and you have to either implement 
all functionality or add "not supported" error codes.

In other words, a trait inheriting a struct neatly separates the trait part 
where multiple inheritance is natural from the struct part where single 
inheritance is natural.
Also, a trait inheriting a Struct behaves to users of the trait exactly like a 
trait with a get_struct() accessor method, but with better performance.

It's only different for implementors, where it mandates how get_struct() is 
implemented for the sake of performance, at the cost of making it impossible to 
implement it along with traits inheriting from incompatible structs.

In general I think it's better to have multiple options at a low level like 
this, rather than having multiple option at an high-level semantic level like 
virtual struct vs trait, since that exposes the choice less to other modules.   

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Niko Matsakis
First off, it'd probably be best to wait to have this discussion until
the RFC is available, so that we can be sure we're all commenting on
the same thing. The current design evolved after many hours of
discussion about the precise performance requirements we wanted to
meet as well as exploring the design space that we saw (yes, this
includes the HasPrefix proposal). I'm not inclined to dive into the
full details of our thought process just yet; I'd rather include that
as part of the RFC or else as a blog post, because it's a very
complicated issue.

I personally think that offering some kind of virtual structs fits
completely within Rust. We've always tried to avoid "one size fits
all" thinking -- in real life there are performance tradeoffs, and you
often can't cover the entire space with a single design. This is why
we offer multiple pointer types, closures vs procs, and so forth.

I agree that the existing trait objects are the better approach in
most regards. They are extensible, so you can add new interfaces
later. They provide a convenient choice between static and dynamic
dispatch. In general, I hope that Rust programmers will reach for
traits first.

However, the extensibility of trait objects comes at the cost of fat
pointers, which can be a problem if you have a lot of pointers. It
also implies that downcasting isn't really possible, at least not
cheaply, because there is no notion of the "actual type" of a
particular object. The whole notion of downcasting rests on the idea
that there is a single dynamic type of the object that we can
test. (Downcasting can be emulated with virtual method dispatch, at
the cost of boilerplate and efficiency; but this is one of those
details I'd prefer to leave for a blog post or RFC.)

(As an aside, I am personally happier to see virtual structs than to
see traits extending structs or traits extending a `HasPrefix` trait,
as was included in previous designs. Both of those approaches mean
that the trait is no longer "pure interface", and if you write
"generic" code against that trait, you're actually coding at least
partially against a fixed implementation, not an interface.)

In summary, I believe that only providing trait objects is a kind of
"one size fits all" thinking.  In specialized cases, where single
inheritance is sufficient and extensibility is not desired, we can
offer other abstractions that perform better.



regards,

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Josh Matthews
>Is the 'all nodes consuming same amount of memory' too much memory?

Unfortunately yes, this is a very big problem. This solution has been
discussed in the past, but some of the elements types necessarily contain
far more members than others, and this would absolutely destroy memory
usage in the face of competing browsers.

Cheers,
Josh


On 12 March 2014 05:24, Maciej Piechotka  wrote:

> Recently I saw a video of person from scala team who regretted some
> 'pragmatic' choices in long run so I might be still under it's
> impression regarding pragmatic choices in a language. Fortunately (or
> unfortunately) I'm not in charge of Rust design.
>
> Also last question - why not use:
>
> struct Element {
> //... element specific elements
> }
>
> struct Attribute {
> //... attribute specific elements
> }
>
> enum NodeChild {
> NodeAttribute(Attribute),
> NodeElement(Element)
> }
>
> struct Node<'r> {
> parent: &'r Node,
> first_child: &'r Node,
> last_child: &'r Node,
> next_sibling: &'r Node,
> last_sibling: &'r Node,
> node: NodeChild
> }
>
> For static types:
>
> struct Element<'r> {
> elem: &'r Node
> }
>
> pub fn downcast_to_element<'r>(node: &'r Node) -> Option> {
> match (node.node) {
> NodeElement(_) -> Some(Element {elem: node}),
> _ -> None
> }
> }
>
> + impl with potentially partial methods? Is the 'all nodes consuming
> same amount of memory' too much memory?
>
> 1. One word pointers - check
> 2. Access to fields - check
> 3. Downcasting and upcasting - check
> 4. Inheritance with prefix property - check (sort of)
> 5. No need for behind-the-back optimization - check
>
> -. static dispatch (check) at the cost of match instead of jump with all
> its pros and cons
>
> Best regards
>
> On Tue, 2014-03-11 at 19:47 -0700, Patrick Walton wrote:
> > I thought about tricks like this, but (a) a sufficiently smart
> > compiler should *not* be doing this automatically, as it makes certain
> > common operations like fetching the pointer more expensive as well as
> > violating the principle of least surprise when it comes to machine
> > representation, and (b) does this sort of hack really result in a
> > cleaner design than having some simple language extensions? Mind you,
> > I'm all about ways to simplify Rust, but sometimes the simplest
> > solution is to build stuff into the language.
> >
> > On March 11, 2014 7:39:30 PM PDT, Maciej Piechotka
> >  wrote:
> > On Tue, 2014-03-11 at 14:18 -0700, Patrick Walton wrote:
> >  On 3/11/14 2:15 PM, Maciej Piechotka wrote:
> >  Could you elaborate on DOM? I saw it referred a
> few times but I haven't
> >  seen any details. I wrote simple bindings to
> libxml2 dom
> >  (https://github.com/uzytkownik/xml-rs -
> warning - I wrote it while I was
> >  learning ruby) and I don't think there was a
> problem of OO - main
> >  problem was mapping libxml memory management
> and rust's one [I gave up
> >  with namespaces but with native rust dom
> implementation it would be
> >  possible to solve in nicer way]. Of course - I
> might've been at too
> >  early stage.
> >
> >  You need:
> >
> >  1. One-word pointers to each DOM node, not two. Every
> DOM node has 5
> >  pointers inside (parent, first child, last child, next
> sibling, previous
> >  sibling). Using trait objects would 10 words, not 5
> words, and would
> >  constitute a large memory regression over current
> browser engines.
> >
> >  2. Access to fields common to every instance of a trait
> without virtual
> >  dispatch. Otherwise the browser will be at a
> significant performance
> >  disadvantage relative to other engines.
> >
> >  3. Downcasting and upcasting.
> >
> >  4. Inheritance with the prefix property, to allow for
> (2).
> >
> >  If anyone has alternative proposals that handle these
> constraints that
> >  are more orthogonal and are pleasant to use, then I'm
> happy to hear
> >  them. I'm just saying that dismissing the feature out
> of hand is not
> >  productive.
> >
> >  Patrick
> >
> >
> >
> > Ok. I see where my misunderstanding was - I was thinking
> > about DOM
> > implementation in Ruby for Ruby while you (Mozilla) were talking
> about
> > implementation in Ruby for JavaScript.
> >
> > Please feel free to ignore next paragraph as I haven't given it
> much
> > though but my guess would be that it would be possible to avoid
> the
> > penalty by enum + alignment + smart compiler. As data have 6
> words + in
> > your scheme (

Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Nathan Myers

On 03/11/2014 02:18 PM, Patrick Walton wrote:
> You need:
> 1. One-word pointers to each DOM node, not two...
> 2. Access to fields common to every instance of a trait without
>   virtual dispatch...
> 3. Downcasting and upcasting.

Let's look at what C++ virtual functions F and the classes T they
operate on really amount to.

At runtime, class T is just a const global array V of pointers to
those functions F. A T instance is just a struct with &V in it.
The functions F are notable only for having a T* first argument,
but that is really just a C++ convention. You can field those with
no difficulty in C, as indeed GTK+ does.

A derived class T2 is another const global array V2 of pointers to
functions F2, the first N of which are stack-frame compatible with
F, and, each, optionally identical.  The T2 instance is another
struct, with its first member an instance of T. Nothing there
conflicts with the Rust we know.

Compile time support is only a little more specialized.  We need
some representation-preserving type coercions for the various pointers.
(For multiple inheritance, some of the coercions would add a compile-
time constant.)  The only type-compatibility enforcement needed is for
the function-argument lists.

The const-global-array-of-function-pointers has been called a driver,
and the struct-with-a-pointer-to-it has been a file (or FILE, or FCB
to old-timers) for longer than I have been alive.  Syntactic sugar to
extend T and V, and enforcing F2 compatibility with F, takes us all the
way to "object-oriented".

It would be a good demonstration of Rust expressiveness to make object
orientation a library construct.  Having that in the standard library
would suffice for interoperability. Language primitives just sufficient
to enable such a library would be more useful than wired-in support.

Given such primitives, esoteric constructions like virtual inheritance
could be left to ambitious users.

Nathan Myers

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-12 Thread Maciej Piechotka
Recently I saw a video of person from scala team who regretted some
'pragmatic' choices in long run so I might be still under it's
impression regarding pragmatic choices in a language. Fortunately (or
unfortunately) I'm not in charge of Rust design.

Also last question - why not use:

struct Element {
//... element specific elements
}

struct Attribute {
//... attribute specific elements
}

enum NodeChild {
NodeAttribute(Attribute),
NodeElement(Element)
}

struct Node<'r> {
parent: &'r Node,
first_child: &'r Node,
last_child: &'r Node,
next_sibling: &'r Node,
last_sibling: &'r Node,
node: NodeChild
}

For static types:

struct Element<'r> {
elem: &'r Node
}

pub fn downcast_to_element<'r>(node: &'r Node) -> Option> {
match (node.node) {
NodeElement(_) -> Some(Element {elem: node}),
_ -> None
}
}

+ impl with potentially partial methods? Is the 'all nodes consuming
same amount of memory' too much memory?

1. One word pointers - check
2. Access to fields - check
3. Downcasting and upcasting - check
4. Inheritance with prefix property - check (sort of)
5. No need for behind-the-back optimization - check

-. static dispatch (check) at the cost of match instead of jump with all
its pros and cons

Best regards

On Tue, 2014-03-11 at 19:47 -0700, Patrick Walton wrote:
> I thought about tricks like this, but (a) a sufficiently smart
> compiler should *not* be doing this automatically, as it makes certain
> common operations like fetching the pointer more expensive as well as
> violating the principle of least surprise when it comes to machine
> representation, and (b) does this sort of hack really result in a
> cleaner design than having some simple language extensions? Mind you,
> I'm all about ways to simplify Rust, but sometimes the simplest
> solution is to build stuff into the language.
> 
> On March 11, 2014 7:39:30 PM PDT, Maciej Piechotka
>  wrote:
> On Tue, 2014-03-11 at 14:18 -0700, Patrick Walton wrote:
>  On 3/11/14 2:15 PM, Maciej Piechotka wrote:
>  Could you elaborate on DOM? I saw it referred a few 
> times but I haven't
>  seen any details. I wrote simple bindings to libxml2 
> dom
>  (https://github.com/uzytkownik/xml-rs - warning - I 
> wrote it while I was
>  learning ruby) and I don't think there was a problem 
> of OO - main
>  problem was mapping libxml memory management and 
> rust's one [I gave up
>  with namespaces but with native rust dom 
> implementation it would be
>  possible to solve in nicer way]. Of course - I 
> might've been at too
>  early stage.
>  
>  You need:
>  
>  1. One-word pointers to each DOM node, not two. Every DOM 
> node has 5 
>  pointers inside (parent, first child, last child, next 
> sibling, previous 
>  sibling). Using trait objects would 10 words, not 5 words, 
> and would 
>  constitute a large memory regression over current browser 
> engines.
>  
>  2. Access to fields common to every instance of a trait 
> without virtual 
>  dispatch. Otherwise the browser will be at a significant 
> performance 
>  disadvantage relative to other engines.
>  
>  3. Downcasting and upcasting.
>  
>  4. Inheritance with the prefix property, to allow for (2).
>  
>  If anyone has alternative proposals that handle these 
> constraints that 
>  are more orthogonal and are pleasant to use, then I'm happy 
> to hear 
>  them. I'm just saying that dismissing the feature out of 
> hand is not 
>  productive.
>  
>  Patrick
>  
> 
> 
> Ok. I see where my misunderstanding was - I was thinking
> about DOM
> implementation in Ruby for Ruby while you (Mozilla) were talking about
> implementation in Ruby for JavaScript.
> 
> Please feel free to ignore next paragraph as I haven't given it much
> though but my guess would be that it would be possible to avoid the
> penalty by enum + alignment + smart compiler. As data have 6 words + 
> in
> your scheme (5 described + vtable) the 4 bit alignment (assuming 32+ 
> bit
> platform) should not cause much memory waste. This allows for using 
> the
> 'wasted' bits for other purposes (the trick is used in, for example,
> lock-free structures) - for example:
> 
> enum ElementChild<'r> {
>ElementChildElement(&'r Element),
>ElementChildComment(&'r Com

Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Oren Ben-Kiki
I like the way this handles all sorts of "trivial casts". There seems to be
a downside in that "inherited" struct field access becomes very noisy.
Perhaps it would be possible to unify this with an anonymous fields syntax
to get the best of both worlds?


On Wed, Mar 12, 2014 at 1:51 AM, Vadim Chugunov  wrote:

> By the way, I didn't see any discussion of the HasPrefix/Coercible
> proposalin 
> the workweek minutes.  Did anybody bring it up at all?
>
> Vadim
>
>
> On Tue, Mar 11, 2014 at 2:30 PM, Oren Ben-Kiki  wrote:
>
>> I can't help but feel that forcing the "single inheritance of fast field
>> access" and "inheritance of trait functions" into one mechanism would be
>> regrettable.
>>
>> Would https://github.com/mozilla/rust/issues/10491 address all the
>> requirements? If not, why?
>>
>>
>> On Tue, Mar 11, 2014 at 10:52 PM, Brian Anderson 
>> wrote:
>>
>>> The downsides you list are all more or less applicable to this design,
>>> indeed. We are seeing real requirements in real code that indicates that
>>> the current abstraction facilities provided by Rust are efficient enough
>>> for certain demanding use cases (the DOM in particular).
>>>
>>> Here are the identified requirements:
>>>
>>> tree of types (single inheritance)
>>> downcasting
>>> thin pointers
>>> cheap field access
>>> easy upcasting
>>>
>>
>> ___
>> 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] "Virtual fn" is a bad idea

2014-03-11 Thread Patrick Walton
I thought about tricks like this, but (a) a sufficiently smart compiler should 
*not* be doing this automatically, as it makes certain common operations like 
fetching the pointer more expensive as well as violating the principle of least 
surprise when it comes to machine representation, and (b) does this sort of 
hack really result in a cleaner design than having some simple language 
extensions? Mind you, I'm all about ways to simplify Rust, but sometimes the 
simplest solution is to build stuff into the language.

On March 11, 2014 7:39:30 PM PDT, Maciej Piechotka  
wrote:
>On Tue, 2014-03-11 at 14:18 -0700, Patrick Walton wrote:
>> On 3/11/14 2:15 PM, Maciej Piechotka wrote:
>> > Could you elaborate on DOM? I saw it referred a few times but I
>haven't
>> > seen any details. I wrote simple bindings to libxml2 dom
>> > (https://github.com/uzytkownik/xml-rs - warning - I wrote it while
>I was
>> > learning ruby) and I don't think there was a problem of OO - main
>> > problem was mapping libxml memory management and rust's one [I gave
>up
>> > with namespaces but with native rust dom implementation it would be
>> > possible to solve in nicer way]. Of course - I might've been at too
>> > early stage.
>> 
>> You need:
>> 
>> 1. One-word pointers to each DOM node, not two. Every DOM node has 5 
>> pointers inside (parent, first child, last child, next sibling,
>previous 
>> sibling). Using trait objects would 10 words, not 5 words, and would 
>> constitute a large memory regression over current browser engines.
>> 
>> 2. Access to fields common to every instance of a trait without
>virtual 
>> dispatch. Otherwise the browser will be at a significant performance 
>> disadvantage relative to other engines.
>> 
>> 3. Downcasting and upcasting.
>> 
>> 4. Inheritance with the prefix property, to allow for (2).
>> 
>> If anyone has alternative proposals that handle these constraints
>that 
>> are more orthogonal and are pleasant to use, then I'm happy to hear 
>> them. I'm just saying that dismissing the feature out of hand is not 
>> productive.
>> 
>> Patrick
>> 
>> 
>
>Ok. I see where my misunderstanding was - I was thinking about DOM
>implementation in Ruby for Ruby while you (Mozilla) were talking about
>implementation in Ruby for JavaScript.
>
>Please feel free to ignore next paragraph as I haven't given it much
>though but my guess would be that it would be possible to avoid the
>penalty by enum + alignment + smart compiler. As data have 6 words + in
>your scheme (5 described + vtable) the 4 bit alignment (assuming 32+
>bit
>platform) should not cause much memory waste. This allows for using the
>'wasted' bits for other purposes (the trick is used in, for example,
>lock-free structures) - for example:
>
>enum ElementChild<'r> {
>   ElementChildElement(&'r Element),
>   ElementChildComment(&'r Comment),
>}
>
>Could be represented as pointer with last bit specifying if it's
>element
>or comment - similar to Option<&T> optimization. The lookup should
>behave much nicer with respect to branch prediction (plus) but getting
>pointer is more complicated (minus) and possibly longer code instead of
>jump (minus). If data alignes the compiler should be able to optimize
>the jumps if it notices that all jumps lead to the same pointer
>arithmetic. I'm not sure about handles from JS but I don't think there
>is more then 16 choices for types of parent/child/sibling for any node
>so it should be achivable - on language side it would just be enum +
>pointer (+ specification of alignment as attribute?).
>
>That said a) I have done no measurements/benchmarks so my intuition is
>likely to be wrong b) should in above paragraph means 'it looks that it
>could work after 5s thought' and c) I'm not a Rust designer and I don't
>pay for nor contribute so I don't expect that I should have anything
>resembling last word.
>
>Best regards
>
>
>
>
>___
>Rust-dev mailing list
>Rust-dev@mozilla.org
>https://mail.mozilla.org/listinfo/rust-dev

-- 
Sent from my Android phone with K-9 Mail. Please excuse my brevity.___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Maciej Piechotka
On Tue, 2014-03-11 at 14:18 -0700, Patrick Walton wrote:
> On 3/11/14 2:15 PM, Maciej Piechotka wrote:
> > Could you elaborate on DOM? I saw it referred a few times but I haven't
> > seen any details. I wrote simple bindings to libxml2 dom
> > (https://github.com/uzytkownik/xml-rs - warning - I wrote it while I was
> > learning ruby) and I don't think there was a problem of OO - main
> > problem was mapping libxml memory management and rust's one [I gave up
> > with namespaces but with native rust dom implementation it would be
> > possible to solve in nicer way]. Of course - I might've been at too
> > early stage.
> 
> You need:
> 
> 1. One-word pointers to each DOM node, not two. Every DOM node has 5 
> pointers inside (parent, first child, last child, next sibling, previous 
> sibling). Using trait objects would 10 words, not 5 words, and would 
> constitute a large memory regression over current browser engines.
> 
> 2. Access to fields common to every instance of a trait without virtual 
> dispatch. Otherwise the browser will be at a significant performance 
> disadvantage relative to other engines.
> 
> 3. Downcasting and upcasting.
> 
> 4. Inheritance with the prefix property, to allow for (2).
> 
> If anyone has alternative proposals that handle these constraints that 
> are more orthogonal and are pleasant to use, then I'm happy to hear 
> them. I'm just saying that dismissing the feature out of hand is not 
> productive.
> 
> Patrick
> 
> 

Ok. I see where my misunderstanding was - I was thinking about DOM
implementation in Ruby for Ruby while you (Mozilla) were talking about
implementation in Ruby for JavaScript.

Please feel free to ignore next paragraph as I haven't given it much
though but my guess would be that it would be possible to avoid the
penalty by enum + alignment + smart compiler. As data have 6 words + in
your scheme (5 described + vtable) the 4 bit alignment (assuming 32+ bit
platform) should not cause much memory waste. This allows for using the
'wasted' bits for other purposes (the trick is used in, for example,
lock-free structures) - for example:

enum ElementChild<'r> {
   ElementChildElement(&'r Element),
   ElementChildComment(&'r Comment),
}

Could be represented as pointer with last bit specifying if it's element
or comment - similar to Option<&T> optimization. The lookup should
behave much nicer with respect to branch prediction (plus) but getting
pointer is more complicated (minus) and possibly longer code instead of
jump (minus). If data alignes the compiler should be able to optimize
the jumps if it notices that all jumps lead to the same pointer
arithmetic. I'm not sure about handles from JS but I don't think there
is more then 16 choices for types of parent/child/sibling for any node
so it should be achivable - on language side it would just be enum +
pointer (+ specification of alignment as attribute?).

That said a) I have done no measurements/benchmarks so my intuition is
likely to be wrong b) should in above paragraph means 'it looks that it
could work after 5s thought' and c) I'm not a Rust designer and I don't
pay for nor contribute so I don't expect that I should have anything
resembling last word.

Best regards


signature.asc
Description: This is a digitally signed message part
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Vadim Chugunov
By the way, I didn't see any discussion of the HasPrefix/Coercible
proposalin
the workweek minutes.  Did anybody bring it up at all?

Vadim


On Tue, Mar 11, 2014 at 2:30 PM, Oren Ben-Kiki  wrote:

> I can't help but feel that forcing the "single inheritance of fast field
> access" and "inheritance of trait functions" into one mechanism would be
> regrettable.
>
> Would https://github.com/mozilla/rust/issues/10491 address all the
> requirements? If not, why?
>
>
> On Tue, Mar 11, 2014 at 10:52 PM, Brian Anderson wrote:
>
>> The downsides you list are all more or less applicable to this design,
>> indeed. We are seeing real requirements in real code that indicates that
>> the current abstraction facilities provided by Rust are efficient enough
>> for certain demanding use cases (the DOM in particular).
>>
>> Here are the identified requirements:
>>
>> tree of types (single inheritance)
>> downcasting
>> thin pointers
>> cheap field access
>> easy upcasting
>>
>
> ___
> 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] "Virtual fn" is a bad idea

2014-03-11 Thread Erick Tryzelaar
I've actually come around and now I'm starting to actually like this
virtual struct proposal, although not necessarily the example syntax (yay
bikeshed!). What brought me around is that if you squint your eyes a bit,
the example was mashing together struct inheritance and virtual methods
into one syntax. If we decouple the two we can get a more rust-y syntax (to
me) if we reify the anonymous trait into something that can be implemented
by substructures:

```
// Unsized structs are unsized but *can't* end with an unsized field (so
they can be extended)
unsized struct Base { id: int }
unsized struct Foo: Base { }
struct Bar: Foo  { }

impl Base {
fn a(); // impls can now have unimplemented methods
fn b() { }
}

impl Base for Foo {
fn a() { }
}

impl Foo {
fn c() { }
}

impl Base for Bar {}
impl Foo for Bar {}

fn do_something(t: &Base) {
println!("{}", t.id); // compiler can figure out the exact field offset
because `Base` is a struct trait
}

fn main() {
let bases = ~[
~Foo { id: 1 } as ~Base, // compiler uses the more optimal
`~(*vtable, obj)` because `Base` is a struct trait
~Bar { id: 2 } as ~Base,
];
for base in bases.iter() {
do_something(base);
}
}
```

One interesting thing we could do with this is allow named traits to also
derive from struct traits. This could allow parallel virtual method trees:

```
unsized struct Base { id: int }
unsized struct Foo: Base { }
struct Bar: Foo  { }

trait BaseTrait1: Base {
fn foo(&self) {
println!("{}", self.id); // exact offset because id comes from a
struct trait
}
}
impl BaseTrait1 for Base { }
impl BaseTrait1 for Foo { }
impl BaseTrait1 for Bar { }

trait BaseTrait2: Base {
fn bar(&self) {
println!("{}", self.id); // exact offset because id comes from a
struct trait
}
}
impl BaseTrait2 for Base { }
impl BaseTrait2 for Foo { }
impl BaseTrait2 for Bar { }

fn main() {
let bases = ~[ ~Foo as ~BaseTrait1, ~Bar as ~BaseTrait1 ]; // compiler
uses more optimal ~(*vtable, obj)` layout
for base in bases.iter() { base.foo() }

let bases = ~[ ~Foo as ~BaseTrait2, ~Bar as ~BaseTrait2 ];
for base in bases.iter() { base.foo() }
}
```

I'm not sure if there are any practical applications for this though.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Oren Ben-Kiki
I can't help but feel that forcing the "single inheritance of fast field
access" and "inheritance of trait functions" into one mechanism would be
regrettable.

Would https://github.com/mozilla/rust/issues/10491 address all the
requirements? If not, why?


On Tue, Mar 11, 2014 at 10:52 PM, Brian Anderson wrote:

> The downsides you list are all more or less applicable to this design,
> indeed. We are seeing real requirements in real code that indicates that
> the current abstraction facilities provided by Rust are efficient enough
> for certain demanding use cases (the DOM in particular).
>
> Here are the identified requirements:
>
> tree of types (single inheritance)
> downcasting
> thin pointers
> cheap field access
> easy upcasting
>
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Patrick Walton

On 3/11/14 2:19 PM, Haoyi Li wrote:

FWIW, C# requires that you mark overridable functions *virtual*, the
opposite of Java where you need to mark un-overridable functions
*final*. The Scala community is coming to the same conclusion that
unrestricted overriding is pretty dangerous. It's similar to monkey
patching, with all the convenience and danger it provides.


As a systems language we'd definitely need to keep virtual as 
non-default anyhow.


Patrick

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Haoyi Li
FWIW, C# requires that you mark overridable functions *virtual*, the
opposite of Java where you need to mark un-overridable functions *final*.
The Scala community is coming to the same conclusion that unrestricted
overriding is pretty dangerous. It's similar to monkey patching, with all
the convenience and danger it provides.


On Tue, Mar 11, 2014 at 2:15 PM, Maciej Piechotka wrote:

> On Tue, 2014-03-11 at 13:44 -0700, Patrick Walton wrote:
> > On 3/11/14 1:42 PM, Daniel Micay wrote:
> > > Existing object systems like COM, DOM and gobject are worth looking at,
> > > but Rust shouldn't bend over backwards to support them. They're legacy
> > > technologies and while interacting with them is important, I don't
> think
> > > it should result in any extra complexity being added to Rust.
> >
> > We have to support the technologies that are in use in a pleasant way,
> > or else Rust will not be practical. Regardless of your feelings about
> > existing OO systems, Rust has to support them well.
> >
> > So far nobody in this thread has demonstrated an understanding of the
> > constraints here. Traits are simply not sufficient to model the DOM, for
> > example.
> >
> > Patrick
> >
> >
>
> Could you elaborate on DOM? I saw it referred a few times but I haven't
> seen any details. I wrote simple bindings to libxml2 dom
> (https://github.com/uzytkownik/xml-rs - warning - I wrote it while I was
> learning ruby) and I don't think there was a problem of OO - main
> problem was mapping libxml memory management and rust's one [I gave up
> with namespaces but with native rust dom implementation it would be
> possible to solve in nicer way]. Of course - I might've been at too
> early stage.
>
> Regarding existing OO systems - Haskell interops with few of them (like
> gtk+ for example) using typeclasses without problems I know of. Possible
> next stage would be modelling the same hierarchy but since most systems
> use multiple inheritance in one form or another it would not help much.
>
> Best regards
>
> ___
> 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] "Virtual fn" is a bad idea

2014-03-11 Thread Patrick Walton

On 3/11/14 2:15 PM, Maciej Piechotka wrote:

Could you elaborate on DOM? I saw it referred a few times but I haven't
seen any details. I wrote simple bindings to libxml2 dom
(https://github.com/uzytkownik/xml-rs - warning - I wrote it while I was
learning ruby) and I don't think there was a problem of OO - main
problem was mapping libxml memory management and rust's one [I gave up
with namespaces but with native rust dom implementation it would be
possible to solve in nicer way]. Of course - I might've been at too
early stage.


You need:

1. One-word pointers to each DOM node, not two. Every DOM node has 5 
pointers inside (parent, first child, last child, next sibling, previous 
sibling). Using trait objects would 10 words, not 5 words, and would 
constitute a large memory regression over current browser engines.


2. Access to fields common to every instance of a trait without virtual 
dispatch. Otherwise the browser will be at a significant performance 
disadvantage relative to other engines.


3. Downcasting and upcasting.

4. Inheritance with the prefix property, to allow for (2).

If anyone has alternative proposals that handle these constraints that 
are more orthogonal and are pleasant to use, then I'm happy to hear 
them. I'm just saying that dismissing the feature out of hand is not 
productive.


Patrick

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Patrick Walton

On 3/11/14 2:09 PM, SiegeLord wrote:

On 03/11/2014 04:52 PM, Brian Anderson wrote:

Fortunately, this feature is independent of others and we can feature
gate it until it's right.

I think that's the crux of the issue some have with this. If a whole
another, completely disjoint path for inheritance and dynamic
polymorphism is required for the sake of efficiency, then maybe trait
objects should go?


You still need them for Java `interface`-like functionality, where you 
need to step outside the boundaries of single inheritance. Single 
inheritance alone is too limiting. You can do C++-like multiple 
inheritance in theory with thin pointers, but you lose runtime 
efficiency doing it that way (double dispatch for finding fields) and in 
practice people don't use multiple inheritance with the `virtual` in C++ 
very often for this reason.


Patrick

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Maciej Piechotka
On Tue, 2014-03-11 at 13:44 -0700, Patrick Walton wrote:
> On 3/11/14 1:42 PM, Daniel Micay wrote:
> > Existing object systems like COM, DOM and gobject are worth looking at,
> > but Rust shouldn't bend over backwards to support them. They're legacy
> > technologies and while interacting with them is important, I don't think
> > it should result in any extra complexity being added to Rust.
> 
> We have to support the technologies that are in use in a pleasant way, 
> or else Rust will not be practical. Regardless of your feelings about 
> existing OO systems, Rust has to support them well.
> 
> So far nobody in this thread has demonstrated an understanding of the 
> constraints here. Traits are simply not sufficient to model the DOM, for 
> example.
> 
> Patrick
> 
> 

Could you elaborate on DOM? I saw it referred a few times but I haven't
seen any details. I wrote simple bindings to libxml2 dom
(https://github.com/uzytkownik/xml-rs - warning - I wrote it while I was
learning ruby) and I don't think there was a problem of OO - main
problem was mapping libxml memory management and rust's one [I gave up
with namespaces but with native rust dom implementation it would be
possible to solve in nicer way]. Of course - I might've been at too
early stage.

Regarding existing OO systems - Haskell interops with few of them (like
gtk+ for example) using typeclasses without problems I know of. Possible
next stage would be modelling the same hierarchy but since most systems
use multiple inheritance in one form or another it would not help much.

Best regards


signature.asc
Description: This is a digitally signed message part
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread SiegeLord

On 03/11/2014 04:52 PM, Brian Anderson wrote:

Fortunately, this feature is independent of others and we can feature
gate it until it's right.
I think that's the crux of the issue some have with this. If a whole 
another, completely disjoint path for inheritance and dynamic 
polymorphism is required for the sake of efficiency, then maybe trait 
objects should go?


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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Patrick Walton

On 3/11/14 1:42 PM, Daniel Micay wrote:

Traits already provide a choice between monomorphization and virtual
function tables. I hope that the existing system can be extended in an
orthogonal way. I would be very disappointed if Rust ended up like C++,
where you have two almost completely exclusive systems.


This is as orthogonal of a way as we could come up with while 
maintaining the constraints of (a) one pointer, not two; (b) statically 
accessed fields at known offsets through trait objects; (c) the prefix 
property for single inheritance.


Patrick

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Brian Anderson
The downsides you list are all more or less applicable to this design, 
indeed. We are seeing real requirements in real code that indicates that 
the current abstraction facilities provided by Rust are efficient enough 
for certain demanding use cases (the DOM in particular).


Here are the identified requirements:

tree of types (single inheritance)
downcasting
thin pointers
cheap field access
easy upcasting

The big problem that putting virtual methods on structs solves is 
removing the need for fat pointers to objects - with a lot of trait 
objects this can involve many duplicated words.


Fortunately, this feature is independent of others and we can feature 
gate it until it's right. So as with many aspects of Rust's design we 
are going to iterate on it using *real code* until it's right, and in 
the end Rust is going to be able to to provide the zero-cost 
abstractions necessary to write very high performance code.


Regards,
Brian


On 03/11/2014 12:09 PM, Bill Myers wrote:

I see a proposal to add "virtual struct" and "virtual fn" in the workweek 
meeting notes, which appears to add an exact copy of Java's OO system to Rust.

I think however that this should be carefully considered, and preferably not 
added at all (or failing that, feature gated and discouraged).

The core problem of "virtual functions" (shared by Java's classes, etc.) is 
that rather than exposing a single public API, they expose two: the API formed by public 
functions, and the API formed by virtual functions to be overridden by subclasses, and 
the second API is exposed in an inflexible and unclean way.

A much better way of allowing to override part of a struct's behavior is by 
defining a trait with the overridable functionality, and allowing to pass in an 
implementation of the trait to the base class, while also providing a default 
implementation if desired.

Another way is to have the "subclass" implement all the traits that the "base class" implements, 
include a field of the "base class" type, and then direct all non-overridden functionality to the "base 
class" (here syntax sugar can be easily added to eliminate the boilerplate, by automatically implementing all 
non-implemented trait functions by calling the same function on the base class field).

These approaches can be combined, as the first approach allows to change the "inside" 
behavior of the base class, while the second one allows to put extra behavior "around" 
the base class code.

The fact that OO using virtual functions (as opposed to traits) is a bad design 
is one of the crucial steps forward of the design of languages like Go and 
current Rust compared to earlier OO languages, and Rust should not go backwards 
on this.

Here is a list of issues with virtual functions:

1. Incentive for bad documentation

Usually there is no documentation for how virtual functions are supposed to be 
overridden, and it as awkward to add it since it needs to be mixed with the 
documentation on how to use the struct

2. Mishmashing multiple unrelated APIs

With traits, you could pass in multiple objects to implement separate sets of 
overridable functionality; with virtual structs you need to mishmash all those 
interfaces into a single set of virtual functions, all sharing data even when 
not appropriate.

3. No encapsulation

Private data for virtual function implementations is accessible to all other 
functions in the struct.

This means for instance that if you have a virtual function called "compute_foo()" that is 
implemented by default by reading a "foo" field in the base class, then all other parts of the base 
class can access "foo" too.

If anything else accesses mistakenly "foo" directly, which it can, then overriding 
"compute_foo()" will not work as expected.

If compute_foo() were provided by an external trait implementation, then "foo" 
would be private and inaccessible, eliminating the problem.

4. Data for overridden implementations left there in a "zombie" state.

In the above example, if you override "compute_foo()", the foo variable in the 
base class will no longer be used, yet it will still be present in the type and allocated 
in memory.

5. Inability to statically dispatch

With a trait implementation, you can pass the concrete type as a generic 
parameter, allowing static dispatch.

If you instead call an overridable virtual function, then you can't dispatch 
that statically at all (unless you add cumbersome syntax for that).

6. Adds a ton of unnecessary complexity to the language 

___
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] "Virtual fn" is a bad idea

2014-03-11 Thread Patrick Walton

On 3/11/14 12:09 PM, Bill Myers wrote:

I see a proposal to add "virtual struct" and "virtual fn" in the
workweek meeting notes, which appears to add an exact copy of Java's
OO system to Rust.

I think however that this should be carefully considered, and
preferably not added at all (or failing that, feature gated and
discouraged).

The core problem of "virtual functions" (shared by Java's classes,
etc.) is that rather than exposing a single public API, they expose
two: the API formed by public functions, and the API formed by
virtual functions to be overridden by subclasses, and the second API
is exposed in an inflexible and unclean way.

A much better way of allowing to override part of a struct's behavior
is by defining a trait with the overridable functionality, and
allowing to pass in an implementation of the trait to the base class,
while also providing a default implementation if desired.


This approach is not efficient enough for use cases like the DOM (two 
words on each pointer instead of one, for example), and doesn't allow 
for nonvirtual access of fields through a trait object.


Patrick

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Patrick Walton

On 3/11/14 1:42 PM, Daniel Micay wrote:

Existing object systems like COM, DOM and gobject are worth looking at,
but Rust shouldn't bend over backwards to support them. They're legacy
technologies and while interacting with them is important, I don't think
it should result in any extra complexity being added to Rust.


We have to support the technologies that are in use in a pleasant way, 
or else Rust will not be practical. Regardless of your feelings about 
existing OO systems, Rust has to support them well.


So far nobody in this thread has demonstrated an understanding of the 
constraints here. Traits are simply not sufficient to model the DOM, for 
example.


Patrick

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


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Daniel Micay
On 11/03/14 03:59 PM, Clark Gaebel wrote:
> I like virtual functions. They're not for everything, and stylistically,
> traits are almost always a better solution. However, they can be nice to
> reduce code bloat. See how the LLVM devs managed to share a good amount
> of code for their SmallVector class thanks to the magic of virtual
> functions:
> 
> http://llvm.org/docs/doxygen/html/classllvm_1_1SmallVector.html
> 
> Not sure if it deserves a whole keyword, but a way to do this
> efficiently would be nice.
> 
>   - Clark

Traits already provide a choice between monomorphization and virtual
function tables. I hope that the existing system can be extended in an
orthogonal way. I would be very disappointed if Rust ended up like C++,
where you have two almost completely exclusive systems.

I think object inheritance is a very counter-intuitive concept, without
much basis in either the real world or theory. Traits could be extended
to include non-virtual fields, without us having the concept of base
classes.

Existing object systems like COM, DOM and gobject are worth looking at,
but Rust shouldn't bend over backwards to support them. They're legacy
technologies and while interacting with them is important, I don't think
it should result in any extra complexity being added to Rust.



signature.asc
Description: OpenPGP digital signature
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Maciej Piechotka
See for example
http://jscience.org/api/org/jscience/mathematics/structure/Field.html
and
http://jscience.org/api/org/jscience/mathematics/number/Float64.html.
Now you cannot just use Double as to use
http://jscience.org/api/org/jscience/mathematics/function/Polynomial.html you 
need to have a type that implements Ring. Then you needed to perform a few 
operations on polynomial and feed it to different library which had it own 
interfaces for float. You cannot just add static method as you're not an user 
of it - the other component is so using interface to abstract numeric 
operations, so function is not a viable workaround (BTW - I don't remember if 
jscience is one of libraries which I've used - they just appeared as one of 
first in Google).

And sure, in ideal world all packages would have one interface but it
wasn't something I controlled or anyone remotely connected with project.
And I wasn't somehow inclined to rewrite 2 libraries.

Another example would be interface which could be implemented in terms
of another. So interface A is subset of B. You could make A a
subinterface of B but it isn't and it is not something you control (for
example first project don't want to depend on second, or does not know
of its existence, or the work is in progress but it hasn't been done
yet).

If you happen to have control over whole system you're in much easier
situation as you can make a single sane hierarchy. If you don't and you
try to pull a few external libraries to work together as a small
component of a larger project it's much more of a problem.

Best regards

On Tue, 2014-03-11 at 15:00 -0500, Evan G wrote:
> I still don't a hundred percent understand... what interface could
> there be that doesn't require the object to store the state necessary
> to implement it? I mean, anything else is really just a function,
> instead of 60.days_after(date) use days_after(60, date).
> 
> 
> On Tue, Mar 11, 2014 at 2:51 PM, Maciej Piechotka
>  wrote:
> On Tue, 2014-03-11 at 14:37 -0500, Evan G wrote:
> > ... Why didn't they just extend Number? (Or, at worst, that
> was a bad
> > design decision on Oracle's part, by choosing to make the
> Float class
> > final)
> >
> > Either way, I don't see how that's a fault of the language.
> >
> >
> 
> 
> I don't remember - maybe they had, but it wouldn't solved the
> problem.
> And Float is final - and even if it hadn't been it wouldn't
> solve the
> problem at all. Assume that Float is not final and they did
> extended
> Number.
> 
>  - Platform P provides interface PI and object PO (say Number
> and Float)
>  - Component A provided and required interface AI and object
> AO
> extending PO and implementing AI and PI
>  - Component B provided and required interface BI and object
> AO
> extending PO and implementing BI and PI
> 
> Now you cannot pass object AO to component B as it requires
> BI. You need
> either:
>  - Provide adapter from AI to BI (or other way round) which
> implements
> AI, BI and PI
>  - Each time convert from AO to BO when you transfer between
> interfaces
> In proposed interface there would be only second option due to
> single
> inheritance.
> 
> On the other hand with traits:
>  - Platform P provides interface PI and object PO
>  - Component A provides and requires interface AI and
> implements AI for
> PO (there is no need for adding AI as PO is 'open' for trait
> implementation)
>  - Component B provides and requires interface BI and
> implements BI for
> PO (there is no need for adding BI as PO is 'open' for trait
> implementation)
> The user needs to do:
>  - Nothing. Everything works out of the box
> 
> And before you ask - component A and B were 2 different
> libraries for
> which the Oracle interfaces were insufficient.
> 
> Best regards
> 
> >
> > On Tue, Mar 11, 2014 at 2:35 PM, Maciej Piechotka
> >  wrote:
> > On Tue, 2014-03-11 at 19:09 +, Bill Myers wrote:
> > > I see a proposal to add "virtual struct" and
> "virtual fn" in
> > the workweek meeting notes, which appears to add an
> exact copy
> > of Java's OO system to Rust.
> > >
> > > I think however that this should be carefully
> considered,
> > and preferably not added at all (or failing that,
> feature
> > gated and discouraged).
> > >
> > > The core problem of "virtual functions" (shared by
> Ja

Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Nathan Myers

Bill's posting pleases me more than any other I have seen
so far.

Virtual functions in C++ have been an especially fruitful
source of unfortunate consequences, both in the language and
in users' programs.  It is common in C++ coding guidelines
to forbid public virtual functions, to help avoid mixing
implementation details into a public interface, but that
only mitigates one problem.

Virtual functions have been a source of confusion, too,
because they can be overloaded two different ways, with
identical syntax but radically different semantics. The
compiler cannot help catch mistakes because either might
reasonably have been intended.  This is part of the
rationale for "pure virtual" classes, just so that
failing to override a virtual as intended through some
trivial error stands some chance of being noticed. For
this reason, some coding guidelines go farther and _only_
allow overriding a parent's pure virtual functions.

Virtual functions are the chief ingredient in what Alex
Stepanov calls "O-O gook".  It should surprise no one
that Java and C# went the wrong way by making all member
functions virtual, thereby exposing all programs and all
programmers to these ills all the time.

That said, virtual functions do provide a more structured
form of function pointer, which we do need.  Any such feature
should start with the problems it must solve, and work toward
a defensible design, not by patching traditional O-O method
overriding. Rust has the advantage over early C++ that
lambdas and macros are available as well-defined building
blocks. Ideally, Rust's architectural replacement for
virtual functions would be purely a standard-library
construct, demonstrating greater expressiveness to enable
user code to do what another language is obliged to have
built into its core.

[aside: I don't know of any family connection to Bill.]

Nathan Myers

On 03/11/2014 12:09 PM, Bill Myers wrote:

I see a proposal to add "virtual struct" and "virtual fn" in the workweek 
meeting notes, which appears to add an exact copy of Java's OO system to Rust.

I think however that this should be carefully considered, and preferably not 
added at all (or failing that, feature gated and discouraged).

The core problem of "virtual functions" (shared by Java's classes, etc.) is 
that rather than exposing a single public API, they expose two: the API formed by public 
functions, and the API formed by virtual functions to be overridden by subclasses, and 
the second API is exposed in an inflexible and unclean way.

A much better way of allowing to override part of a struct's behavior is by 
defining a trait with the overridable functionality, and allowing to pass in an 
implementation of the trait to the base class, while also providing a default 
implementation if desired.

Another way is to have the "subclass" implement all the traits that the "base class" implements, 
include a field of the "base class" type, and then direct all non-overridden functionality to the "base 
class" (here syntax sugar can be easily added to eliminate the boilerplate, by automatically implementing all 
non-implemented trait functions by calling the same function on the base class field).

These approaches can be combined, as the first approach allows to change the "inside" 
behavior of the base class, while the second one allows to put extra behavior "around" 
the base class code.

The fact that OO using virtual functions (as opposed to traits) is a bad design 
is one of the crucial steps forward of the design of languages like Go and 
current Rust compared to earlier OO languages, and Rust should not go backwards 
on this.

Here is a list of issues with virtual functions:

1. Incentive for bad documentation

Usually there is no documentation for how virtual functions are supposed to be 
overridden, and it as awkward to add it since it needs to be mixed with the 
documentation on how to use the struct

2. Mishmashing multiple unrelated APIs

With traits, you could pass in multiple objects to implement separate sets of 
overridable functionality; with virtual structs you need to mishmash all those 
interfaces into a single set of virtual functions, all sharing data even when 
not appropriate.

3. No encapsulation

Private data for virtual function implementations is accessible to all other 
functions in the struct.

This means for instance that if you have a virtual function called "compute_foo()" that is 
implemented by default by reading a "foo" field in the base class, then all other parts of the base 
class can access "foo" too.

If anything else accesses mistakenly "foo" directly, which it can, then overriding 
"compute_foo()" will not work as expected.

If compute_foo() were provided by an external trait implementation, then "foo" 
would be private and inaccessible, eliminating the problem.

4. Data for overridden implementations left there in a "zombie" state.

In the above example, if you override "compute_foo()", the foo variable in the 
base class 

Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Clark Gaebel
I like virtual functions. They're not for everything, and stylistically,
traits are almost always a better solution. However, they can be nice to
reduce code bloat. See how the LLVM devs managed to share a good amount of
code for their SmallVector class thanks to the magic of virtual functions:

http://llvm.org/docs/doxygen/html/classllvm_1_1SmallVector.html

Not sure if it deserves a whole keyword, but a way to do this efficiently
would be nice.

  - Clark


On Tue, Mar 11, 2014 at 3:51 PM, Maciej Piechotka wrote:

> On Tue, 2014-03-11 at 14:37 -0500, Evan G wrote:
> > ... Why didn't they just extend Number? (Or, at worst, that was a bad
> > design decision on Oracle's part, by choosing to make the Float class
> > final)
> >
> > Either way, I don't see how that's a fault of the language.
> >
> >
>
> I don't remember - maybe they had, but it wouldn't solved the problem.
> And Float is final - and even if it hadn't been it wouldn't solve the
> problem at all. Assume that Float is not final and they did extended
> Number.
>
>  - Platform P provides interface PI and object PO (say Number and Float)
>  - Component A provided and required interface AI and object AO
> extending PO and implementing AI and PI
>  - Component B provided and required interface BI and object AO
> extending PO and implementing BI and PI
>
> Now you cannot pass object AO to component B as it requires BI. You need
> either:
>  - Provide adapter from AI to BI (or other way round) which implements
> AI, BI and PI
>  - Each time convert from AO to BO when you transfer between interfaces
> In proposed interface there would be only second option due to single
> inheritance.
>
> On the other hand with traits:
>  - Platform P provides interface PI and object PO
>  - Component A provides and requires interface AI and implements AI for
> PO (there is no need for adding AI as PO is 'open' for trait
> implementation)
>  - Component B provides and requires interface BI and implements BI for
> PO (there is no need for adding BI as PO is 'open' for trait
> implementation)
> The user needs to do:
>  - Nothing. Everything works out of the box
>
> And before you ask - component A and B were 2 different libraries for
> which the Oracle interfaces were insufficient.
>
> Best regards
>
> >
> > On Tue, Mar 11, 2014 at 2:35 PM, Maciej Piechotka
> >  wrote:
> > On Tue, 2014-03-11 at 19:09 +, Bill Myers wrote:
> > > I see a proposal to add "virtual struct" and "virtual fn" in
> > the workweek meeting notes, which appears to add an exact copy
> > of Java's OO system to Rust.
> > >
> > > I think however that this should be carefully considered,
> > and preferably not added at all (or failing that, feature
> > gated and discouraged).
> > >
> > > The core problem of "virtual functions" (shared by Java's
> > classes, etc.) is that rather than exposing a single public
> > API, they expose two: the API formed by public functions, and
> > the API formed by virtual functions to be overridden by
> > subclasses, and the second API is exposed in an inflexible and
> > unclean way.
> > >
> > > A much better way of allowing to override part of a struct's
> > behavior is by defining a trait with the overridable
> > functionality, and allowing to pass in an implementation of
> > the trait to the base class, while also providing a default
> > implementation if desired.
> > >
> > > Another way is to have the "subclass" implement all the
> > traits that the "base class" implements, include a field of
> > the "base class" type, and then direct all non-overridden
> > functionality to the "base class" (here syntax sugar can be
> > easily added to eliminate the boilerplate, by automatically
> > implementing all non-implemented trait functions by calling
> > the same function on the base class field).
> > >
> > > These approaches can be combined, as the first approach
> > allows to change the "inside" behavior of the base class,
> > while the second one allows to put extra behavior "around" the
> > base class code.
> > >
> > > The fact that OO using virtual functions (as opposed to
> > traits) is a bad design is one of the crucial steps forward of
> > the design of languages like Go and current Rust compared to
> > earlier OO languages, and Rust should not go backwards on
> > this.
> > >
> > > Here is a list of issues with virtual functions:
> > >
> > > 1. Incentive for bad documentation
> > >
> > > Usually there is no documentation for how virtual functions
> > are supposed to be overridden, and it as awkward to add it
> > since it needs to be mixed with the documentation on how to
> > use the st

Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Maciej Piechotka
On Tue, 2014-03-11 at 14:37 -0500, Evan G wrote:
> ... Why didn't they just extend Number? (Or, at worst, that was a bad
> design decision on Oracle's part, by choosing to make the Float class
> final)
> 
> Either way, I don't see how that's a fault of the language.
> 
> 

I don't remember - maybe they had, but it wouldn't solved the problem.
And Float is final - and even if it hadn't been it wouldn't solve the
problem at all. Assume that Float is not final and they did extended
Number.

 - Platform P provides interface PI and object PO (say Number and Float)
 - Component A provided and required interface AI and object AO
extending PO and implementing AI and PI
 - Component B provided and required interface BI and object AO
extending PO and implementing BI and PI

Now you cannot pass object AO to component B as it requires BI. You need
either:
 - Provide adapter from AI to BI (or other way round) which implements
AI, BI and PI
 - Each time convert from AO to BO when you transfer between interfaces
In proposed interface there would be only second option due to single
inheritance.

On the other hand with traits:
 - Platform P provides interface PI and object PO
 - Component A provides and requires interface AI and implements AI for
PO (there is no need for adding AI as PO is 'open' for trait
implementation)
 - Component B provides and requires interface BI and implements BI for
PO (there is no need for adding BI as PO is 'open' for trait
implementation)
The user needs to do:
 - Nothing. Everything works out of the box

And before you ask - component A and B were 2 different libraries for
which the Oracle interfaces were insufficient.

Best regards

> 
> On Tue, Mar 11, 2014 at 2:35 PM, Maciej Piechotka
>  wrote:
> On Tue, 2014-03-11 at 19:09 +, Bill Myers wrote:
> > I see a proposal to add "virtual struct" and "virtual fn" in
> the workweek meeting notes, which appears to add an exact copy
> of Java's OO system to Rust.
> >
> > I think however that this should be carefully considered,
> and preferably not added at all (or failing that, feature
> gated and discouraged).
> >
> > The core problem of "virtual functions" (shared by Java's
> classes, etc.) is that rather than exposing a single public
> API, they expose two: the API formed by public functions, and
> the API formed by virtual functions to be overridden by
> subclasses, and the second API is exposed in an inflexible and
> unclean way.
> >
> > A much better way of allowing to override part of a struct's
> behavior is by defining a trait with the overridable
> functionality, and allowing to pass in an implementation of
> the trait to the base class, while also providing a default
> implementation if desired.
> >
> > Another way is to have the "subclass" implement all the
> traits that the "base class" implements, include a field of
> the "base class" type, and then direct all non-overridden
> functionality to the "base class" (here syntax sugar can be
> easily added to eliminate the boilerplate, by automatically
> implementing all non-implemented trait functions by calling
> the same function on the base class field).
> >
> > These approaches can be combined, as the first approach
> allows to change the "inside" behavior of the base class,
> while the second one allows to put extra behavior "around" the
> base class code.
> >
> > The fact that OO using virtual functions (as opposed to
> traits) is a bad design is one of the crucial steps forward of
> the design of languages like Go and current Rust compared to
> earlier OO languages, and Rust should not go backwards on
> this.
> >
> > Here is a list of issues with virtual functions:
> >
> > 1. Incentive for bad documentation
> >
> > Usually there is no documentation for how virtual functions
> are supposed to be overridden, and it as awkward to add it
> since it needs to be mixed with the documentation on how to
> use the struct
> >
> > 2. Mishmashing multiple unrelated APIs
> >
> > With traits, you could pass in multiple objects to implement
> separate sets of overridable functionality; with virtual
> structs you need to mishmash all those interfaces into a
> single set of virtual functions, all sharing data even when
> not appropriate.
> >
> > 3. No encapsulation
> >
> > Private data for virtual function implementations is
> accessible to all other functions in the struct.
> >
> > This means for instance that if you have a virtual function
> called "compute_foo()" that is implemented by

Re: [rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Maciej Piechotka
On Tue, 2014-03-11 at 19:09 +, Bill Myers wrote:
> I see a proposal to add "virtual struct" and "virtual fn" in the workweek 
> meeting notes, which appears to add an exact copy of Java's OO system to Rust.
> 
> I think however that this should be carefully considered, and preferably not 
> added at all (or failing that, feature gated and discouraged).
> 
> The core problem of "virtual functions" (shared by Java's classes, etc.) is 
> that rather than exposing a single public API, they expose two: the API 
> formed by public functions, and the API formed by virtual functions to be 
> overridden by subclasses, and the second API is exposed in an inflexible and 
> unclean way.
> 
> A much better way of allowing to override part of a struct's behavior is by 
> defining a trait with the overridable functionality, and allowing to pass in 
> an implementation of the trait to the base class, while also providing a 
> default implementation if desired.
> 
> Another way is to have the "subclass" implement all the traits that the "base 
> class" implements, include a field of the "base class" type, and then direct 
> all non-overridden functionality to the "base class" (here syntax sugar can 
> be easily added to eliminate the boilerplate, by automatically implementing 
> all non-implemented trait functions by calling the same function on the base 
> class field).
> 
> These approaches can be combined, as the first approach allows to change the 
> "inside" behavior of the base class, while the second one allows to put extra 
> behavior "around" the base class code.
> 
> The fact that OO using virtual functions (as opposed to traits) is a bad 
> design is one of the crucial steps forward of the design of languages like Go 
> and current Rust compared to earlier OO languages, and Rust should not go 
> backwards on this.
> 
> Here is a list of issues with virtual functions:
> 
> 1. Incentive for bad documentation
> 
> Usually there is no documentation for how virtual functions are supposed to 
> be overridden, and it as awkward to add it since it needs to be mixed with 
> the documentation on how to use the struct
> 
> 2. Mishmashing multiple unrelated APIs
> 
> With traits, you could pass in multiple objects to implement separate sets of 
> overridable functionality; with virtual structs you need to mishmash all 
> those interfaces into a single set of virtual functions, all sharing data 
> even when not appropriate.
> 
> 3. No encapsulation
> 
> Private data for virtual function implementations is accessible to all other 
> functions in the struct.
> 
> This means for instance that if you have a virtual function called 
> "compute_foo()" that is implemented by default by reading a "foo" field in 
> the base class, then all other parts of the base class can access "foo" too.
> 
> If anything else accesses mistakenly "foo" directly, which it can, then 
> overriding "compute_foo()" will not work as expected.
> 
> If compute_foo() were provided by an external trait implementation, then 
> "foo" would be private and inaccessible, eliminating the problem.
> 
> 4. Data for overridden implementations left there in a "zombie" state.
> 
> In the above example, if you override "compute_foo()", the foo variable in 
> the base class will no longer be used, yet it will still be present in the 
> type and allocated in memory.
> 
> 5. Inability to statically dispatch
> 
> With a trait implementation, you can pass the concrete type as a generic 
> parameter, allowing static dispatch.
> 
> If you instead call an overridable virtual function, then you can't dispatch 
> that statically at all (unless you add cumbersome syntax for that).
> 
> 6. Adds a ton of unnecessary complexity to the language   
>   
> 

7. Harder interoperability. For example I've encountered at least 2
Float interfaces for Java from 2 different libraries (both trying to
abstract over Float) which I need to use in one of my projects (long
story) - either one needed to have an adapter or there was a need to
convert float to float. In total there were 3 32-bit floats
representation in single function counting also the float. With traits
they would just add implementation to Java's float.

Best regards


signature.asc
Description: This is a digitally signed message part
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] "Virtual fn" is a bad idea

2014-03-11 Thread Bill Myers
I see a proposal to add "virtual struct" and "virtual fn" in the workweek 
meeting notes, which appears to add an exact copy of Java's OO system to Rust.

I think however that this should be carefully considered, and preferably not 
added at all (or failing that, feature gated and discouraged).

The core problem of "virtual functions" (shared by Java's classes, etc.) is 
that rather than exposing a single public API, they expose two: the API formed 
by public functions, and the API formed by virtual functions to be overridden 
by subclasses, and the second API is exposed in an inflexible and unclean way.

A much better way of allowing to override part of a struct's behavior is by 
defining a trait with the overridable functionality, and allowing to pass in an 
implementation of the trait to the base class, while also providing a default 
implementation if desired.

Another way is to have the "subclass" implement all the traits that the "base 
class" implements, include a field of the "base class" type, and then direct 
all non-overridden functionality to the "base class" (here syntax sugar can be 
easily added to eliminate the boilerplate, by automatically implementing all 
non-implemented trait functions by calling the same function on the base class 
field).

These approaches can be combined, as the first approach allows to change the 
"inside" behavior of the base class, while the second one allows to put extra 
behavior "around" the base class code.

The fact that OO using virtual functions (as opposed to traits) is a bad design 
is one of the crucial steps forward of the design of languages like Go and 
current Rust compared to earlier OO languages, and Rust should not go backwards 
on this.

Here is a list of issues with virtual functions:

1. Incentive for bad documentation

Usually there is no documentation for how virtual functions are supposed to be 
overridden, and it as awkward to add it since it needs to be mixed with the 
documentation on how to use the struct

2. Mishmashing multiple unrelated APIs

With traits, you could pass in multiple objects to implement separate sets of 
overridable functionality; with virtual structs you need to mishmash all those 
interfaces into a single set of virtual functions, all sharing data even when 
not appropriate.

3. No encapsulation

Private data for virtual function implementations is accessible to all other 
functions in the struct.

This means for instance that if you have a virtual function called 
"compute_foo()" that is implemented by default by reading a "foo" field in the 
base class, then all other parts of the base class can access "foo" too.

If anything else accesses mistakenly "foo" directly, which it can, then 
overriding "compute_foo()" will not work as expected.

If compute_foo() were provided by an external trait implementation, then "foo" 
would be private and inaccessible, eliminating the problem.

4. Data for overridden implementations left there in a "zombie" state.

In the above example, if you override "compute_foo()", the foo variable in the 
base class will no longer be used, yet it will still be present in the type and 
allocated in memory.

5. Inability to statically dispatch

With a trait implementation, you can pass the concrete type as a generic 
parameter, allowing static dispatch.

If you instead call an overridable virtual function, then you can't dispatch 
that statically at all (unless you add cumbersome syntax for that).

6. Adds a ton of unnecessary complexity to the language 
  
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev