How can I call a function named apply() defined on a Javascript object from Scala.js code?
The obvious solution does not work since apply is always compiled into a function call on its parent object by Scala.JS (?):
var test = {
apply: function(idx) {...},
apple: function(idx) {...}
}
trait Test extends js.Object {
def apple(idx: Int) : Int = ???
def apply(idx: Int) : Int = ???
}
val test = js.Dynamic.global.test.asInstanceOf[Test]
test.apple(1) // works, of course
test.apply(1) // does not work (seems to be compiled into the call test(1) ?)
js.Dynamic.global.test.apply(1) // does not work either
You can annotate the apply method in your facade type with #JSName("apply"). This will yield the desired behavior:
trait Test extends js.Object {
def apple(idx: Int) : Int = ???
#JSName("apply")
def apply(idx: Int) : Int = ???
}
Testing:
val test = js.Dynamic.literal(
apply = (idx: Int) => idx,
apple = (idx: Int) => idx
).asInstanceOf[Test]
test.apple(1) // -> 1
test.apply(1) // -> 1
For the dynamically typed case, you'll have to invoke applyDynamicNamed manually:
val dyn = test.asInstanceOf[js.Dynamic]
dyn.applyDynamicNamed("apply")(1) // -> 1
Related
Let's say I have a class called A:
class A(i: Int) {
//private def to initialize a calculated value
def maintainedValue : Int = calculatedValue
def double : A = new A(maintainedValue * 2)
def combine(other: A) : A = new A(maintainedValue + other.maintainedValue)
def addAmt(amt : Int) : A = new A(maintainedValue + amt)
// Many many more methods
}
I want to define a class B that extends class A such that it's methods, almost all of which have similar logic, return an object of class B:
class B(i: Int) extends A(i) {
//private def to initialize a differently calculated value
def maintainedValue : Int = diffCalculatedValue
//Change all other methods to return type B without override???
}
Is it possible to do this without overriding all the methods?
Is there a simple way to instantiate these new instances with a variable/dynamic class?
Perhaps there is a more elegant way to do this?
One solution, and the simplest one in my opinion, is to change class A to have a structure such that a single method handles object creation:
def create(i: Int): TYPE = new B(i)
And just use an implicit method in class B to handle casting when calling the unaltered methods:
private implicit def convert(a: A): B = new B(a.maintainedValue)
Short and sweet, though I'm curious how efficient and/or scale-able this solution is.
How about having base trait with common logic and two implementation?
object App extends App {
println(A(1).double)
println(B(1).double)
}
trait A {
type TYPE
def create(i: Int): TYPE
def maintainedValue: Int
def double: TYPE = create(maintainedValue * 2)
def addAmt(amt: Int): TYPE = create(maintainedValue + amt)
}
trait B extends A {
}
object A {
def apply(i: Int) = new AImpl(i)
case class AImpl(i: Int) extends A {
override type TYPE = A
override def create(i: Int) = A(i)
override def maintainedValue: Int = 2
}
}
object B {
def apply(i: Int): B = new BImpl(i)
case class BImpl(i: Int) extends B {
override type TYPE = B
override def create(i: Int): TYPE = B(i)
override def maintainedValue: Int = 1
}
}
I cannot understand why Scala is not able to infer an overloaded method's arguments :
object A {
implicit object SequenceMarker
implicit object IntMarker
def b(f: Int => Seq[Int])(implicit ev: SequenceMarker.type) = 0
def b(f: Int => Int)(implicit ev: IntMarker.type) = 0
def c() = { b(i => i + 1) } // this doesn't compile
}
When I try to compile this, I get the following error :
error: missing parameter type
def c() = { b(i => i + 1) }
I've made some investigation using javap and scala -print and figure out that the previous code cannot be compiled without specifying what i is :
object A {
...
def c() = { b((i: Int) => i + 1) }
}
Why is that so ? Is there any other way to overload a method while not specifying its argument's type during the call ?
Thank you in advance.
UPDATE
I've noticed using scala -print :
#SerialVersionUID(value = 0) final <synthetic> class anonfun$c$1 extends scala.runtime.AbstractFunction1$mcII$sp with Serializable {
final def apply(i: Int): Int = anonfun$c$1.this.apply$mcII$sp(i);
<specialized> def apply$mcII$sp(i: Int): Int = i.+(1);
final <bridge> <artifact> def apply(v1: Object): Object = scala.Int.box(anonfun$c$1.this.apply(scala.Int.unbox(v1)));
def <init>(): <$anon: Function1> = {
anonfun$c$1.super.<init>();
()
}
}
that the argument seems to be casted in some way:
scala.Int.box(anonfun$c$1.this.apply(scala.Int.unbox(v1)))
This line changes depending on the argument's type :
scala.Int.box(anonfun$c$1.this.apply(scala.Int.unbox(v1)));
...
scala.Int.box(anonfun$c$1.this.apply(v1.$asInstanceOf[String]()))
which would explain why the type is required. Here is the whole log :
package <empty> {
object A extends Object {
def b(f: Function1, ev: A$SequenceMarker.type): Int = 0;
def b(f: Function1, ev: A$IntMarker.type): Int = 0;
def c(): Int = A.this.b({
(new <$anon: Function1>(): Function1)
}, A$IntMarker);
def <init>(): A.type = {
A.super.<init>();
()
}
};
object A$SequenceMarker extends Object {
def <init>(): A$SequenceMarker.type = {
A$SequenceMarker.super.<init>();
()
}
};
object A$IntMarker extends Object {
def <init>(): A$IntMarker.type = {
A$IntMarker.super.<init>();
()
}
};
#SerialVersionUID(value = 0) final <synthetic> class anonfun$c$1 extends scala.runtime.AbstractFunction1$mcII$sp with Serializable {
final def apply(i: Int): Int = anonfun$c$1.this.apply$mcII$sp(i);
<specialized> def apply$mcII$sp(i: Int): Int = i.+(1);
final <bridge> <artifact> def apply(v1: Object): Object = scala.Int.box(anonfun$c$1.this.apply(scala.Int.unbox(v1)));
def <init>(): <$anon: Function1> = {
anonfun$c$1.super.<init>();
()
}
}
}
Therefore, what I want to achieve cannot be done in the way previously described. Any other idea ?
UPDATE 2
I've also tried :
def c() = { b(_ + 1) }
but I get another error
error: missing parameter type for expanded function ((x$1) => x$1.$plus(1))
def c() = { b(_ + 1) }
When I comment the first b(f: Int => Seq[Int]), it compiles well.
It's because for purposes of overload resolution, arguments are typed without an expected type, so there is no information about what function is expected.
http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#overloading-resolution
The compiler doesn't care that the set of possible overloads includes only methods that take an Int.
I wanted to instantiate a trait and override a protected function g, making it accessible (function f is for testing).
trait A {
protected def g( i: Int ) = println( i )
def f( i: Int ) = println( i )
}
I created an object a1
val a1= new A {
override def f( i: Int ) = super.f(i)
override def g( i: Int ) = super.g(i)
def h( i: Int ) = super.g(i)
}
and tried to call the methods
a1.f(1)
a1.g(3) // this call fails
a1.h(5)
For a1.g(3) I get this error:
<console>:10: error: method g in trait A cannot be accessed in A{def h(i: Int): Unit}
Access to protected method g not permitted because
enclosing object $iw is not a subclass of
trait A where target is defined
a1.g(3) // this call fails
But when I define a trait A2 extending A and overriding the methods f and g, create an instance of it and call the methods, all works fine
trait A2 extends A {
override def f( i: Int ) = super.f(i)
override def g( i: Int ) = super.g(i)
def h( i: Int ) = super.g(i)
}
val a2= new A2 {}
a2.f(2)
a2.g(4)
a2.h(6)
Why is there a difference between
val a1= new A {
override def g( i: Int ) = super.g(i)
}
and
trait A2 extends A {
override def g( i: Int ) = super.g(i)
}
val a2= new A2 {}
?
Thanks!
I'll just go ahead and make my comment an answer. It's a bug. It really should work the way you expect, but it doesn't.
In Java protected member is accessible to both subclasses and the package in which the member is defined, in Scala, on the other hand, member is visible only to subclasses.
In your case, the code is probably called from outside of a class implementing A (e.g. from worksheet)
If you want to simulate Java behavior, then you can use notation
protected[package_name] def g(i: Int) = println(i)
then, the method g() will be visible inside the package package_name
You don't have to play games with override just for testing. You can do something like this:
package com.foo.bar
trait MyTrait{
def stuff(i: Int) = hidden(i) + 1
protected[bar] hidden(i: Int): Int
}
and then in the test file
package com.foo.bar
class Testing extends Specification{
"hidden" must{
//some tests in here
}
which is another way of saying, "hidden is visible at the package level and thus anything within that package can see/test it."
Suppose that I want to write a case class Stepper as follows:
case class Stepper(step: Int) {def apply(x: Int) = x + step}
It comes with a nice toStringimplementation:
scala> Stepper(42).toString
res0: String = Stepper(42)
but it's not really a function:
scala> Some(2) map Stepper(2)
<console>:10: error: type mismatch;
found : Stepper
required: Int => ?
Some(2) map Stepper(2)
A workaround is to implement the Function trait...
case class Stepper(step: Int) extends (Int => Int) {def apply(x: Int) = x + step}
But then, I can't have for free a nice toString implementation anymore:
scala> Stepper(42).toString
res2: java.lang.String = <function1>
Then, the question is: can I have the best of these two worlds? Is there a solution where I have the nice toString implementation for free AND an implementation of trait Function. In other words, is there a way to apply the linearization in such a way that case class syntaxic sugar is applied at last?
The question is not really to do with linearisation. In case-classes toString is a method automatically generated by the compiler if and only if Any.toString is not overridden in the end-type.
However, the answer is partly to do with linearisation - we need to override Function1.toString with the method that would have been generated by compiler if not for the version introduced by Function1 :
trait ProperName extends Product {
override lazy val toString = scala.runtime.ScalaRunTime._toString(this)
}
// now just mix in ProperName and... magic!
case class Stepper(step: Int) extends (Int => Int) with ProperName {
def apply(x:Int) = x+step
}
Then
println(Some(2) map Stepper(2))
println(Stepper(2))
Will produce
Some(4)
Stepper(2)
Update
Here is a version of ProperName trait that doesn't rely on the undocumented API method:
trait ProperName extends Product {
override lazy val toString = {
val caseFields = {
val arity = productArity
def fields(from: Int): List[Any] =
if (from == arity) List()
else productElement(from) :: fields(from + 1)
fields(0)
}
caseFields.mkString(productPrefix + "(", ",", ")")
}
}
Alternative toString implementation is derived from the source code for the original _toString method scala.runtime.ScalaRunTime._toString.
Please note that this alternative implementation is still based on the assumption that a case class always extends Product trait. Although the latter holds true as of Scala 2.9.0 and is a fact that is known to and relied upon by some members of Scala community it's not formally documented as part of Scala Language Spec.
EDIT: What about overriding toString?
case class Stepper(step: Int) extends (Int => Int) {
def apply(x: Int) = x + step
override def toString = "Stepper(" + step + ")"
}
You can use an implicit conversion to have Stepper treated like a function only when necessary:
case class Stepper(step: Int) { def apply(x: Int) = x + step }
implicit def s2f(s: Stepper) = new Function[Int, Int] {
def apply(x: Int) = s.apply(x)
}
Now you get the case class's toString when you call Stepper(42).toString, but Some(2) map Stepper(2) also works as desired.
(Note that I've been more verbose than necessary above to keep the mechanics clear. You can also write implicit def s2f(s: Stepper) = s.apply _ or any number of other more concise formulations).
I want to do this:
abstract class Context {
def getInt(id: Int): Int
}
abstract class Dependency[+T]
(val name: String, val id: Int)
extends Function1[Context,T]
class IntDependency(name: String, id: Int)
extends Dependency[Int](name, id) {
def apply(implicit context: Context): Int =
context.getInt(id)
}
But then I get an error message like this:
class IntDependency needs to be abstract, since method apply in trait
Function1 of type (v1: Context)Long is not defined (Note that T1 does
not match Context)
I understand that implicits should normally be part of the second parameter list, but I can't work out how to code it so it compiles, and gives the result I want.
Explanation: I'm trying to create a framework where one can define "Function" object, which can depend on other functions to compute their value. All functions should only take a single Context parameter. The context know the "result" of the other functions. The function instances should be immutable, with the state residing in the context. I want the functions to create "dependency" fields at creation time, which take the context implicitly, and return the value of the dependency within that context, so that accessing the dependency inside of the apply method "feels like" accessing a parameter or field, that is without explicitly giving the context as parameter to the dependency.
Are you sure you need your Dependency to extend a Function? Because if you don't, just leave the extends Function1[Context,T] part out and your code will work.
If you really need to extend a Function than I don't know of a solution in your case. But there are cases where you could try to overload the apply method. Like here:
scala> val sum = new Function1[Int, Function1[Int, Int]] {
| def apply(a: Int) = (b: Int) => a + b
| def apply(a: Int)(implicit b: Int) = a + b
|}
sum: java.lang.Object with (Int) => (Int) => Int{def apply(a:Int)(implicit b: Int): Int} = <function1>
scala> sum(2)(3)
res0: Int = 5
scala> implicit val b = 10
b: Int = 10
scala> sum(2)
res1: Int = 12
A method may have its final parameter section marked implicit; it need not be the second section, although that is most commonly seen.
But it seems that when a subclass marks a parameter section implicit, it is no longer considered to override the method in the superclass.
scala> new (Int => Int) { def apply(implicit i: Int) = i }
<console>:8: error: object creation impossible, since method apply in trait Function1 of type (v1: Int)Int is not defined
(Note that T1 does not match Int)
new (Int => Int) { def apply(implicit i: Int) = i }
^
scala> trait F1 { def f(a: Any) }; new F1 { def f(implicit a: Any) = () }
<console>:8: error: object creation impossible, since method f in trait F1 of type (a: Any)Unit is not defined
trait F1 { def f(a: Any) }; new F1 { def f(implicit a: Any) = () }
^
The spec does not specifically mention this (§5.1.4 Overriding), so it may be an implementation restriction, or an bug.
Its sure, that your apply method signature with implicit doesn´t conform with the signature of Function1.apply.
Hopefully I get your problem right, so what about (assuming that your context is mutable and perhaps singleton) having the implicit context injected at creation time? Is that possible in your case?
class IntDependency(id: Int)(implicit context: Context) extends Dependency[Int](id)
But then I wonder (and still was wondering before) what to do with the context argument at the apply method.
Here is the working solution:
abstract class Context {
def getInt(id: Int): Int
}
abstract class Dependency[+T]
(val name: String, val id: Int) {
def get(context: Context): T
}
class IntDependency(name: String, id: Int)
extends Dependency[Int](name, id) {
def get(context: Context): Int =
context.getInt(id)
}
implicit def intDep2Int(dep: IntDependency)
(implicit context: Context): Int =
dep.get(context)