* using lambda to implement one method interface @ 2017-09-17 15:32 Sonny To 2017-09-17 15:38 ` Sonny To 0 siblings, 1 reply; 13+ messages in thread From: Sonny To @ 2017-09-17 15:32 UTC (permalink / raw) To: Kawa mailing list follwing docs at https://www.gnu.org/software/kawa/Anonymous-classes.html (let ((handler (android.os.Handler (android.os.Looper:getMainLooper))) (runnable (lambda () (android.util.Log:i "scm" "run me")))) (handler:post runnable) ) that doesn't seem to work. Do I need to give type hints to be able to do this? I'm getting this error: #|.....44|# #|.....45|# #|.....46|# #|.....47|# /dev/stdin:46:17: warning - type function is incompatible with required type java.lang.Runnable java.lang.ClassCastException: don't know how to coerce gnu.expr.LambdaExp$Closure to java.lang.Runnable at gnu.bytecode.ObjectType.coerceFromObject(ObjectType.java:180) at gnu.kawa.functions.Convert.apply2(Convert.java:38) at gnu.mapping.Procedure2.applyToObject(Procedure2.java:62) at java.lang.reflect.Method.invoke(Native Method) at gnu.mapping.CallContext$ReflectMethodHandle.invokeExact(CallContext.java:726) at gnu.mapping.Procedure.applyToConsumerDefault(Procedure.java:75) at java.lang.reflect.Method.invoke(Native Method) at gnu.mapping.CallContext$ReflectMethodHandle.invokeExact(CallContext.java:726) at gnu.mapping.CallContext.runUntilDone(CallContext.java:586) at gnu.mapping.CallContext.getFromContext(CallContext.java:616) at gnu.expr.Expression.eval(Expression.java:52) at gnu.expr.ApplyExp.apply(ApplyExp.java:161) at gnu.expr.LetExp.apply(LetExp.java:72) at gnu.expr.ModuleExp.evalModule2(ModuleExp.java:281) at gnu.expr.ModuleExp.evalModule(ModuleExp.java:211) at kawa.Shell.run(Shell.java:283) at kawa.Shell.run(Shell.java:196) at kawa.Shell.run(Shell.java:183) at kawa.TelnetRepl.apply0(TelnetRepl.java:25) at gnu.mapping.RunnableClosure.run(RunnableClosure.java:75) at java.lang.Thread.run(Thread.java:764) ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: using lambda to implement one method interface 2017-09-17 15:32 using lambda to implement one method interface Sonny To @ 2017-09-17 15:38 ` Sonny To 2017-09-17 15:59 ` Per Bothner 0 siblings, 1 reply; 13+ messages in thread From: Sonny To @ 2017-09-17 15:38 UTC (permalink / raw) To: Kawa mailing list this works (let ((handler (android.os.Handler (android.os.Looper:getMainLooper))) ) (handler:post (lambda () (android.util.Log:i "scm" "run me"))) ) this is non-intuitive. why doesn't it work if i bind the lambda to a symbol? seems like a bug to me On Sun, Sep 17, 2017 at 8:32 AM, Sonny To <son.c.to@gmail.com> wrote: > follwing docs at https://www.gnu.org/software/kawa/Anonymous-classes.html > > (let ((handler (android.os.Handler (android.os.Looper:getMainLooper))) > (runnable (lambda () > (android.util.Log:i "scm" "run me")))) > (handler:post runnable) > ) > > that doesn't seem to work. Do I need to give type hints to be able to do this? > > I'm getting this error: > > #|.....44|# #|.....45|# #|.....46|# #|.....47|# /dev/stdin:46:17: > warning - type function is incompatible with required type > java.lang.Runnable > java.lang.ClassCastException: don't know how to coerce > gnu.expr.LambdaExp$Closure to java.lang.Runnable > at gnu.bytecode.ObjectType.coerceFromObject(ObjectType.java:180) > at gnu.kawa.functions.Convert.apply2(Convert.java:38) > at gnu.mapping.Procedure2.applyToObject(Procedure2.java:62) > at java.lang.reflect.Method.invoke(Native Method) > at gnu.mapping.CallContext$ReflectMethodHandle.invokeExact(CallContext.java:726) > at gnu.mapping.Procedure.applyToConsumerDefault(Procedure.java:75) > at java.lang.reflect.Method.invoke(Native Method) > at gnu.mapping.CallContext$ReflectMethodHandle.invokeExact(CallContext.java:726) > at gnu.mapping.CallContext.runUntilDone(CallContext.java:586) > at gnu.mapping.CallContext.getFromContext(CallContext.java:616) > at gnu.expr.Expression.eval(Expression.java:52) > at gnu.expr.ApplyExp.apply(ApplyExp.java:161) > at gnu.expr.LetExp.apply(LetExp.java:72) > at gnu.expr.ModuleExp.evalModule2(ModuleExp.java:281) > at gnu.expr.ModuleExp.evalModule(ModuleExp.java:211) > at kawa.Shell.run(Shell.java:283) > at kawa.Shell.run(Shell.java:196) > at kawa.Shell.run(Shell.java:183) > at kawa.TelnetRepl.apply0(TelnetRepl.java:25) > at gnu.mapping.RunnableClosure.run(RunnableClosure.java:75) > at java.lang.Thread.run(Thread.java:764) ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: using lambda to implement one method interface 2017-09-17 15:38 ` Sonny To @ 2017-09-17 15:59 ` Per Bothner 2017-09-17 16:04 ` Sonny To 0 siblings, 1 reply; 13+ messages in thread From: Per Bothner @ 2017-09-17 15:59 UTC (permalink / raw) To: Sonny To, Kawa mailing list On 09/17/2017 08:38 AM, Sonny To wrote: > this works > > (let ((handler (android.os.Handler (android.os.Looper:getMainLooper))) > ) > (handler:post (lambda () > (android.util.Log:i "scm" "run me"))) > ) > > this is non-intuitive. why doesn't it work if i bind the lambda to a > symbol? seems like a bug to me Perhaps a documentation bug: It may not be clear that when the manual say "required type" in: This is possible when the required type is an interface or abstract class with a Single (exactly one) Abstract Methods. we mean the type required by the *compile-time context* of the expression. This is a deliberate design limitation, not a bug. This way the anonymous class can be created a compile-time, not run-time. Doing it at run-time would be more difficult and more expensive. Kawa has always put a high priority on performance. Perhaps a future Kawa extension will allow "SAM-conversion" at run-time, but it is not currently in the plans. -- --Per Bothner per@bothner.com http://per.bothner.com/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: using lambda to implement one method interface 2017-09-17 15:59 ` Per Bothner @ 2017-09-17 16:04 ` Sonny To 2017-09-17 16:50 ` Per Bothner 0 siblings, 1 reply; 13+ messages in thread From: Sonny To @ 2017-09-17 16:04 UTC (permalink / raw) To: Per Bothner; +Cc: Kawa mailing list Thanks for the explanation. However, I'm still not clear about compile-time. I'm evaluating this in the TelnetRepl. its interpreted no? On Sun, Sep 17, 2017 at 8:59 AM, Per Bothner <per@bothner.com> wrote: > On 09/17/2017 08:38 AM, Sonny To wrote: >> >> this works >> >> (let ((handler (android.os.Handler (android.os.Looper:getMainLooper))) >> ) >> (handler:post (lambda () >> (android.util.Log:i "scm" "run me"))) >> ) >> >> this is non-intuitive. why doesn't it work if i bind the lambda to a >> symbol? seems like a bug to me > > > Perhaps a documentation bug: It may not be clear that when the manual > say "required type" in: > > This is possible when the required type is an interface or > abstract class with a Single (exactly one) Abstract Methods. > > we mean the type required by the *compile-time context* of the expression. > > This is a deliberate design limitation, not a bug. This way the anonymous > class can be created a compile-time, not run-time. Doing it at run-time > would be more difficult and more expensive. Kawa has always put a high > priority on performance. > > Perhaps a future Kawa extension will allow "SAM-conversion" at run-time, > but it is not currently in the plans. > -- > --Per Bothner > per@bothner.com http://per.bothner.com/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: using lambda to implement one method interface 2017-09-17 16:04 ` Sonny To @ 2017-09-17 16:50 ` Per Bothner 2017-09-17 18:54 ` Sonny To 0 siblings, 1 reply; 13+ messages in thread From: Per Bothner @ 2017-09-17 16:50 UTC (permalink / raw) To: Sonny To; +Cc: Kawa mailing list On 09/17/2017 09:03 AM, Sonny To wrote: > Thanks for the explanation. However, I'm still not clear about > compile-time. I'm evaluating this in the TelnetRepl. its interpreted > no? Yes and no. "Compile-time" is when the Scheme expression is parsed, analyzed, and (normally) translated to JVM bytecode. On most platforms, even when you type an expression into a REPL, it gets translated to bytecode and then loaded on-the-fly using java.lang.ClassLoader.defineClass. Because Android doesn't have ClassLoader.defineClass (because it uses dex), we don't translate REPL input to bytecode. Instead, there is an interpreter that evaluates to tree (Expression) form of the expression. Determining when "SAM-conversion" (converting lambda to anonymous class) is allowed is done at compile-time. On most platforms, creating the anonymous class is also done at time-time. On Android, the last step is deferred to run-time, using a ProcedurallProxy class, but that only supports converting a lambda to an interface, not a class. It probably wouldn't be difficult to use ProcedurallProxy at run-time to convert a procedure value to a class instance. However, it would require changes to error handling: Instead of compiling a simple cast, we have to compile to a more complex (and slower) procedure. There is also a question of what warning messages, if any to emit. Perhaps worth revisiting if/when we implement "Optional strict typing along with an explicit dynamic type" (https://www.gnu.org/software/kawa/Ideas-and-tasks.html#Optional-strict-typing-along-with-an-explicit-dynamic-type). (The 'dynamic' type is already partially supported.) -- --Per Bothner per@bothner.com http://per.bothner.com/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: using lambda to implement one method interface 2017-09-17 16:50 ` Per Bothner @ 2017-09-17 18:54 ` Sonny To 2017-09-17 20:02 ` Per Bothner 0 siblings, 1 reply; 13+ messages in thread From: Sonny To @ 2017-09-17 18:54 UTC (permalink / raw) To: Per Bothner; +Cc: Kawa mailing list this is a big problem for my use case... i wouldn't be able to do something like this on android at runtime (object (java.lang.Runnable) ((run (a ::void))::void (+ 1 1) )) On Sun, Sep 17, 2017 at 9:50 AM, Per Bothner <per@bothner.com> wrote: > On 09/17/2017 09:03 AM, Sonny To wrote: >> >> Thanks for the explanation. However, I'm still not clear about >> compile-time. I'm evaluating this in the TelnetRepl. its interpreted >> no? > > > Yes and no. "Compile-time" is when the Scheme expression is parsed, > analyzed, and (normally) translated to JVM bytecode. On most platforms, > even when you type an expression into a REPL, it gets translated to bytecode > and then loaded on-the-fly using java.lang.ClassLoader.defineClass. > > Because Android doesn't have ClassLoader.defineClass (because it uses dex), > we don't translate REPL input to bytecode. Instead, there is an > interpreter that evaluates to tree (Expression) form of the expression. > > Determining when "SAM-conversion" (converting lambda to anonymous class) > is allowed is done at compile-time. On most platforms, creating the > anonymous class is also done at time-time. On Android, the last step is > deferred to run-time, using a ProcedurallProxy class, but that only supports > converting a lambda to an interface, not a class. > > It probably wouldn't be difficult to use ProcedurallProxy at run-time to > convert > a procedure value to a class instance. However, it would require changes to > error handling: Instead of compiling a simple cast, we have to compile to a > more > complex (and slower) procedure. There is also a question of what warning > messages, > if any to emit. Perhaps worth revisiting if/when we implement > "Optional strict typing along with an explicit dynamic type" > (https://www.gnu.org/software/kawa/Ideas-and-tasks.html#Optional-strict-typing-along-with-an-explicit-dynamic-type). > > (The 'dynamic' type is already partially supported.) > > -- > --Per Bothner > per@bothner.com http://per.bothner.com/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: using lambda to implement one method interface 2017-09-17 18:54 ` Sonny To @ 2017-09-17 20:02 ` Per Bothner 2017-09-18 6:35 ` Sonny To 0 siblings, 1 reply; 13+ messages in thread From: Per Bothner @ 2017-09-17 20:02 UTC (permalink / raw) To: Sonny To; +Cc: Kawa mailing list On 09/17/2017 11:54 AM, Sonny To wrote: > this is a big problem for my use case... > > i wouldn't be able to do something like this on android at runtime > > (object (java.lang.Runnable) > ((run (a ::void))::void > (+ 1 1) > )) You can probably work around it with: (->java.lang.Runnable (lambda ()::void (set! i (+ i 1)))) BTW - I assume (a ::void) is just a typo. Kawa should probably complain about it. -- --Per Bothner per@bothner.com http://per.bothner.com/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: using lambda to implement one method interface 2017-09-17 20:02 ` Per Bothner @ 2017-09-18 6:35 ` Sonny To 2017-09-18 8:17 ` Sonny To 2017-09-18 11:22 ` Sudarshan S Chawathe 0 siblings, 2 replies; 13+ messages in thread From: Sonny To @ 2017-09-18 6:35 UTC (permalink / raw) To: Per Bothner; +Cc: Kawa mailing list [-- Attachment #1: Type: text/plain, Size: 726 bytes --] yes that was an error. copy and paste of testing code. how would I implement an interface with multiple methods? On Sun, Sep 17, 2017 at 11:02 PM Per Bothner <per@bothner.com> wrote: > On 09/17/2017 11:54 AM, Sonny To wrote: > > this is a big problem for my use case... > > > > i wouldn't be able to do something like this on android at runtime > > > > (object (java.lang.Runnable) > > ((run (a ::void))::void > > (+ 1 1) > > )) > > You can probably work around it with: > > (->java.lang.Runnable > (lambda ()::void (set! i (+ i 1)))) > > BTW - I assume (a ::void) is just a typo. Kawa should probably complain > about it. > -- > --Per Bothner > per@bothner.com http://per.bothner.com/ > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: using lambda to implement one method interface 2017-09-18 6:35 ` Sonny To @ 2017-09-18 8:17 ` Sonny To 2017-09-18 13:59 ` Per Bothner 2017-09-18 11:22 ` Sudarshan S Chawathe 1 sibling, 1 reply; 13+ messages in thread From: Sonny To @ 2017-09-18 8:17 UTC (permalink / raw) To: Per Bothner; +Cc: Kawa mailing list It seems implementing single method interface using lambda only works with methods and not in constructors? for example, this fails #|kawa:137|# (java.lang.Thread (lambda () (+ 1 1))) #|.....138|# /dev/stdin:137:1: warning - no possibly applicable method '<init>/valueOf' in java.lang.Thread gnu.mapping.WrongArguments at gnu.mapping.MethodProc.matchFailAsException(MethodProc.java:136) at gnu.kawa.reflect.Invoke.applyToObject(Invoke.java:264) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at gnu.mapping.CallContext$ReflectMethodHandle.invokeExact(CallContext.java:726) at gnu.mapping.Procedure.applyToConsumerDefault(Procedure.java:75) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at gnu.mapping.CallContext$ReflectMethodHandle.invokeExact(CallContext.java:726) at gnu.mapping.CallContext.runUntilDone(CallContext.java:586) at gnu.expr.ModuleExp.evalModule2(ModuleExp.java:342) at gnu.expr.ModuleExp.evalModule(ModuleExp.java:211) at kawa.Shell.run(Shell.java:283) at kawa.Shell.run(Shell.java:196) at kawa.Shell.run(Shell.java:183) at kawa.repl.processArgs(repl.java:714) at kawa.repl.main(repl.java:820) On Mon, Sep 18, 2017 at 9:35 AM, Sonny To <son.c.to@gmail.com> wrote: > yes that was an error. copy and paste of testing code. how would I > implement an interface with multiple methods? > > > On Sun, Sep 17, 2017 at 11:02 PM Per Bothner <per@bothner.com> wrote: >> >> On 09/17/2017 11:54 AM, Sonny To wrote: >> > this is a big problem for my use case... >> > >> > i wouldn't be able to do something like this on android at runtime >> > >> > (object (java.lang.Runnable) >> > ((run (a ::void))::void >> > (+ 1 1) >> > )) >> >> You can probably work around it with: >> >> (->java.lang.Runnable >> (lambda ()::void (set! i (+ i 1)))) >> >> BTW - I assume (a ::void) is just a typo. Kawa should probably complain >> about it. >> -- >> --Per Bothner >> per@bothner.com http://per.bothner.com/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: using lambda to implement one method interface 2017-09-18 8:17 ` Sonny To @ 2017-09-18 13:59 ` Per Bothner 0 siblings, 0 replies; 13+ messages in thread From: Per Bothner @ 2017-09-18 13:59 UTC (permalink / raw) To: Sonny To; +Cc: Kawa mailing list On 09/18/2017 01:16 AM, Sonny To wrote: > It seems implementing single method interface using lambda only works > with methods and not in constructors? > > for example, this fails > > #|kawa:137|# (java.lang.Thread (lambda () > (+ 1 1))) > #|.....138|# /dev/stdin:137:1: warning - no possibly applicable method > '<init>/valueOf' in java.lang.Thread > gnu.mapping.WrongArguments Yes and no. Method selection uses different code than the code that checks for type compatibility. It's mostly the same tests, but the former doesn't handle lambda-to-interface conversion. It would be non-trivial to change that. However, this works: (java.lang.Thread (->java.lang.Runnable (lambda () (newline)))) -- --Per Bothner per@bothner.com http://per.bothner.com/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: using lambda to implement one method interface 2017-09-18 6:35 ` Sonny To 2017-09-18 8:17 ` Sonny To @ 2017-09-18 11:22 ` Sudarshan S Chawathe 2017-09-18 14:24 ` Per Bothner 1 sibling, 1 reply; 13+ messages in thread From: Sudarshan S Chawathe @ 2017-09-18 11:22 UTC (permalink / raw) To: Sonny To; +Cc: Kawa mailing list > how would I implement an interface with multiple methods? I have found that simply defining the methods required by an interface (with the proper names and type signatures) works, in the sense that the resulting objects can be used anywhere that requires objects implementing the interface. Regards, -chaw ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: using lambda to implement one method interface 2017-09-18 11:22 ` Sudarshan S Chawathe @ 2017-09-18 14:24 ` Per Bothner 2017-09-18 14:31 ` Sudarshan S Chawathe 0 siblings, 1 reply; 13+ messages in thread From: Per Bothner @ 2017-09-18 14:24 UTC (permalink / raw) To: Sudarshan S Chawathe, Sonny To; +Cc: Kawa mailing list On 09/18/2017 04:22 AM, Sudarshan S Chawathe wrote: >> how would I implement an interface with multiple methods? > > I have found that simply defining the methods required by an interface > (with the proper names and type signatures) works, in the sense that the > resulting objects can be used anywhere that requires objects > implementing the interface. Not sure I understand what you mean by that. The problem is defining an instance of an interface: (1) with multiple methods; (2) on-the-fly, in a REPL; (3) on Android, which doesn't (didn't?) have ClassLoader.defineClass. It should be possible to generalize gnu.kawa.reflect.ProceduralProxy to handle multiple methods and corresponding implementing procedures. The tricky is specifying which method is implemented by which procedure. Perhaps problem (3) above is no longer a problem, at least on Android 8. https://developer.android.com/reference/java/lang/ClassLoader.html says that the byte array to defineClass "should have the format of a valid class file as defined by The Java⢠Virtual Machine Specification." So maybe we need to update the compilerAvailable test in ModuleExp.java. If we now can generate classes on-the-fly then that removes a major limitation of Kawa on Android. (At least on newer Android versions.) -- --Per Bothner per@bothner.com http://per.bothner.com/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: using lambda to implement one method interface 2017-09-18 14:24 ` Per Bothner @ 2017-09-18 14:31 ` Sudarshan S Chawathe 0 siblings, 0 replies; 13+ messages in thread From: Sudarshan S Chawathe @ 2017-09-18 14:31 UTC (permalink / raw) To: Per Bothner; +Cc: Sonny To, Kawa mailing list Mea culpa. I temporarily lost sight of the fact that the discussion was in the context of a REPL on Android. -chaw > Subject: Re: using lambda to implement one method interface > Cc: Kawa mailing list <kawa@sourceware.org> > From: Per Bothner <per@bothner.com> > Date: Mon, 18 Sep 2017 07:22:56 -0700 > > On 09/18/2017 04:22 AM, Sudarshan S Chawathe wrote: > >> how would I implement an interface with multiple methods? > > > > I have found that simply defining the methods required by an interface > > (with the proper names and type signatures) works, in the sense that the > > resulting objects can be used anywhere that requires objects > > implementing the interface. > > Not sure I understand what you mean by that. > > The problem is defining an instance of an interface: > (1) with multiple methods; > (2) on-the-fly, in a REPL; > (3) on Android, which doesn't (didn't?) have ClassLoader.defineClass. > > It should be possible to generalize gnu.kawa.reflect.ProceduralProxy > to handle multiple methods and corresponding implementing procedures. > The tricky is specifying which method is implemented by which procedure. > > Perhaps problem (3) above is no longer a problem, at least on Android 8. > https://developer.android.com/reference/java/lang/ClassLoader.html > says that the byte array to defineClass "should have the format of a valid > class file as defined by The Java™ Virtual Machine Specification." > > So maybe we need to update the compilerAvailable test in ModuleExp.java. > If we now can generate classes on-the-fly then that removes a major > limitation of Kawa on Android. (At least on newer Android versions.) > -- > --Per Bothner > per@bothner.com http://per.bothner.com/ > ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2017-09-18 14:31 UTC | newest] Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2017-09-17 15:32 using lambda to implement one method interface Sonny To 2017-09-17 15:38 ` Sonny To 2017-09-17 15:59 ` Per Bothner 2017-09-17 16:04 ` Sonny To 2017-09-17 16:50 ` Per Bothner 2017-09-17 18:54 ` Sonny To 2017-09-17 20:02 ` Per Bothner 2017-09-18 6:35 ` Sonny To 2017-09-18 8:17 ` Sonny To 2017-09-18 13:59 ` Per Bothner 2017-09-18 11:22 ` Sudarshan S Chawathe 2017-09-18 14:24 ` Per Bothner 2017-09-18 14:31 ` Sudarshan S Chawathe
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).