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
> <uzytkown...@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@mozilla.org
>         https://mail.mozilla.org/listinfo/rust-dev
>         
> 
> 
> 

Attachment: 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

Reply via email to