4

I have to work with this huge monolithic code that was written in Java and has hundreds of code-repetitions like:

createButtonOne() {
    ... 
    public boolean pressed() {
        doSomething();
        return true;
    }
}

createButtonTwo() {
    ...
    public boolean pressed() {
        doAnotherThing();
        return true;
    }
}

The code literally is the same apart from the function that is called, but it's rather annoying. Of course I could outsource great parts of the methods but this would cost me more time than doing it right with better tools. Or so I thought.

What I want to do is this:

ScalaButton buttonOne = new ScalaButton();
buttonOne.create("Label", Controller.doSomething());

ScalaButton buttonTwo = new ScalaButton();
buttonTwo.create("Label2", Controller.doAnotherThing());

Therefore I created ScalaButton as follows:

class ScalaButton
{
    def create(label:String, action: () => Unit): Unit = 
    {
        val button:Button = singletonCreator.createButton(label);
        button.addListener(new InputListener()
        {
            override def pressed(...)
            {
                action()
                true
            }
        }
}

The problem is that I've never done this call from Java and it says

found void, required scala.Function0

So I wonder, is it even possible to pass a java-method call to Scala this (or another) way? I haven't worked with Java in a few months and never used it alongside Scala in this way...

1 Answers1

1

It does not compile since you're not passing the method to ScalaButton.create, you're passing the result of the method call, which is void.

If you want to pass a function to Scala from Java, you need to construct an instance of - in this case - AbstractFunction0<BoxedUnit>, which corresponds to () => Unit.

To do this, you need to:

import scala.AbstractFunction0
import scala.runtime.BoxedUnit

and then:

buttonOne.create("Label", new AbstractFunction0<BoxedUnit>() {
    @Override
    public BoxedUnit apply() {
        Controller.doSomething()
        return BoxedUnit.UNIT;
    }
});

There is also a Function0<BoxedUnit>, but you don't want to use it - it's not intended to be constructed in Java.

As you can see it's not exactly straightforward to use. If you're using Java 8 though, you can streamline this a bit.

You'd need to define a function like this one:

private static Function0<BoxedUnit> getBoxedUnitFunction0(Runnable f) {
    return new AbstractFunction0<BoxedUnit>() {

            @Override
            public BoxedUnit apply() {
                f.run();
                return BoxedUnit.UNIT;
            }
        };
}

Don't forget to import scala.Function0 - here it's not constructed, so it's OK. Now you can use it like that:

buttonOne.create("Label", getBoxedUnitFunction0(Controller::doSomething));
Paweł Motyl
  • 1,304
  • 10
  • 16
  • 1
    So if NOT using Java 8 I would replace dozens of (rather useless) inline functions with other (rather useless) inline functions? I wanted to have this abstract like "buttonOne.create("Label", method()") and not having to define the callback yet again :( (As I see this, with this approach I don't gain _anything_ :() –  May 09 '15 at 22:21
  • Unfortunately no - method references (like `Controller::doSomething`) are only supported from Java 8. There is no pretty way to make Java understand Scala's abstractions. – Paweł Motyl May 10 '15 at 07:50
  • That's very unfortunate, but thank you very much for your clarification. Reminds me of always using Scala for my own (and/or new) projects :) –  May 10 '15 at 10:43