Pass Scala.js class instance to JavaScript that will invoke the function call method - scala.js

I have a simple Scala.js class (Scala-2.12.10 and Scala-js 0.6.31):
class Foo extends js.Object {
def apply() = { println("apply") }
def bar() = { println("bar") }
}
val myfoo = new Foo()
An instance of Foo will be passed to a JavaScript library which will in turn attempt to invoke the following two methods:
myfoo()
myfoo.bar()
Of course, this will not work because I cannot define the apply method on Foo since it derives from js.Object and that will not translate to calling () on the object.
How does one construct an appropriate class for this scenario?
Update:
Here is some example code based on #sjrd's answer that provides for strong typing while encapsulating the js.Dynamic complexity.
trait FooTrait extends js.Object {
def own()
def bar()
}
class Foo extends FooTrait {
def own() = { println("apply") }
def bar() = { println("bar") }
}
def makeFoo(foo: FooTrait]) = {
val jsFoo = ({ () =>
foo.own()
}: js.Function0[Unit]).asInstanceOf[js.Dynamic]
jsFoo.bar = ({ () =>
foo.bar()
}: js.Function0[Unit])
jsFoo
}
val myFoo = makeFoo(new Foo())
Now myFoo is ready to be passed to the JavaScript library.

In JavaScript, the only way that a call like myfoo() can be valid is if myfoo was created as a function value. To make myfoo.bar() work in addition, that must be patched on the function value after it's created. There is no way (except proxies, which are another beast entirely) to create myfoo as an object first, from a class or not, and make it answer to myfoo().
Therefore, this is also what you have to do in Scala.js:
val myfoo = ({ () =>
println("apply")
}: js.Function0[Unit]).asInstanceOf[js.Dynamic]
myfoo.bar = ({ () =>
println("bar")
}: js.Function0[Unit])
After that, you can pass myfoo to the JavaScript code.

Related

Scala - why cannot use trait from object

I have created a simple application with singleton object which contains local traits:
object Singleton {
trait FirstTrait {
val func1 = (i: Int) => i * 2
}
trait SecondTrait {
val func2 = (s: String) => s
}
trait ThirdTrait {
val func3 = () => println("Func 3")
}
}
And now, in Main object, I would like to do something like this:
object Main extends App {
val singleton = Singleton.FirstTrait//cannot do this
}
But I cannot do this (compile error). Why? Why I have not an access into this local trait? If I change Singleton object into:
object Singleton {
trait FirstTrait {
val func1 = (i: Int) => i * 2
}
trait SecondTrait {
val func2 = (s: String) => s
}
trait ThirdTrait {
val func3 = () => println("Func 3")
}
object FirstObject extends FirstTrait {
println(func1)
}
}
Main works well and program compiles. But I call another singleton object from Singleton, not a trait. I understand that trait cannot be instanced, but I think it is not a solution for it, because I have also a simple ScalaTest test name, which looks like
"Singleton" should "test it" in Singleton.FirstTrait{...}
and here I have an access into FirstTrait. So why I cannot use it in normal code?
I cannot understand it well. Maybe I am an idiot, but if someone could explain it to me well, I would be greatful.
It's a trait so you'll need to "instantiate" it properly:
val singleton = new Singleton.FirstTrait {}
// singleton: Singleton.FirstTrait = $anon$1#5e97da56
Note that technically a trait cannot be instantiated. The above expression is an instantiation of the anonymous class that extends the trait.
Singleton.FirstTrait is a type, not a value. You can't write
val singleton = Singleton.FirstTrait
any more than you can write
val singleton = Int
val singleton = String
etc. Traits and classes can have companion objects (objects with the same name), but FirstTrait obviously doesn't have one.
You can use it as a type, e.g.
def foo(x: Singleton.FirstTrait) = {}
val x: Singleton.FirstTrait = new Singleton.FirstTrait {}

Scala: Companion object with arguments

I am looking for a way to initialize a companion object with arguments. I tried this, it has the risk for re-instantiation.
private[mypackage] class A(in:Int) {
def method = {}
}
object A {
var singleton: Option[A] = None
def getInstance(): A = {
if(singleton.isDefined)
singleton.get
else {
throw InitializationException("Object not configured")
}
}
def getInstance(in:Int): A = {
singleton = Some(new A(in))
singleton.get
}
}
Is there a better way?
Pure Scala way
Scala allows you to create a singleton object of a type using object keyword. Scala ensures only one instance of A is available in the system.
private[myPackage] object A {
val configValue = Config.getInt("some_value")
def fn: Unit = ()
}
type of A object
scala> object A {}
defined object A
scala> :type A
A.type
more about singleton objects in scala Explanation of singleton objects in Scala
Guice Annotations
import com.google.inject.Singleton
#Singleton
class A (val value: Int) {
def fn: Unit = ()
}
Classic Java way
Use synchronized keyword to protect the getInstance from creating more than one object when called. of course constructor of the class has to be private
You can use a lazy val to delay creation of your singleton, and base it on a var that should be updated once during start-up sequence:
object A {
// will be instantiated once, on first call
lazy val singleton: A = create()
private var input: Option[Int] = None
// call this before first access to 'singleton':
def set(i: Int): Unit = { input = Some(i) }
private def create(): A = {
input.map(i => new A(i))
.getOrElse(throw new IllegalStateException("cannot access A before input is set"))
}
}

Is it possible to call an overridden method from self type?

Consider this:
class Foo { def foo = "foo" }
trait Bar { self: Foo =>
override def foo = "bar"
}
I was pleasantly surprised to find out that this is possible, and works as expected:
new Foo with Bar foo
returns "bar". The question is whether it is possible for Bar.foo to invoke Foo.foo, like one would often do in the "ordinary" inheritance case. override def foo = super.foo + "bar" does not work (says "foo is not a member of AnyRef), and neither does override def foo = self.foo + "bar" (it ends up just calling itself, and results in infinite recursion).
I tried a few other combinations (like self.Foo.foo, Foo.this.foo etc.), but without any luck.
Is this just impossible?
No. It is impossible to call overridden method from a self type.
Firstly the trait Bar is not a successor of class Foo so it is not possible using super.foo.
And secondly it is also not possible using self.foo since self is actually of type Bar with Foo. It can be shown by printing the program after typer:
$ scalac -Xprint:typer test.scala
[[syntax trees at end of typer]] // test.scala
package <empty> {
class Foo extends scala.AnyRef {
def <init>(): Foo = {
Foo.super.<init>();
()
};
def foo: String = "foo"
};
abstract trait Bar extends scala.AnyRef { self: Bar with Foo =>
def /*Bar*/$init$(): Unit = {
()
};
override def foo: String = "bar"
};
class FooBar extends Foo with Bar {
def <init>(): FooBar = {
FooBar.super.<init>();
()
}
};
object TestApp extends scala.AnyRef {
def <init>(): TestApp.type = {
TestApp.super.<init>();
()
};
def main(args: Array[String]): Unit = {
val a: FooBar = new FooBar();
scala.this.Predef.println(a.foo)
}
}
}
So with self.foo you are trying to access the method foo of the trait Bar. Such behavior matches the Scala Specification (PDF):
The sequence of template statements may be prefixed with a formal
parameter definition and an arrow, e.g. x =>, or x: T =>. If a formal
parameter is given, it can be used as an alias for the reference this
throughout the body of the template. If the formal parameter comes
with a type T, this definition affects the self type S of the
underlying class or object as follows: Let C be the type of the class
or trait or object defining the template. If a type T is given for the
formal self parameter, S is the greatest lower bound of T and C. If no
type T is given, S is just C. Inside the template, the type of this is
assumed to be S.
It is possible to access the method using reflection but I think that it is not what you are looking for.
I am not aware of any particular syntax to disentangle the base class and the mixed-in trait.
There is, however, an easy solution to achieve the result manually by distinguishing the overridden method from the default implementation in the base class:
class Foo { def foo = defaultFoo; def defaultFoo = "foo" }
trait Bar { self: Foo => override def foo = self.defaultFoo + "bar" }
As expected
new Foo with Bar foo == "foobar"
new Foo foo == "foo"
You make your trait extend Foo instead of using the self type:
class Foo {def foo = "foo"}
trait Bar extends Foo {
override def foo = super.foo + "bar"
}
new Foo with Bar foo // barfoo
See also this answer.

Pass a reference to a no-argument method in scala

How can I pass a reference to a no-argument method reference in scala?
For example:
class Foo {
def foo: String = computeSomethingAndReturnIt
}
object Foo extends App {
def acceptSupplier(???) { doSomethingWithFooSupplier }
val f = new Foo
acceptSupplier(f.foo ???)
}
I know I can define foo to accept Unit by declaring def foo()... and this will work, but is there a way to pass foo and have it accept zero arguments as shown above in the code snippet?
You can use a by-name argument:
def acceptSupplier(f: => String) { ... }
val f = new Foo
acceptSupplier(f.foo)
Or more explicitly:
def acceptSupplier(f: () => String) { ... }
val f = new Foo
acceptSupplier(f.foo _)

Forwarding calls to underlying object in Scala

I have the following class definition:
class Foo[T](iteratorThunk: () => Iterator[T]) {
def values = iteratorThunk()
}
And I would like Foo to have all the methods that Iterator exposes, while still returning objects of type Foo. For instance, I would like to be able to do:
val a = new Foo({ () => List(1, 2, 3).toIterator })
val b = new Foo({ () => List(4, 5, 6).toIterator })
val c = a ++ b
And have c equal to:
new Foo({ () => a.values ++ b.values })
I had a look at forwarders (IterableForwarder, TraversableForwarder, ...), but none seemed fit to forward methods to an Iterator, and I would still like to keep Foo as both the static and dynamic result type.
What is the best way to achieve this behavior, without defining every forwarding method?
I need the Foo class as it is, and not only as an Iterator because I
need to be able to do more than one pass through its values.
Then you want either a Traverable or an Iterable. To have them work as you wish, you need to extend both them and TraversableLike or IterableLike, through which you'll specify the return type. And you'll need to provide both a Builder and a CanBuildFrom as well.
Here's a simple implementation:
import scala.collection.IterableLike
import scala.collection.mutable.LazyBuilder
class Foo[T](iteratorThunk: () => Iterator[T]) extends Iterable[T] with IterableLike[T, Foo[T]] {
def iterator = iteratorThunk()
override protected def newBuilder = new Foo.FooBuilder[T]
}
object Foo {
class FooBuilder[T] extends LazyBuilder[T, Foo[T]] {
def result(): Foo[T] = {
val coll = parts.toList.flatten
new Foo(() => coll.iterator)
}
}
}