2016-05-02 18:11 GMT+02:00 Jochen Theodorou <blackd...@gmx.org>: > On 02.05.2016 16:44, Cédric Champeau wrote: > [...] > >> Of course, it may look a bit superficial but it is super important for >> nice DSLs like in Gradle. >> > > could you give an example of a more complex closure usage? >
Sure, basically you can have that kind of configuration: dependencies { compile '...' } (the method is dependencies(Action<? super DependencyContainer>, and we generate a Closure version at runtime) or: repositories { // Action<? super RepositoryHander maven { Action<? super MavenRepository> url '....' } } > We should be also aware that this change may break code, since it is > semantic change and a local method of the same name will no longer be > called if it exists on the delegate. A functional interface is after all > not something that came really to exist with java8 only, Callable and > Runnable are examples that existed before and work with Closure already. > > Implementation wise to have something like > > void configure(Action<Person> config) { >> config.execute(person) >> } >> > > working we need to set the delegate to person, but we don´t know person > before the method invocation. This means the proxy for the Action > delegating to the closure config represents must also make the delegation > setter call. > > And there is also the problem of what we do if Action contains default > methods - I do not consider our current solution as appropriate anymore. > But of course that is not essential for the idea at hand. > > I have a patch that does the work for functional interfaces already: public static Object coerceToSAM(Closure argument, Method method, Class clazz, boolean isInterface) { if (argument!=null && clazz.isAssignableFrom(argument.getClass())) { return argument; } if (isInterface) { if (Traits.isTrait(clazz)) { Map<String,Closure> impl = Collections.singletonMap( method.getName(), argument ); return ProxyGenerator.INSTANCE.instantiateAggregate(impl,Collections.singletonList(clazz)); } return Proxy.newProxyInstance( clazz.getClassLoader(), new Class[]{clazz}, new SAMClosure(argument)); } else { Map<String, Object> m = new HashMap<String,Object>(); m.put(method.getName(), argument); return ProxyGenerator.INSTANCE. instantiateAggregateFromBaseClass(m, clazz); } } private static class SAMClosure extends ConvertedClosure { public SAMClosure(final Closure closure) { super(closure); } @Override public Object invokeCustom(final Object proxy, final Method method, final Object[] args) throws Throwable { if (args!=null && args.length>0) { Closure delegate = (Closure) getDelegate(); delegate.setResolveStrategy(Closure.DELEGATE_FIRST); delegate.setDelegate(args[0]); } return super.invokeCustom(proxy, method, args); } } Doing the same for abstract classes should be straightforward. For static compilation, it's going to be more complicated and probably requires transparently invoking a configurer (like Gradle does). > > bye Jochen >