Multiple Inheritance Part 2: Possible directions

In the previous post in this series we discussed the disadvantages of the inheritance model we initially planned for Kotlin. Today we will talk about alternative designs.

Note that these posts are intended to provoke a discussion, so that we can benefit from your feedback and come up with a better design.

What’s out there

The previous post concluded with the following (incomplete) list of solutions to the problem of multiple inheritance available in other languages:

  • Java and C# have classes and interfaces, i.e. multiple interface inheritance and single implementation inheritance;
  • Scala has classes and traits that may implement methods and even have state, but their constructors can not have parameters;
  • Some other languages, like Fortress, do not allow state in traits;
  • <Your favorite language here>

We all know that Java’s approach is rock-solid, but imposes severe limitations on code reuse, so we would like to relax these limitations, but without getting ourselves into trouble. “First degree” of relaxing the limitations would be stateless traits (like in Fortress, and in [1]): no state in traits, no implicit overrides. Or we can trade inheritance of traits off for state and get mixins (like in Ruby). Relaxing the limitations even more we get to Scala’s traits that have state but no parameters for constructors, and one trait may override functions of another. Then we get to CZ’s classes with requires (as presented in [2]). The next step, I guess, would already be unrestricted multiple inheritance, like in C++.

We will skip a thorough analysis of each of these solutions, and just make a remark about state.

State. One important consideration is whether to allow multiple inheritance of state in this or that form. On the one hand, it seems to be very useful, but on the other hand, it imposes problems. One problem was discussed in the previous post under the name of Problem 2:

the implementation of Left assumes it’s initialized with 3, but it may call bar() that is implemented in Right and assumes everything is initialized with 4. This may cause some inconsistent behavior.

Another problem is that having state in a unit of inheritance (a class or trait or mixin) implies having a constructor there, and constructors may have side effects, and it’s important that those come in a predictable order.

Problem 2 is rather elegantly fixed by the Scala’s approach of having no parameters in the trait constructors. Unfortunately, the problem of constructor side-effects still stands: changing inheritance relations between traits (e.g. done by a library-writer) may reorder side-effects of their constructors upon creating a subclass instance (see this comment below). And this problem seems to be inevitable no matter what approach to multiple inheritance of state we choose (I wish someone could prove me wrong here!).

All that said, I’ll explain a design we are currently considering. As mentioned above, the purpose of this text is to start a discussion, so your feedback is very welcome.

The Kotlin way (Attempt #2)

First, I would like to note that at this point, we prefer conservative solutions, so that we could naturally extend them later if the set of features they provide is not enough.

In short, the current design can be described as follows:

  • Stateless traits: no properties with backing fields, no constructors,
  • that can “require” classes to be present in the set of supertypes of a concrete class that uses the trait,
  • with no automatic resolution for overriding conflicts: if a class inherits two implementations of something, it must override this something and provide its own implementation (i.e., choose from the inherited ones, or write its own from scratch, or mix the two).

So, we refrain from having multiple inheritance of state for now. I think it’s OK if we try it this way and consider relaxing the limitations later, if there’s a real demand for that.

Syntax. Now, let’s render this in some syntax. First question here is “Should we still call those stateless guys classes, or have a special term?” They differ from classes by imposing some limitations, and for now it is that they don’t have any state. If there are only classes, the user will fall into the following situation:

  • Nothing tells me that this class is special, so
  • I add a piece of state, and
  • the compiler complains about having no constructor, so
  • I simply add a constructor, and
  • get errors from some other classes telling me that I broke someone’s supertype lists, so
  • it takes some time before I track down the real cause of the error, which is no good.

It would be a lot better if I knew that this class bears some restrictions in the first place, so I wouldn’t make any changes blindly, and if I made a bad change, the compiler would know that I have violated a local restriction, and would complain appropriately. So, it’s better to have traits differ syntactically from unrestricted classes. So, let’s have a keyword trait in front of the declaration, rather than class1.

So, we have classes (state and all, but single inheritance) and traits (no state, no constructor, but multiple inheritance). Traits can declare (“require”, is CZ terms) one superclass, but not initialize it:

This allows traits to use members of a base class without interfering with the initialization logic.

One other syntactic issue is whether we should have a single homogenous supertype list (like in the example above) or something like Java’s “extends” and “implements” clauses, or even Scala’s “extends Class with Trait1 with Trait2 with Trait3″ syntax. The idea of making things explicit speaks for some syntactic separation of a class in the supertype list, for it is privileged in some way, i.e. having something like Java’s “extends” and “implements”, at least. On the other hand, we all know this annoying case in Java, when I turn an interface into an abstract class, and have to change all those subclasses that used to implement the interface, and now must extend the class. The change that could be syntactically local becomes non-local. This is why we’re inclined to have a homogenous supertype list, as in the example above.

Using traits

Now, we prohibit state in traits. It certainly is a significant limitation, but I would like to point out what it is not.

You CAN have properties in your traits. The limitation is that those properties can not have backing fields or initializers, but properties themselves may appear in traits:

Our trait declares an abstract property, and the class overrides it with a stateful one. Now, the trait can use the property, and by late binding of calls, if we call foo() on an object of C, we get 239 printed.

You CAN access state in your traits. The previous example shows how you can do it sort of indirectly, by making subclasses override a property you define, but there is another way. Remember that a trait may declare (require) a superclass:

In this example, we have a base class A, that defines a concrete property y and initializes it. The trait B extends this class, but does not pass a constructor parameter in, because traits have no initialization code at all. Note that B has access to the property y defined in A. Now, class C extends A and initializes it with 239, and extends B. Extending B is OK because B requires A, and we extend A, all right.
Now, what happens when we call foo() on an instance of C? It prints 478 (239 * 2), because the value of y is obtained from this instance, and the constructor of C has written 239 there.

Now, let’s look at the last example about traits:

How to resolve overriding conflicts. When we declare many types in out supertype list, it may appear that we inherit more than one implementation of the same method. For example:

Traits A and B both declare functions foo() and bar(). Both of them implement foo(), but only B implements bar() (bar() is not marked abstract in A, because this is the default for traits, if the function has no body). Now, if we derive a concrete class C from A, we, obviously, have to override bar() and provide an implementation. And if we derive D from A and B, we don’t have to override bar(), because we have inherited only one implementation of it. But we have inherited two implementations of foo(), so the compiler does not know, which one to choose, and forces us to override foo() and say what we want explicitly.

I think, it’s enough for today. Your comments are very welcome, as usual.

References

  1. Nathanael Shärli, Stéphane Ducasse, Oscar Nierstrasz, and Andrew Black. Traits: Composable Units of Behavior. ECOOP-2003, pdf preprint.
  2. Donna Malayeri and Jonathan Aldrich. CZ: multiple inheritance without diamonds. SIGPLAN Not. 44, 10 (October 2009), 21-40, a pdf preprint.

1 Earlier this post used to say the following:

One good way to do it is to have a qualifier on a class declaration, i.e. trait class instead of just class (we could say just trait, but there are some language extensibility considerations against it, which I do not want to dive into now).

But we have found a simple solution to our language extensibility problem, and the problem does not stand any more.

About Andrey Breslav

Andrey is the lead language designer working on Project Kotlin at JetBrains. He also works on making the Java language better, serving as a Java Community Process expert in a group for JSR-335 ("Project Lambda"), and occasionally speak at software conferences such as Devoxx or JavaOne.
This entry was posted in General, Language design and tagged . Bookmark the permalink.

57 Responses to Multiple Inheritance Part 2: Possible directions

  1. Nikita Skvortsov says:

    A misprint: in the example
    class C() : A(239), B {}
    It is said, calling foo() on C will print 239, but wont it print 478 (=239*2)?

  2. Jan Kotek says:

    In Scala traits with state are often used as cache. For example there is trait which caches ‘hashCode’ so it is computed only once.

    Other common use for trait in Scala is to provide ‘default value’ (returned when record does not exists) for Maps. And there would be no way to pass this value to stateless trait.

    I still think you should make simple rules and refuse to compile a few corner cases (diamonds).

    • The cases you refer to are interesting. Thanks.

      Diamonds are not corner cases, they may arise in library+user code system without any of the authors knowing without it, which basically prevents library writers from ever introducing new superclasses to existing classes, which is a very severe limitation.

  3. Henrik S Törnblom says:

    Again very interesting reading. Thanks.

  4. Peter says:

    Why don’t you just use traits as in scala. I think they work quite well there.

    • In case you meant to ask a question. As mentioned in the post, Scala traits have constructors whose side effects may be reordered if hierarchy changes. This is unpredictable, and we would like to avoid this as long as we can.

      • Steve says:

        This is completely new to me … care to explain where they have constructors without arguments?

        Isn’t the possibility to reorder the traits to change the implementation an obvious feature, e. g. class Foo extends Logging vs. class Foo extends LogAboveWarn with Logging?

        If you need it predictable instead, you can just tell which trait you actually want to use easily …

        • First, about constructors in Scala traits. In Scala, you can initialize a member variable in a trait with some arbitrary code, or even just print something, like this:

          trait A {
            val x = computeX()
            print("A")
          }

          This means that trait A has a constructor that is executed when an object of a class that mixes this trait in is created. In our example the constructor of A has an obvious side effect of printing “A” to the standard output. One can argue that something like this is not typical, but we should remember that the initializer computeX() may have side effects too, e.g., write something to some sort of a cache. So traits in Scala have constructors, and these constructors may have side effects.

          Now, let’s look at another trait and a class that mixes both traits in:

          trait B {
            print("B")
          }
          class AB() with A with B {
          }

          Ok, when I create an instance of AB(), the side effects are ordered according to the traits coming in, i.e. it prints “A” and then “B”.

          Now, my library evolves, and in the version 2 I decided to make my trait A extend B:

          trait A extends B {
            val x = computeX()
            print("A")
          }

          Look: I didn’t touch the class AB. I didn’t even touch the code inside the traits’ constructors, I only reused some of the code by extending B in A. But what the client who wrote AB gets is that the side effects are reordered: new AB() now prints “B” and then “A”.
          And this may cause bugs that are really difficult to track down, especially because the client code did not change AT ALL.

          • steve says:

            Aren’t those things you call “constructors” not pretty much akin to instance initializers, which even Java had from the early days?

            Looking at your problem at hand, I think it is completely academic. There are always things you can’t do as a library producer. It is like this in Java, in Scala and in pretty much every other language, too.

            Considering that the proposed goal of Kotlin is to “publish zero papers” about it, I think any solution here is far away from the possible design space. You probably have to take some existing approach and compromise.

            If you still haven’t figured out substantial parts of the language’s inheritance mechanism, how realistic is a beta release at the end of the year?

          • Whatever you call those things, they are there. :)

            The problem I described exists in Scala and does not exist in Java, because Java interfaces, unlike Scala traits, do not have “those things”.
            You might not be able to do some things as a library writer in any language. But it does matter what things you can’t do.

            So, I’d better deliver a language without this problem (and a possibility of relaxing the limitation at expense of introducing this problem, if it appears to be really needed, in practice).

            As of the beta plans: yes, I think it’s pretty realistic.

  5. This feels like an improvement over the previous MI proposal. The techniques for accessing state are not very direct, but do avoid diamond issues. I like where this is going.

  6. Nick Linker says:

    Why is the keywords “trait class” is used instead of just “trait”? (For me this sounds like unnecessary verbosity). Thanks.

    • *this reply is obsolete, see below*

      As mentioned in the post, there are some language extensibility considerations. Basically we would like some external plugins to allow traits to have all the syntactic elements of classes. This does not mean that a plugin could alter the inheritance model, but it can leverage, say, constructor syntax for traits to allow users to “instantiate” them by calling their “constructors” that would be actually compiled down to some factory method taking instances from a container, like DI frameworks do. For all this it is convenient if trait is syntactically just a special case of class, so having “trait” as a modifier is the easiest way to achieve this.

    • We have resolved our extensibility problems and now we simple say “trait”, not “trait class”. Thank you for your question.

  7. hans marggraff says:

    The gain from state in traits like in scala outweighs the risks.
    If a library writer changes print(a + b) to print(b +a) in its code, then any dependent class gets the same effect. It does not matter, whether the change is procesural or declarative. I believe coders will quickly learn to be aware of that. After all they are writing traits and not plain classes. Writing Scala, I was acutely aware of initialisation order and side effects.

    And doing it like Scala reduces learning. You can simply tell any Scala user, that they can use traits as before.
    Don’t just be different, fpr the sake of it.

    • The gain from state in traits like in scala outweighs the risks.

      Could you support this with some examples?

      • Robert Thau says:

        Well, for me, the benefits at least are in dealing with third-party class hierarchies. To give a concrete example:

        Android has a class called “Activity”, which corresponds roughly to a single screen of a mobile app, and a bunch of convenience subclasses — ListActivity, PreferenceActivity, MapActivity, and so forth — that support particular styles of interaction. Activities have an “onDestroy” hook that gets called when they are shut down — to terminate associated AsyncTasks, close associated Databases, unregister as an Observer of whatever kind, and so forth. But doing things this way can lead the implementation of all of these things to get coupled, in a single onDestroy that becomes a bit of a kitchen sink.

        One way to mitigate the coupling is to mix in a trait that runs a bunch of callbacks in its onDestroy, and supplies a method to add a callback to the list. That, in turn, lets you write an openDatabase which registers the associated “close” as a callback.

        In Scala, that’s easy — the list of callbacks is state (an extra attribute) that’s declared and managed by the trait. You could, alternatively, produce an ActivityWithCallbacks base class that manages the associated state (or implements the cleanup stuff directly). But then you couldn’t use it for MapActivity, whose superclass is plain Activity, not your variant.

        By the way, in this example, the ordering consideration is really unlikely to arise, since the state is effectively private to the trait. Conversely, when you have constraints that are all manipulating base-class state (because they can’t have state of their own), that might arguably make them more likely to step on each others’ toes, not less — particularly if the implementers of some of the traits in question chose to use a particular piece of base-class state in incompatible ways. In particular, this sort of thing could easily introduce ordering incompatibilities, or worse, between traits that could otherwise happily coexist.

        (BTW, one of my current projects is a Scala library for trying to mop up boilerplate in Android apps using this sort of technique, Positronic Net. Looking over the available material on Kotlin, it looks like it might be preferable generally — but a restriction to stateless traits would be a real stumbling block.)

        • Thank you for the use case.

        • I though about your use case a little and I think it can be easily done in Kotlin, by delegation. Something like

          class MyActivity() : MapActivity, Callbacks by CallbacksImpl() {
          // …
          }

          • Robert Thau says:

            It might, at that. Where I can imagine that getting awkward is if there are multiple trait-like entities that build on the Callbacks functionality in different, but compatible, ways. But it handles the simple version of the problem well enough…

          • @Robert: What do you think will make it awkward?

          • Robert Thau says:

            The basic thought was that if we wound up with multiple extensions in a class hierarchy of delegates rooted at “CallbacksImpl”, that might ultimately lead to similar issues involving multiple inheritance at that level…

          • If I understood you correctly, we’d have the same issues with stateful traits as well. Is this correct?

          • Robert Thau says:

            Well, the way we got to “CallbacksImpl” was to avoid having “Callbacks” as a stateful trait. The situation I’m imagining is what would be, in Scala, multiple other traits which build on the Callbacks functionality in various ways, but add some extra state of their own. There’s at least the potential for a tower of delegates with delegates, which could get awkward to manage.

            (BTW, once again, the usual case is that each of these traits is adding state for its own use, to avoid stepping on the toes of the others — in which case, the ordering considerations you’re worried about don’t matter much.

            Where ordering has mattered, in my experience, is with traits that override base-class methods to add their own special behavior, in ways which may not refer to trait-private state at all. For instance, in ScalaTest, the behavior you get by mixing both BeforeAndAfterEach and OneInstancePerTest into a Suite depends on the order in which you do it. Each overrides the runTests method — the first to call beforeEach and afterEach setup and teardown methods around each test, the second to create a separate test suite instance for running each test. So, if you add both, does beforeEach get called in the main test suite instance, or the private “InstancePerTest” copies? Depends on the order in which they’re mixed in.

            So, ordering issues do arise here, but not due to trait-private state: so far as I can tell, neither trait declares any.)

          • The ordering problems I am worried about do not necessarily have anything to do with who uses the state, because problems arise upon initialization and involve side effects of constructors (that can come in unpredictable order). Overriding something in a base class can always be troublesome, whether you have traits or not.

            If we are talking about keeping a little private state for our own, delegation looks like a pretty good fit. If there are a dozen variations of Callbacks implementations, they can build upon each other as an essentially separate hierarchy of classes and maybe traits and/or delegation, which seems OK to me.

          • Since both features are similar and the delegation one is much easier and has no edge cases that I can see:

            why don’t you just omit traits alltogether (at least for the first version)?

          • The main reason is that with delegation you don’t get true overriding, because the object you delegate to does not know that is is being delegated to, i.e. is you “override” some of its methods, it wouldn’t know that you did.

          • Why would the delegated object need to know that?

            Can you make an example to make it clear?

          • Let’s say I have a trait T with two functions:

            trait T {
            fun foo() : Unit
            fun bar() : Unit
            }

            Now I have a class I will delegate TO:
            class D() : T {
            override fun foo() { bar() }
            override fun bar() { print(“D”) }
            }

            And here’s my class that delegated to D:

            class C() : T by D() {
            override fun bar() { print(“C”) }
            }

            Now, I call bar() on C:

            C().foo()

            What does it print?

            It prints “D” (and not “C” as you might expect), because foo’s implementation is delegated to D() and this object does not have a way to know that bar() is overridden.

          • Robert Thau says:

            Well, here’s more from ScalaTest. I’ve already mentioned the BeforeAndAfterEach and OneInstancePerTest traits. Those still work as traits in Kotlin (as proposed); they’re stateless. However, there are also stateful traits that can get mixed into a Suite — for instance, the FixtureSuite trait, which needs to add state of its own to keep track of the fixtures that it’s managing.

            In Scala, these are all traits, so there’s a single way to add these standard extensions to suites. I guess in Kotlin, you’d need two: one for the stateless extensions (as traits), and another for the stateful ones (as delegates).

            However, FixtureSuite also wants to override some of the base class methods — in fact, the same ones as the other two. If I read your last message right, it’s awkward for delegates to do that, which means that implementing FixtureSuite would get awkward…

          • I don’t think it’s awkward for a delegate to “override” methods of the host class. It behaves strangely if happens the other way around: when a host class tries to override a method from the delegate.

    • MuppetGate says:

      >> And doing it like Scala reduces learning. You can simply tell any Scala user, that they can use traits as before. <<

      I suspect that they're targetting Java developers as a priority (Scala developers already have Scala, after all), in which case the scheme they've suggested makes more sense.

  8. Christopher Cobb says:

    I like the idea of having stateless things. They just feel good. And they are easy to understand. I’m sure there are many ways they could be useful even outside of MI.

    Cool!

  9. No, it doesn’t surprise me, but there is an easy fix to your example:

    class E() : D() {
    override fun bar() { print(“C”) }
    }

    class C() : T by E() {
    }

    It is also clearer, because you make it clear that you want to adapt D and not have general method in C.

    Alternatively, you could allow (a la C#)

    class C() : T by D() {
    override fun D.bar() { print(“C”) }
    }

    but less is probably more…

    • To me this “fix” is inconvenient enough not to prefer it to traits.

      The C# approach is not really relevant here, for D has no way to know what happens in C.

      • Well, it boilds down to if you want to create a toolbox like Scala with many ways to do similar things or less ways as in Java.
        I had the impression that you wanted to go the Java way here, to keep things simple.

        The C# thing was meant to be: you could implement it in a way that you modify the behavior of the delegate, so it’s syntactic sugar for the first example (an inlined E)

        • Well, the example with E has the following disadvantages:
          1. It eats up memory (especially PermGen space). In this sense traits are much better: no objects created at all, only constant number of .class files generated (vs. as many as subtypes in the E-example).
          2. The “C# way” requires delegation to go only to a newly created object, I cannot use, say, a parameter for that. That’s a huge limitation that seems to defeat the whole purpose of delegation as such.

          On the toolbox business. If we drop traits alltogether, we are left with classes, delegation and interfaces. Still three things. Following your argument, it’s much more appealing to drop delegation, but we are aiming at eliminating boilerplate here, and delegation introduces a lot of it if not supported on the language level…

          Do you think we should drop delegation?

          • I don’t think your arguments against against delegates are convincing – only being based on on the number of class files being generated.

            But that doesn’t mean that there are no other good reasons to pick traits instead of delegates – since it seems to work in Scala.
            Maybe some use cases only work with traits?

            That brings me to the next question: what is the boilerplate (that you mentioned) that can only be eliminated with delegates? Why is that no problem in Scala?

            I’d also have to study delegation in go – as it was mentioned in this thread.

            One thing that would make delegation more interesting is to delegate by an object.

            class C(e) : T by e {
            }

            This can be used to add an interface to an object
            while preserving all implemented interfaces of e.

            It could be used in methods like

            IPeekingIterable peeking(Iterable i);
            IResettableIterable resettable(Iterable i);

            where you get an object with both interfaces if you chain them.

          • Sure you can delegate by an object! This is the whole point of it (see here). You can use a complex expression as well:

            class Foo(x : Bar) : Buzz by x.getBuzzManager().getBuzz(now()) {

            }

            And the boilerplate (that by the way is not eliminated in Scala) is havnig all those delegating methods in your code (either written by hand or generated by an IDE).

          • That makes delegation even better –
            and another reason to think of skipping traits.

            Do you have a real example where traits are needed?

            In your example, if x.getBuzzManager().getBuzz(now()) is SomeInterface,
            does it mean that Foo is SomeInterface?

          • Just to clarify: in Kotlin, there are not interfaces as such, only traits.

            And when I say
            class X : Y by e { … }

            it means that my class has only the supertype Y, not other supertypes of e become supertypes of X.

  10. While I really like programming in Scala; I’m also liking where Kotlin’s going (particularly with the goal of a fast compiler and a great IDEA plugin :).

    However the worst thing about Scala by a mile is the ‘recompile all your code and your dependencies on the same major version of the scala compiler & make sure all your transitive dependencies do the same’ issue. One thing Java really got right was having a minimum bytecode level (1.5, 1.6 or whatever) so that all new compilers can output old bytecode and all your jars just worked & it doesn’t much matter which version of the compiler built the jars.

    With Scala thats not the case; every library developer has to cross compile for every major version of scala (and really you probably should do minor too to be safe) leading to jar & dependency problem explosions; then release cycles all block on 1 dependency dragging its heels or upgrading too quickly or whatever; you get stuck unable to upgrade until every transitive dependency has been rebuilt and re-released.

    It seems Scala’s stateful traits are the main culprit; changing a trait means classes using it need to be recompiled & if those traits are from the Scala SDK then everything has to be rebuilt.

    To be honest; I’d rather a nice simple stable ecosystem of jars/bundles/modules which are compiler version agnostic than have the benefit of stateful traits; so I just wanted to say (in a rather long winded manner :) keep up the good work – but please try to keep Kotlin a compiler that generates bytecode thats Kotlin-version-safe & is capable of reusing older and newer Kotlin-compiled-code without major issues. Plus try to not make backwards incompatible changes to whatever Kotlin Development Kit you ship (I’m guessing you’ll have a library with map / filter / flatMap / join and whatnot on collections kinda like Guava but available as Extension methods etc).

    I’d be much happier using just delegation and stateless traits if it means there’s no issues of which version of Kotlin was used to compile which jar. While in the early days of a language it can be tricky to fully maintain bytecode generated by older and newer compilers – I hope fairly early on you can get Kotlin to generate stable bytecode that can be mixed and matched easily among different Kotlin bytecode. Forcing the Kotlin ecosystem of jars to all rebuild should be a last resort every now and again (like the leap from 1.4 => 1.5 => 1.6).

    So I’d much rather you prioritise bytecode stability above fancy features like solving diamond inheritence or stateful traits :)

    • Thanks for your comment!

      I’d like to emphasize two priorities we have:

      Binary compatibility: we pay attention to what changes make clients recompile. Really. It is very important for us.
      Version compatibility: we guarantee nothing before version 1.0 is out. But after that, backward compatibility will stand firm. (And we do not expect any production code in Kotlin to be written outside JetBrains before Kotlin 1.0 is out.)

  11. Habfast says:

    I have read most of the comments, but not all of them, so I hope I’m not discussing again something.

    One possible issue I can see is the following one:
    class A(){}
    class B(){}
    trait C: A{
    //some really useful stuff
    }
    trait D: B{
    //some more extremely useful stuff
    }

    now, with the above design, if I understand correctly, I have absolutely no way of benefiting from the useful stuff in both C and D. I’ve never encountered this case since I mostly program in java nowadays and can’t recall having done anything similar in scala, so I don’t know how much of an issue it could be, but I see how I could get really frustrated when I would encounter something like that.

    great stuff, by the way =)

    • Thanks!

      I don’t think this blocking case you mention is likely to be a problem, because if something requires A, and something else requires B, this means that these two thing can’t do their useful stuff without being A and B respectively, and if they are designed this way, the design implies that you can’t have them both.

  12. Hi everyone, thanks for fancy reading!

    I do enjoy stateful traits in Scala, really. You see, for our educational project we’ve invented a tiny XML-(de)serialization library (mostly to get rid of clumsy Scala XML API).

    Our objects are mutable (yes, this approach makes our library already a bit out of the True Scala Way), because most of the time they are handled by application-wide cache (yes, mutable objects are shared across different threads, and we are totally OK with it), or they are used thread-locally and do not require external synchronization.

    Now, lots of our classes are composed of stateful traits. We define lots traits like these:


    trait Identifier extends ElemHolder {
    protected def _defaultId = randomString(8)
    protected val _id = attr("id").set(_defaultId)
    def id = _id()
    def setId(newId: String) {
    if (!const.regex.id.matcher(newId).matches)
    throw new ValidationException("id.syntax")
    _id := newId
    checkUniqueId()
    }
    def checkUniqueId() {}
    }

    trait UUID extends ElemHolder {
    protected val _uuid = attr("uuid").set(randomUUID)
    def uuid = _uuid()
    }

    trait Title extends ElemHolder {
    protected val _title = attr("title")
    def title = _title.getOrElse("")
    def setTitle(newTitle: String) {
    val t = newTitle.trim
    if (t == "")
    throw new ValidationException("title.empty")
    this._title := t
    }
    }

    and then we compose lots of classes out of them:


    class Foo extends StructHolder with Identifier with UUID with Title { ... }
    class Bar extends StructHolder with Identifier with UUID with Title { ... }
    ...

    Now, if we were not allowed to have state in traits (in my example it would mean “no vals inside!”), we would replace these mutable attributes inside with methods, and eventually come up with something like this:


    trait Identifier extends ElemHolder {
    // protected val _id = attr("id").set(_defaultId)
    protected def _id: AttrHolder
    // ...
    }

    Now every implementation is forced to define these missing pieces:


    class Foo extends StructHolder with Identifier with UUID with Title {
    val _id = attr("id").set(_defaultId)
    }

    So for our project it would mean a handful of boilerplate lines in every implementation, which could be safely avoided with stateful traits.

    On the other hand, I do like the order (in general sense), and I would prefer the overall tranquility over my own habits. Specifically, given that stateless trait limitation really helps to organize and discipline the code around, I would gladly rewrite it to conform to this new, more efficient paradigm.

  13. BTW, you are referring to “delegation supported by the language”, but I can’t seem to find anything related in the docs. Could you please point me to an explanation of this concept? TIA

  14. Oliver Plow says:

    Hello,
    let’s have a look at the perennial Rectangle example:

    public trait Rectangular {
    protected val upperLeft : Point
    protected val lowerRight : Point

    protected fun printBounds() {
    println(upperLeft)
    println(lowerRight)
    }
    }

    open class Rectangle(upperLeftParam: Point, lowerRightParam: Point) : Rectangular
    {
    override var upperLeft = upperLeftParam
    override var lowerRight = lowerRightParam

    fun foo() {
    printBounds()
    }
    }

    Now what I don’t like with this solution is that I have to declare variables in my class enforced by the contract with the trait where those variables are declared abstract. Reason is that I thought I had delegated all this to the trait and it’s not my concern anymore. I think a lot developers will think that way. Most of them don’t understand what the problem for the compiler constructor is here. Unless he reads some blog entry like this one. I like very much the way the Kotlin language creators communicate with people interested in the project. Ceylon is also trying to do this, but they do it much less. For all others there is at best a mailing list.

    Nevertheless, most developers wil just look at this and say: “No, what’s the gain?. Then I just go with Scala traits”. Not wanting to be rough. But that’s the way most “ordinary developers” like me will think, I believe. What I personally would do to get around it is this:

    open class AbstractRectangle(upperLeftParam: Point, lowerRightParam: Point) : Rectangular
    {
    override protected var upperLeft = upperLeftParam
    override protected var lowerRight = lowerRightParam
    }

    open class Rectangle(upperLeftParam: Point, lowerRightParam: Point) : AbstractRectangle(upperLeftParam, lowerRightParam)
    {
    fun foo() {
    printBounds()
    }
    }

    fun main(args: Array) {
    var rect = Rectangle(Point(0, 5), Point(5, 0))
    rect.foo()
    }

    Now, the overridden vars from the trait are out of my sight and >that’s all I want<. My question is now whether the compiler could generate that AbstractRectangle class and insert it silently so that the developer wouldn't know about it. If the developer declared

    open class Rectangle : C, Rectangular

    the compiler would just generate

    open class AbstractRectangle(upperLeftParam: Point, lowerRightParam: Point) : C, Rectangular

    open class Rectangle : AbstractRectangle

    But the code would still read

    open class Rectangle : C, Rectangular

    Maybe that's naive. I'm not a competent compiler constructor. Just an idea.

    • If we generated those classes, they’d help single inheritance, and not help multiple inheritance. If all you want is singly inherit from your trait — use an abstract class.

      BTW, your example are not fair. In fact, it is:

      open class Rectangle(
      override var upperLeftParam: Point,
      override var lowerRightParam: Point) : Rectangular
      {
      fun foo() {
      printBounds()
      }
      }

  15. Oliver Plow says:

    BTW, your example are not fair. In fact, it is:

    open class Rectangle(
    override var upperLeftParam: Point,
    override var lowerRightParam: Point) : Rectangular
    {
    }

    Ah! That’s cool. Didn’t know. Just tried something and thought that must be it when it compiled. Might be an idea to add this as a sample to http://confluence.jetbrains.net/display/Kotlin/Classes+and+Inheritance. Clarifies things a lot and prevents people from making dues.

  16. Oliver Plow says:

    What IMHO people are looking for in a language that will make them change from Java is extension methods, traits, closures (Java interoperability has to remain there, of course). JDK8 has closures and JDK8 default methods give you the same as what stateless traits give you except that you cannot have protected default methods. Extensions methods are really nice to have, but they won’t make you change language. If the problems with stateful traits can be solved, I’ll be the first one to develop everything in Kotlin :-).

  17. Sergey says:

    Possible typos in examples:
    - Paragraph “You CAN have properties in your traits”:
    - – “abstract” is redutant in trait

    - Paragraph “How to resolve overriding conflicts”
    - – this.foo() -> super.foo()
    - – this.foo() -> super.foo()

  18. I’m liking Kotlin pretty well so far!

    Have a few thoughts on type and inheritance…

    First a disclaimer: although I worked on Java, my knowledge of language design is relatively limited. That said, my book “Coding: On Software Design Process” has a couple sections at the end describing an interesting approach to type extension: “type arithmetic” and “type enhancers”. Although very sketchy, these ideas might be an interesting starting point for something less sketchy. The key feature of type enhancers is that they work only through the public API of the object being enhanced (a “that” reference). This means that constructor ordering is not an issue and you can enhance even final types like String. Through type arithmetic you can combine types not only by type declaration, but instantly through various kinds of usage. There could easily be some fatal flaw in my ideas here, but they might be worth a look anyway. — Jon

    • From your description, type enhancers look rather similar to extension functions/properties. Speaking of type arithmetic: the biggest issue there would be to keep it simple for the user.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">