You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@groovy.apache.org by Christopher Smith <ch...@gmail.com> on 2021/04/29 00:47:05 UTC

() call-type syntax for functional interfaces?

It would be convenient to be able to use the convention of "use
parentheses on a function-like object" with functional interfaces; for
example, if a variable is declared as type Function, to have
`myVar(3)` run `myVar.apply(3)`. Is there any chance this would be
practical, or would its semantics be limited sufficiently by the
default-dynamic nature of Groovy to not add value?

(I have in mind Groovy's tendency to do runtime switcheroos with
anything that implements Map as a counterexample, but that may be
beside the point.)

Re: () call-type syntax for functional interfaces?

Posted by Christopher Smith <ch...@gmail.com>.
You're right, but we're down to enumerating special cases where this can be
made to work without using a declared type, and that seems fragile. It's
how you get massive pitfalls like the "runtime object implements Map"
situation we have now.

On Thu, Apr 29, 2021, 14:03 Remi Forax <fo...@univ-mlv.fr> wrote:

>
>
> ------------------------------
>
> *De: *"Christopher Smith" <ch...@gmail.com>
> *À: *"dev" <de...@groovy.apache.org>
> *Envoyé: *Jeudi 29 Avril 2021 19:38:27
> *Objet: *Re: () call-type syntax for functional interfaces?
>
> Also an object implementing multiple functional interfaces. In dynamic
> mode, you wouldn't know which method to invoke.
>
>
> if that object is a lambda proxy, i.e. an object created by a Java lambda,
> the only way to implement several functional interfaces is to have default
> methods,
> those methods are defined in their respective interfaces, not in the
> lambda class.
>
> You can have several methods in the lamba proxy class either because you
> have method of java.lang.Object (equals/hashCode/toString) or because of
> the way generics are implemented.
> Because of erasure, you can have a bridge method alongside the method that
> calls the lambda body,
> but in that case, selecting the method with the most specific return type
> and the less specific parameter types is enough.
>
> Rémi
>
>
> On Thu, Apr 29, 2021, 12:34 Jochen Theodorou <bl...@gmx.org> wrote:
>
>> On 29.04.21 15:32, Christopher Smith wrote:
>> > Sure, this is theoretically possible (though many functional interfaces
>> > aren't annotated), but the convenience I'm asking about would have to be
>> > compile-time, because it would depend on the declared type (which is
>> > part of why I suspect it might not even make semantic sense in the
>> > underlying dynamic model).
>>
>> why does it have to be compile time only? I don't quite get that. The
>> problem you have to face is of course an Object, which realizes a
>> functional interface, but also has a call method (not part of the
>> interface)
>>
>> bye Jochen
>>
>
>

Re: () call-type syntax for functional interfaces?

Posted by Remi Forax <fo...@univ-mlv.fr>.
> De: "Christopher Smith" <ch...@gmail.com>
> À: "dev" <de...@groovy.apache.org>
> Envoyé: Jeudi 29 Avril 2021 19:38:27
> Objet: Re: () call-type syntax for functional interfaces?

> Also an object implementing multiple functional interfaces. In dynamic mode, you
> wouldn't know which method to invoke.

if that object is a lambda proxy, i.e. an object created by a Java lambda, the only way to implement several functional interfaces is to have default methods, 
those methods are defined in their respective interfaces, not in the lambda class. 

You can have several methods in the lamba proxy class either because you have method of java.lang.Object (equals/hashCode/toString) or because of the way generics are implemented. 
Because of erasure, you can have a bridge method alongside the method that calls the lambda body, 
but in that case, selecting the method with the most specific return type and the less specific parameter types is enough. 

Rémi 

> On Thu, Apr 29, 2021, 12:34 Jochen Theodorou < [ mailto:blackdrag@gmx.org |
> blackdrag@gmx.org ] > wrote:

>> On 29.04.21 15:32, Christopher Smith wrote:
>> > Sure, this is theoretically possible (though many functional interfaces
>> > aren't annotated), but the convenience I'm asking about would have to be
>> > compile-time, because it would depend on the declared type (which is
>> > part of why I suspect it might not even make semantic sense in the
>> > underlying dynamic model).

>> why does it have to be compile time only? I don't quite get that. The
>> problem you have to face is of course an Object, which realizes a
>> functional interface, but also has a call method (not part of the interface)

>> bye Jochen

Re: () call-type syntax for functional interfaces?

Posted by Christopher Smith <ch...@gmail.com>.
Also an object implementing multiple functional interfaces. In dynamic
mode, you wouldn't know which method to invoke.

On Thu, Apr 29, 2021, 12:34 Jochen Theodorou <bl...@gmx.org> wrote:

> On 29.04.21 15:32, Christopher Smith wrote:
> > Sure, this is theoretically possible (though many functional interfaces
> > aren't annotated), but the convenience I'm asking about would have to be
> > compile-time, because it would depend on the declared type (which is
> > part of why I suspect it might not even make semantic sense in the
> > underlying dynamic model).
>
> why does it have to be compile time only? I don't quite get that. The
> problem you have to face is of course an Object, which realizes a
> functional interface, but also has a call method (not part of the
> interface)
>
> bye Jochen
>

Re: () call-type syntax for functional interfaces?

Posted by Jochen Theodorou <bl...@gmx.org>.
On 29.04.21 15:32, Christopher Smith wrote:
> Sure, this is theoretically possible (though many functional interfaces
> aren't annotated), but the convenience I'm asking about would have to be
> compile-time, because it would depend on the declared type (which is
> part of why I suspect it might not even make semantic sense in the
> underlying dynamic model).

why does it have to be compile time only? I don't quite get that. The
problem you have to face is of course an Object, which realizes a
functional interface, but also has a call method (not part of the interface)

bye Jochen

RE: () call-type syntax for functional interfaces?

Posted by "Milles, Eric (TR Technology)" <er...@thomsonreuters.com>.
Yes, this type of thing is possible.  I think it would be limited to STC or SC since you would need to know the type of the receiver.  org.codehaus.groovy.classgen.VariableScopeVisitor#visitMethodCallExpression is the bit of code that sees "var(...)" and replaces it with "var.call(...)".  Maybe you could add a call method to the metaclass of the functional type that delegates to the SAM as an experiment.

You should be able to create an AST transformation that does this by looking for the INFERRED_TYPE node metadata of a MethodCallExpression's objectExpression.

https://issues.apache.org/jira/browse/GROOVY-5881 is a good ticket to look at and see how even the "call" substitution is limited in reality.


From: Christopher Smith <ch...@gmail.com>
Sent: Thursday, April 29, 2021 8:33 AM
To: dev@groovy.apache.org
Subject: Re: () call-type syntax for functional interfaces?

Sure, this is theoretically possible (though many functional interfaces aren't annotated), but the convenience I'm asking about would have to be compile-time, because it would depend on the declared type (which is part of why I suspect it might not even make semantic sense in the underlying dynamic model).

On Thu, Apr 29, 2021, 08:24 Rachel Greenham <ra...@merus.eu>> wrote:
Sorry if I might be teaching people to suck eggs, but you can discover the functional method of a functional interface through reflection. It’s a bit of a lookup but presumably in groovy the results of such lookups do get cached...

I use (reassembled from something that’s a bit more broken up than this):

Optional.of(Function.class)
    .filter(Class::isInterface)
    .filter(c -> c.isAnnotationPresent(FunctionalInterface.class))
    .stream()
    .flatMap(c -> Arrays.stream(c.getMethods()))
    .filter(Predicate.not(Method::isDefault)
        .and(m -> !Modifier.isStatic(m.getModifiers())))
    .findFirst()
    .map(Method::getName);

<< Optional[public abstract java.lang.Object java.util.function.Function.apply(java.lang.Object)]

Modify to allow any interface as long as it has only one abstract method by, instead of the .findFirst(), go to a list or array and only use it if it’s exactly one entry long.

--
Rachel Greenham
rachel@merus.eu<ma...@merus.eu>



> On 29 Apr 2021, at 12:46, Christopher Smith <ch...@gmail.com>> wrote:
>
> That option is not available when using, for example, java.util.function.Function.
>
> On Thu, Apr 29, 2021, 03:34 Angelo Schneider <an...@oomentor.de>> wrote:
> Is that not already covered by the call() - method?
> I mean the option to declare a method called `Object call(args)´
> Best Regards
> Angelo
>
> ---
> Angelo Schneider
> angelo.schneider@oomentor.de<ma...@oomentor.de>
> +49 172 9873893
>
> > Am 29.04.2021 um 02:47 schrieb Christopher Smith <ch...@gmail.com>>:
> >
> > It would be convenient to be able to use the convention of "use
> > parentheses on a function-like object" with functional interfaces; for
> > example, if a variable is declared as type Function, to have
> > `myVar(3)` run `myVar.apply(3)`. Is there any chance this would be
> > practical, or would its semantics be limited sufficiently by the
> > default-dynamic nature of Groovy to not add value?
> >
> > (I have in mind Groovy's tendency to do runtime switcheroos with
> > anything that implements Map as a counterexample, but that may be
> > beside the point.)
>

Re: () call-type syntax for functional interfaces?

Posted by Christopher Smith <ch...@gmail.com>.
Sure, this is theoretically possible (though many functional interfaces
aren't annotated), but the convenience I'm asking about would have to be
compile-time, because it would depend on the declared type (which is part
of why I suspect it might not even make semantic sense in the underlying
dynamic model).

On Thu, Apr 29, 2021, 08:24 Rachel Greenham <ra...@merus.eu> wrote:

> Sorry if I might be teaching people to suck eggs, but you can discover the
> functional method of a functional interface through reflection. It’s a bit
> of a lookup but presumably in groovy the results of such lookups do get
> cached...
>
> I use (reassembled from something that’s a bit more broken up than this):
>
> Optional.of(Function.class)
>     .filter(Class::isInterface)
>     .filter(c -> c.isAnnotationPresent(FunctionalInterface.class))
>     .stream()
>     .flatMap(c -> Arrays.stream(c.getMethods()))
>     .filter(Predicate.not(Method::isDefault)
>         .and(m -> !Modifier.isStatic(m.getModifiers())))
>     .findFirst()
>     .map(Method::getName);
>
> << Optional[public abstract java.lang.Object
> java.util.function.Function.apply(java.lang.Object)]
>
> Modify to allow any interface as long as it has only one abstract method
> by, instead of the .findFirst(), go to a list or array and only use it if
> it’s exactly one entry long.
>
> --
> Rachel Greenham
> rachel@merus.eu
>
>
>
> > On 29 Apr 2021, at 12:46, Christopher Smith <ch...@gmail.com> wrote:
> >
> > That option is not available when using, for example,
> java.util.function.Function.
> >
> > On Thu, Apr 29, 2021, 03:34 Angelo Schneider <
> angelo.schneider@oomentor.de> wrote:
> > Is that not already covered by the call() - method?
> > I mean the option to declare a method called `Object call(args)´
> > Best Regards
> > Angelo
> >
> > ---
> > Angelo Schneider
> > angelo.schneider@oomentor.de
> > +49 172 9873893
> >
> > > Am 29.04.2021 um 02:47 schrieb Christopher Smith <
> chrylis+groovy@gmail.com>:
> > >
> > > It would be convenient to be able to use the convention of "use
> > > parentheses on a function-like object" with functional interfaces; for
> > > example, if a variable is declared as type Function, to have
> > > `myVar(3)` run `myVar.apply(3)`. Is there any chance this would be
> > > practical, or would its semantics be limited sufficiently by the
> > > default-dynamic nature of Groovy to not add value?
> > >
> > > (I have in mind Groovy's tendency to do runtime switcheroos with
> > > anything that implements Map as a counterexample, but that may be
> > > beside the point.)
> >
>
>

Re: () call-type syntax for functional interfaces?

Posted by Rachel Greenham <ra...@merus.eu>.
Sorry if I might be teaching people to suck eggs, but you can discover the functional method of a functional interface through reflection. It’s a bit of a lookup but presumably in groovy the results of such lookups do get cached...

I use (reassembled from something that’s a bit more broken up than this):

Optional.of(Function.class)
    .filter(Class::isInterface)
    .filter(c -> c.isAnnotationPresent(FunctionalInterface.class))
    .stream()
    .flatMap(c -> Arrays.stream(c.getMethods()))
    .filter(Predicate.not(Method::isDefault)
        .and(m -> !Modifier.isStatic(m.getModifiers())))
    .findFirst()
    .map(Method::getName);

<< Optional[public abstract java.lang.Object java.util.function.Function.apply(java.lang.Object)]

Modify to allow any interface as long as it has only one abstract method by, instead of the .findFirst(), go to a list or array and only use it if it’s exactly one entry long.

-- 
Rachel Greenham
rachel@merus.eu



> On 29 Apr 2021, at 12:46, Christopher Smith <ch...@gmail.com> wrote:
> 
> That option is not available when using, for example, java.util.function.Function.
> 
> On Thu, Apr 29, 2021, 03:34 Angelo Schneider <an...@oomentor.de> wrote:
> Is that not already covered by the call() - method?
> I mean the option to declare a method called `Object call(args)´
> Best Regards
> Angelo
> 
> ---
> Angelo Schneider
> angelo.schneider@oomentor.de
> +49 172 9873893
> 
> > Am 29.04.2021 um 02:47 schrieb Christopher Smith <ch...@gmail.com>:
> > 
> > It would be convenient to be able to use the convention of "use
> > parentheses on a function-like object" with functional interfaces; for
> > example, if a variable is declared as type Function, to have
> > `myVar(3)` run `myVar.apply(3)`. Is there any chance this would be
> > practical, or would its semantics be limited sufficiently by the
> > default-dynamic nature of Groovy to not add value?
> > 
> > (I have in mind Groovy's tendency to do runtime switcheroos with
> > anything that implements Map as a counterexample, but that may be
> > beside the point.)
> 


Re: () call-type syntax for functional interfaces?

Posted by Christopher Smith <ch...@gmail.com>.
That option is not available when using, for example,
java.util.function.Function.

On Thu, Apr 29, 2021, 03:34 Angelo Schneider <an...@oomentor.de>
wrote:

> Is that not already covered by the call() - method?
> I mean the option to declare a method called `Object call(args)´
> Best Regards
> Angelo
>
> ---
> Angelo Schneider
> angelo.schneider@oomentor.de
> +49 172 9873893
>
> > Am 29.04.2021 um 02:47 schrieb Christopher Smith <
> chrylis+groovy@gmail.com>:
> >
> > It would be convenient to be able to use the convention of "use
> > parentheses on a function-like object" with functional interfaces; for
> > example, if a variable is declared as type Function, to have
> > `myVar(3)` run `myVar.apply(3)`. Is there any chance this would be
> > practical, or would its semantics be limited sufficiently by the
> > default-dynamic nature of Groovy to not add value?
> >
> > (I have in mind Groovy's tendency to do runtime switcheroos with
> > anything that implements Map as a counterexample, but that may be
> > beside the point.)
>
>

Re: () call-type syntax for functional interfaces?

Posted by Angelo Schneider <an...@oomentor.de>.
Is that not already covered by the call() - method?
I mean the option to declare a method called `Object call(args)´
Best Regards
Angelo

---
Angelo Schneider
angelo.schneider@oomentor.de
+49 172 9873893

> Am 29.04.2021 um 02:47 schrieb Christopher Smith <ch...@gmail.com>:
> 
> It would be convenient to be able to use the convention of "use
> parentheses on a function-like object" with functional interfaces; for
> example, if a variable is declared as type Function, to have
> `myVar(3)` run `myVar.apply(3)`. Is there any chance this would be
> practical, or would its semantics be limited sufficiently by the
> default-dynamic nature of Groovy to not add value?
> 
> (I have in mind Groovy's tendency to do runtime switcheroos with
> anything that implements Map as a counterexample, but that may be
> beside the point.)