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 <uzytkown...@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 > > <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 > > > > > > > > > > _______________________________________________ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -- Clark. Key ID : 0x78099922 Fingerprint: B292 493C 51AE F3AB D016 DD04 E5E3 C36F 5534 F907
_______________________________________________ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev