Search code examples
interfaceceylon

Implement inner non-static interface


I would like to instantiate an an inner non-static interface from outside the wrapping class.

Is this possible?

Consider the following code:

shared class AOuterClass() {
Integer val = 3;
shared interface AInterface {
        shared Integer val => outer.val;
    }
}

void test() {
    AOuterClass o = AOuterClass();
    object impl satisfies ???.AInterface{}
}

I think object impl satisfies o.AInterface{} would be my reasonable intuition, but the compiler does not allow it.


Solution

  • It is not possible in a case like your one.

    The Ceylon specification says (section 4.5.4 Class Inheritance):

    A subclass of a nested class must be a member of the type that declares the nested class or of a subtype of the type that declares the nested class. A class that satisfies a nested interface must be a member of the type that declares the nested interface or of a subtype of the type that declares the nested interface.

    So you can only satisfy a nested interface inside the declaring class, or in a subclass thereof. Similar language is there for extending a nested interface by a new interface.

    This does not directly mention object declarations, but those are merely a shortcut for class definitions, as elaborated a bit later, in Anonymous classes:

    The following declaration:

    shared my object red extends Color('FF0000') {
         string => "Red";
    }
    

    Is exactly equivalent to:

    shared final class \Ired of red extends Color {
         shared new red extends Color('FF0000') {}
         string => "Red";
    }
    
    shared my \Ired red => \Ired.red;
    

    Where \Ired is the type name assigned by the compiler.

    So this also covers object declarations as your one.

    What you might be able to do (I didn't test this):

    AOuterClass.AInterface test(){
        object o extends AOuterClass() {
           shared object impl satisfies AInterface{}
        }
        return o.impl;
    }
    

    Of course, this doesn't work for an existing AOuterClass object, just for a newly created one. Seeing that this allows accessing a private value of an object, this seems to be a good thing.