ceylon / ceylon-spec

DEPRECATED
Apache License 2.0
108 stars 34 forks source link

catchall methods #1113

Open gavinking opened 10 years ago

gavinking commented 10 years ago

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.

gavinking commented 10 years ago

Related to #1112.

quintesse commented 10 years ago

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

gavinking commented 10 years ago

@quintesse yes, sorry!

NiematojakTomasz commented 10 years ago

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.

quintesse commented 10 years ago

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

NiematojakTomasz commented 10 years ago

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

class FooProxy(Foo wrapped) 
        satisfies Foo&Proxy<Foo>
gavinking commented 10 years ago

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 #901. 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.

RossTate commented 10 years ago

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.