Invoke Scala call-by-name method from Java

331 views
Skip to first unread message

刘斌

unread,
Feb 25, 2016, 8:36:48 AM2/25/16
to scala-user
This my scala code:
class A {
  def ensure(f: => Unit): Unit
}

How can I invoke this method from Java?
I tried many ways but failed...

Jasper-M

unread,
Feb 25, 2016, 9:03:36 AM2/25/16
to scala-user
Let's have a look.

scala> abstract class A {

     
|   def ensure(f: => Unit): Unit
     
| }
defined class A


scala
> :javap -p A
Compiled from "<console>"
public abstract class A {
 
public abstract void ensure(scala.Function0<scala.runtime.BoxedUnit>);
 
public A();
}

So I guess you have to give it a Function0 object whose apply method returns a BoxedUnit.

a.ensure(new scala.Function0<scala.runtime.BoxedUnit>{
   
public scala.runtime.BoxedUnit apply() {
       
//do some stuff
       
return scala.runtime.BoxedUnit.UNIT
   
}
})


Op donderdag 25 februari 2016 14:36:48 UTC+1 schreef 刘斌:

Seth Tisue

unread,
Feb 25, 2016, 10:08:55 AM2/25/16
to scala-user
see also http://stackoverflow.com/a/8380694/86485 — making a scala.FunctionN from Java is much easier if you use AbstractFunctionN

Jasper-M

unread,
Feb 25, 2016, 10:11:06 AM2/25/16
to scala-user
Okay, apparently because of Function0 being specialized for primitive types this is a lot more complex (maybe even not possible to write in Java, I'm not sure) :/
You're probably better off writing some Java-compatible wrapper in Scala first. Or wait until someone who knows more about the internals comes along.

Op donderdag 25 februari 2016 15:03:36 UTC+1 schreef Jasper-M:

Oliver Ruebenacker

unread,
Feb 25, 2016, 10:17:41 AM2/25/16
to Jasper-M, scala-user

     Hello,

  Not sure how specialization is a problem, unless you want to write generic functions and specialize them.

     Best, Oliver

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

Jasper-M

unread,
Feb 25, 2016, 10:23:21 AM2/25/16
to scala-user, jaspe...@gmail.com
If you extend from Function0 you have to implement a whole bunch of methods which are needed for specialization.
But I'm pretty sure Seth's answer solves that problem. I didn't see it in time.

Op donderdag 25 februari 2016 16:17:41 UTC+1 schreef Oliver Ruebenacker:

Oliver Ruebenacker

unread,
Feb 25, 2016, 10:29:44 AM2/25/16
to Jasper-M, scala-user

     Hello,

  Looks like in Scala, you only have to implement the apply method - do you have to implement more when extending it in Java?

scala> val f = new Function0[Int] { def apply() : Int = 42 }
f: () => Int = <function0>

scala> println(f())
42

     Best, Oliver

Jasper-M

unread,
Feb 25, 2016, 11:38:19 AM2/25/16
to scala-user, jaspe...@gmail.com
Yup, you need to implement at least all these methods:

scala> :javap -p scala.Function0
Compiled from "Function0.scala"
public interface scala.Function0<R> {
 
public abstract R apply();
 
public abstract java.lang.String toString();
 
public abstract boolean apply$mcZ$sp();
 
public abstract byte apply$mcB$sp();
 
public abstract char apply$mcC$sp();
 
public abstract double apply$mcD$sp();
 
public abstract float apply$mcF$sp();
 
public abstract int apply$mcI$sp();
 
public abstract long apply$mcJ$sp();
 
public abstract short apply$mcS$sp();
 
public abstract void apply$mcV$sp();
}



Op donderdag 25 februari 2016 16:29:44 UTC+1 schreef Oliver Ruebenacker:

Oliver Ruebenacker

unread,
Feb 25, 2016, 11:41:20 AM2/25/16
to Jasper-M, scala-user

     Hello,

  Why you don't have to implement these in Scala? Thanks!

     Best, Oliver

Seth Tisue

unread,
Feb 25, 2016, 11:58:17 AM2/25/16
to scala-user
because Scala understands that traits can include default implementations for some methods. from Java, the trait just shows up as an interface, with all methods abstract.

Oliver Ruebenacker

unread,
Feb 25, 2016, 2:18:10 PM2/25/16
to Seth Tisue, scala-user

     Hello,

  Where are these default methods defined? I don't see them in Function0, and there are no super-types besides AnyRef.

     Best, Oliver

On Thu, Feb 25, 2016 at 11:58 AM, Seth Tisue <se...@tisue.net> wrote:
because Scala understands that traits can include default implementations for some methods. from Java, the trait just shows up as an interface, with all methods abstract.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Clint Gilbert

unread,
Feb 25, 2016, 2:57:39 PM2/25/16
to scala...@googlegroups.com
They're added by the compiler due to the @specialized annotation on
Function0's type param. From Scala code they're invoked when/if
possible by the compiler; see the semi-mangled names.

On 02/25/2016 02:17 PM, Oliver Ruebenacker wrote:
>
> Hello,
>
> Where are these default methods defined? I don't see them in
> Function0, and there are no super-types besides AnyRef.
>
> Best, Oliver
>
> On Thu, Feb 25, 2016 at 11:58 AM, Seth Tisue <se...@tisue.net
> <mailto:se...@tisue.net>> wrote:
>
> because Scala understands that traits can include default
> implementations for some methods. from Java, the trait just shows up
> as an interface, with all methods abstract.
>
> --
> You received this message because you are subscribed to the Google
> Groups "scala-user" group.
> To unsubscribe from this group and stop receiving emails from it,
> send an email to scala-user+...@googlegroups.com
> <mailto:scala-user+...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout.
>
>
>
>
> --
> Oliver Ruebenacker
> Senior Software Engineer, Diabetes Portal
> <http://www.type2diabetesgenetics.org/>, Broad Institute
> <http://www.broadinstitute.org/>
>
> --
> You received this message because you are subscribed to the Google
> Groups "scala-user" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to scala-user+...@googlegroups.com
> <mailto:scala-user+...@googlegroups.com>.
signature.asc

sunnykaka

unread,
Feb 25, 2016, 9:20:00 PM2/25/16
to scala-user
Thanks Jasper-M.
I tried your solution, this is my Test class:
class A {
def ensure(f: => Unit): Unit println("ensure")
}

public class B {

public static void main(String[] args) {
A a = new A();
a.ensure(new scala.Function0<scala.runtime.BoxedUnit>() {
@Override
public scala.runtime.BoxedUnit apply() {
                return scala.runtime.BoxedUnit.UNIT;
}
});
}

}

The IDEA error is: 
ensure (scala.Function0<void>) in A cannot be applied to (anonymous scala.Function0<scala.runtime.BoxedUnit>)

If I ignore the IDEA error and compile the code, I get this error:
Error:(12, 65) java: <匿名com.akkafun.B$1>不是抽象的, 并且未覆盖scala.Function0中的抽象方法apply$mcV$sp()
which means anonymous com.akkafun.B$1 is not abstract, and not override the abstract method apply$mcV$sp() in scala.Function0.

sunnykaka

unread,
Feb 25, 2016, 9:41:36 PM2/25/16
to scala-user
Hi Seth, I visited the link you provided.

This is not the problem I want to solve.

I want to invoke a call-by-name scala method from Java.

e.g.
def ensure1(f: => Unit): Unit

not this: 
def ensure2(f: Unit => Unit): Unit

I can invoke the latter method from Java easily:

class A {
def ensure1(f: => Unit): Unit = println("ensure1")

def ensure2(f: Unit => Unit): Unit = {
println("before invoke f in ensure2")
f()
}

}

public class B {

public static void main(String[] args) {
A a = new A();
//        a.ensure1(new scala.Function0<scala.runtime.BoxedUnit>() {
// @Override
// public scala.runtime.BoxedUnit apply() {
// return scala.runtime.BoxedUnit.UNIT;
// }
// });

a.ensure2(new AbstractFunction1<BoxedUnit, BoxedUnit>() {
@Override
public BoxedUnit apply(BoxedUnit v1) {
System.out.println("invoke ensure2 success");
return BoxedUnit.UNIT;
}
});
}

}


Run class B will print:
before invoke f in ensure2
invoke ensure2 success

Seth Tisue

unread,
Feb 25, 2016, 10:43:13 PM2/25/16
to scala-user
javap will show you that this:

  def ensure1(f: => Unit): Unit = ...

compiles to the same bytecode, from Java's point of view, as:

  def ensure2(f: () => Unit): Unit = ...

note `() => Unit`, not `Unit => Unit`.

so calling it from Java using AbstractFunction0 works fine:


  A a = new A();
  a.ensure1(new scala.runtime.AbstractFunction0<scala.runtime.BoxedUnit>() {
  @Override public scala.runtime.BoxedUnit apply() { 
    return BoxedUnit.UNIT;
  }));

sunnykaka

unread,
Feb 26, 2016, 12:44:00 AM2/26/16
to scala-user
Yes, it works, the code is good to compile and run.

although IDEA still report the same error.

Thanks a lot.
Reply all
Reply to author
Forward
0 new messages