Groovy: Is there a way to implement multiple inheritance while using type-checking?

groovy, multiple-inheritance, typechecking

Solution

I don't think you can do that with classes. Maybe you'd wanted traits (under discussion update: available in Groovy 2.3 and already rocking!) or, for a pure dynamic solution, `@Mixin`, which you'd back up with a good test suite.

My guess: `@Delegate` is your best friend here, but, as it stands, you can only store a `Chest` object in a `Container` type variable. So you'd need some interfaces.

Even if the superclass is not under your control, you can use groovy `as` operator to make it implement an interface.

First, i rewrote your classes to remove the `abstract` and add interfaces:

import groovy.transform.TypeChecked as TC

interface HasMass { double mass }
interface HasContent { Entity[] getContent() }

@TC class Entity implements HasMass { double mass }

@TC class Location {
    Entity[] getContent() {
        [new Entity(mass: 10.0), new Entity(mass: 20.0)] as Entity[]
    }
}

Note i didn't added `HasContent` to `Location`, to show the usage of `as`.

Second, comes the `Container` and `Chest`. `@Delegate` is added and it auto-inherits the interfaces of the delegates:

@TC 
abstract class Container {
  @Delegate Location location = new Location()
  @Delegate Entity entity = new Entity()
}


@TC class Chest extends Container { }

Last, it becomes type-checkable, as long as you stick to interfaces:

@TC class Mult {
    static main(args) {
        def x // use 'def' for flow-typing
        Container c = new Chest() //Chest extends Container
        HasMass e = c
        x = e.mass
        def l = c as HasContent

        x = l.content  //Programmer error, should throw compile-time error

        assert c.content.collect { Entity it -> it.mass } == [10.0, 20.0]
    }
}

Problem

``` @groovy.transform.TypeChecked abstract class Entity { ... double getMass() { ... } ... } @groovy.transform.TypeChecked abstract class Location { ... Entity[] getContent() { ... } ... } @groovy.transform.TypeChecked abstract class Container {...} //inherits, somehow, from both Location and Entity @groovy.transform.TypeChecked class Main { void main() { double x Container c = new Chest() //Chest extends Container Entity e = c x = e.mass Location l = c x = l.content //Programmer error, should throw compile-time error } } ``` Essentially, is there a way to achieve this, without sacrificing any of the three properties outlines in `main()`: - Direct access to fields, even virtual fields - Assigning to both super-classes - Typechecking (at compile-time)

Original source