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

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