--- Title: Rust and Swift (xv) Subtitle: "Inheritance: a Swiftian specialty (for now)." Category: Tech Tags: [rust, swift, rust-and-swift, programming languages] Date: 2016-03-12 14:45 Series: Title: Rust and Swift Part: 15 ... I am reading through the Swift book, and comparing it to Rust, which I have also been learning over the past few months. As with the other posts in this series, these are off-the-cuff impressions, which may be inaccurate in various ways. I'd be happy to hear feedback! Note, too, that my preferences are just that: preferences. Your tastes may differ from mine. [(See all parts in the series.)][series] [series]: http://v4.chriskrycho.com/rust-and-swift.html --- The next chapter in the Swift book focuses on *inheritance*, a concept which does not yet exist in Rust. Swift embraces classical inheritance for `class` data types. As noted [previously][10], Rust's `struct` covers much of the ground covered by Swift's `struct` and `class` types together (value and reference types, etc.). However, what Swift's `class` types bring to the table is inheritance-based (and not just composition-based) extension of types. [10]: http://v4.chriskrycho.com/2015/rust-and-swift-x.html This is a bit of an interesting point: it is an area where, *as of today*, Swift can do something that is flat impossible in Rust---a rarity. However, the _status quo_ will be changing sometime in the next year or so, as there is a [Rust RFC][rfc] which has been accepted and is in the process of being implemented which paves the way for inheritance. (Discussions are [ongoing] as to the best way to implement it for Rust. Classical inheritance with vtables as in Swift is probably *not* going to be the approach.) [rfc]: https://github.com/rust-lang/rfcs/pull/1210 [ongoing]: https://aturon.github.io/blog/2015/09/18/reuse/ The reason Rust's core team chose to proceed without inheritance for the 1.0 release of the language last May is simple: at a philosophical level, they prefer (as in general most developers increasingly acknowledge that we should all prefer) composition over inheritance. *Prefer*, not *universally choose*, because there are situations in which inheritance is the correct choice. But there is a reason that programming with interfaces rather than via sub-classing is a "best practice" for many scenarios in languages like Java or C#. Rust's `trait` system gives you *composition* in some remarkably powerful ways, allowing you to do things that in C++, for example, have to be accomplished via a combination of inheritance and overloading. Swift, likewise, supplies a `protocol` system and allows extensions to define further behavior on top of existing data structures. From what I've gathered, those approaches are preferred over inheritance in Swift for the same reason Rust shipped 1.0 without it! But Swift does have inheritance, so it's worth seeing how it works. First, any `class` which doesn't declare a parent from which to inherit is a base class. This is an important difference from, say, Python, where all classes inherit from `Object` (leaving aside custom metaclasses). The syntax choices Swift has made around sub-class declarations are sensible and readable: `class SubClass: ParentClass` is eminently readable and doesn't have any obvious points of overlap with other elements in the language. Indeed, *many* of the choices made around classes are quite sensible. Overrides, for example, are made explicit via the `override` keyword. While I've sometimes poked fun at Swift's tendency to add keywords everywhere, this seems like a reasonable place to have one, and it's nice that overrides are explicit rather than implicit. The same is true of the use of `super` to refer to the superclass. I'm not sure of the implementation details, but `super` *appears* to act as just a special/reserved name for an object: all the syntax around it is normal object instance syntax, which is as it should be. The limitations around overriding properties all make sense. You can override a read- or write-only parent property as both readable and writable, but you can't override a readable or writable property *not* to be readable or writable respectively. Presumably this is because the method lookup for properties always checks up the inheritance chain for getters or setters, so if one is present, you can't just get rid of it. (You could of course override with a no-op function that spews a warning or some such, but that would pretty clearly be an abuse of the parent API. There might be times you would do that with a third-party library parent class, but in your own code it should be avoided: it indicates a problem in your API design that you need to address instead.) Finally, we have Swift's `final` keyword---and yes, pun intended. It marks whatever block-level item it is attached to---whether class, method, or property---as non-overridable. Attempts to override an item marked final are compile-time failures. (The same kind of thing exists in Java and C#.) In and of itself, this isn't especially interesting. It is interesting to ponder whether you should make classes subclass-able or not in your API design. There has been [an active debate], in fact, whether classes in Swift should become final *by default* in Swift 3.0, rather than open by default. The debate centers on the danger of unintended consequences of overriding, which ultimately takes us back around to the preference for composition, of course. [an active debate]: http://mjtsai.com/blog/2015/12/21/swift-proposal-for-default-final/ All of this, among other things, raises the very interesting question of what this will look like in Rust when, eventually, we get inheritance there. After all, we know it will be quite different in some ways: - It presumably won't involve a distinct data type constructor, _a la_ Swift's distinction between `struct` and `class`: there may be syntactic sugar involved, and there will definitely be new functionality present, but it will certainly be built on the existing language features as well. There's a good chance it will basically *look* like just a special case of `impl SomeTrait for SomeStruct`, which would fit very well with the ways Rust solves so many other problems. - Rust doesn't have many of the things which Swift takes care to special-case for overriding with `final`, but it will need to address that case for inherited methods and data in some way. (The proposal linked above uses a distinction between `default` and blanket implementations for trait specialization to pull this off; if those words don't mean anything to you, don't worry: I've read that post and RFC half a dozen times before I got a really solid handle on all the pieces involved.) - It will be a relative latecomer to the language, rather than baked in from the start, and therefore will likely seem a secondary way of solving problems, especially at first. (This is, I think, both intentional and good.) --- - [**Previous:** Indexing and subscripts, or: traits vs. keywords again.][14] - [**Next:** Initialization: another area where Swift has a lot more going on than Rust.][16] [14]: http://v4.chriskrycho.com/2016/rust-and-swift-xiv.html [16]: http://v4.chriskrycho.com/2016/rust-and-swift-xvi.html