"Virtual fn" is a bad idea

classic Classic list List threaded Threaded
54 messages Options
123
Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

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    

Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Maciej Piechotka
On Tue, 2014-03-11 at 19:09 +0000, 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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140311/74a50360/attachment.sig>

Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

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
> <uzytkownik2 at gmail.com> wrote:
>         On Tue, 2014-03-11 at 19:09 +0000, 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
>        
>         _______________________________________________
>         Rust-dev mailing list
>         Rust-dev at mozilla.org
>         https://mail.mozilla.org/listinfo/rust-dev
>        
>
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140311/1cf2a873/attachment.sig>

Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

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 <uzytkownik2 at gmail.com>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
> > <uzytkownik2 at gmail.com> wrote:
> >         On Tue, 2014-03-11 at 19:09 +0000, 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
> >
> >         _______________________________________________
> >         Rust-dev mailing list
> >         Rust-dev at mozilla.org
> >         https://mail.mozilla.org/listinfo/rust-dev
> >
> >
> >
> >
>
> _______________________________________________
> Rust-dev mailing list
> Rust-dev at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>
>


--
Clark.

Key ID     : 0x78099922
Fingerprint: B292 493C 51AE F3AB D016  DD04 E5E3 C36F 5534 F907
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140311/a92f8d8b/attachment-0001.html>

Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Nathan Myers
In reply to this post by Bill 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 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 at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>


Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Maciej Piechotka
In reply to this post by 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
> <uzytkownik2 at gmail.com> 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
>         > <uzytkownik2 at gmail.com> wrote:
>         >         On Tue, 2014-03-11 at 19:09 +0000, 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
>         >
>         >         _______________________________________________
>         >         Rust-dev mailing list
>         >         Rust-dev at mozilla.org
>         >         https://mail.mozilla.org/listinfo/rust-dev
>         >
>         >
>         >
>         >
>        
>
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140311/4a8a9f17/attachment.sig>

Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Daniel Micay
In reply to this post by Clark Gaebel
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.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140311/e075142c/attachment-0001.sig>

Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Patrick Walton-2
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


Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Patrick Walton-2
In reply to this post by Bill Myers
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


Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Brian Anderson
In reply to this post by Bill Myers
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 at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>


Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Patrick Walton-2
In reply to this post by Daniel Micay
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


Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

SiegeLord
In reply to this post by Brian Anderson
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

Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Patrick Walton-2
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


Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Maciej Piechotka
In reply to this post by Patrick Walton-2
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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140311/7b032787/attachment.sig>

Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Patrick Walton-2
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


Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Haoyi Li
In reply to this post by Maciej Piechotka
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 <uzytkownik2 at gmail.com>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 at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140311/6cc13b1a/attachment-0001.html>

Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Patrick Walton-2
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


Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Oren Ben-Kiki
In reply to this post by Brian Anderson
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 <banderson at mozilla.com>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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140311/cabf2b6e/attachment.html>

Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

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>(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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140311/f81b6523/attachment.html>

Reply | Threaded
Open this post in threaded view
|

"Virtual fn" is a bad idea

Vadim Chugunov
In reply to this post by Oren Ben-Kiki
By the way, I didn't see any discussion of the HasPrefix/Coercible
proposal<https://github.com/mozilla/rust/issues/9912#issuecomment-36073562>in
the workweek minutes.  Did anybody bring it up at all?

Vadim


On Tue, Mar 11, 2014 at 2:30 PM, Oren Ben-Kiki <oren at ben-kiki.org> 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 <banderson at mozilla.com>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 at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140311/aff24afd/attachment.html>

123