eclipse-archived / ceylon

The Ceylon compiler, language module, and command line tools
http://ceylon-lang.org
Apache License 2.0
396 stars 62 forks source link

catchall methods #4219

Open CeylonMigrationBot opened 9 years ago

CeylonMigrationBot commented 9 years ago

[@gavinking] A "catchall" method allows a class to masquerade as an instance of a type that it doesn't fully implement.

We would define an interface Proxy in ceylon.language.meta.interceptors:

shared interface Proxy<Type> {
    shared formal Result invoke<Result,Args>
            (Result(*Args)(Type) method, Args args)
            given Args satisfies Anything[];
    //TODO: attribute get/set
}

Then the typechecker no longer complains when the class fails to implement all formal methods it inherits:

class ListProxy<T>(List<T> list) 
         satisfies Proxy<List<T>> & List<T> {
     invoke<Result,Args>
         (Result(*Args)(List<T>) method, Args args) 
         => method(list)(*args);
     //TODO: attribute get/set
}

Instead, the compiler generates implementations of the inherited formal methods that just call invoke.

[Migrated from ceylon/ceylon-spec#1113]

CeylonMigrationBot commented 9 years ago

[@gavinking] Related to #4218.

CeylonMigrationBot commented 9 years ago

[@quintesse] In the second code snippet above, shouldn't Proxy be mentioned in the satisfies?

CeylonMigrationBot commented 9 years ago

[@gavinking] @quintesse yes, sorry!

CeylonMigrationBot commented 9 years ago

[@NiematojakTomasz]

Instead, the compiler generates implementations of the inherited formal methods that just call invoke

I understand you want to disallow proxying types which are generic parameters:

shared interface Proxy<T> satisfies T
        given T satisfies Object {
    shared formal Result invoke<Result,Args>(Method<T,Result,Args> method, Args args)
            given Args satisfies Anything[];
}
// Following example would probably require runtime generation of classes (like java proxies).
class LazyInstantationProxy<T>(T() factory) satisfies Proxy<T> 
        given T satisfies Object {
    {T+} lazyInstance = {factory()}; 
    shared actual Result invoke<Result,Args>(Method<T,Result,Args> method, Args args) 
            given Args satisfies Anything[] {
        return method.bind(lazyInstance).apply(args);
    }
}

and only provide new syntax for implementing delegation pattern.

Runtime proxies could be used to provide similar mechanism to RMI or GWT RPC.

CeylonMigrationBot commented 9 years ago

[@quintesse] @NiematojakTomasz true, "delegation" is probably the better technical term here

CeylonMigrationBot commented 9 years ago

[@NiematojakTomasz] @gavinking I just found you have already created very similar issue #4007. In example of that proposal you were implementing proxied interface:

class FooProxy(Foo wrapped) 
        satisfies Foo&Proxy<Foo>
CeylonMigrationBot commented 9 years ago

[@gavinking] Oops, yes, sorry. I need to close one of the two issues.

Sent from my iPhone

On 14 Oct 2014, at 2:55 pm, NiematojakTomasz notifications@github.com wrote:

@gavinking I just found you have already created very similar issue #4007. In example of that proposal you were implementing proxied interface:

class FooProxy(Foo wrapped) satisfies Foo&Proxy — Reply to this email directly or view it on GitHub.

CeylonMigrationBot commented 9 years ago

[@RossTate] I'm not sure what you're actually proposing, and if I go with my best guess then what you've proposed is broken. Either invoke needs the Callable to also accept a this pointer, or a constructor for Proxy needs to take what should be the this pointer that is delegated to. Either way, it seems Proxy needs a type parameter indicating what type it's proxying for and what the type of the this pointer is. This would also indicate the scope of what is proxied, so that if the implementing class also implements other interfaces and it doesn't specify those methods then they aren't mistaken for being handled by the proxy.