How do you convert from a scala class to Dynamic, so unmentioned javascript functions can be called?
How do you convert from Dynamic to a scala class?
If by Scala class you mean a typed facade to JavaScript classes, i.e., a class/trait that extends js.Object, then you can convert simply with an asInstanceOf. For example:
val dateStatic = new js.Date
val dateDynamic = dateStatic.asInstanceOf[js.Dynamic]
The other direction is the same:
val dateStaticAgain = dateDynamic.asInstanceOf[js.Date]
.asInstanceOf[T] is always a no-op (i.e., a hard cast) when T extends js.Any.
If, however, by Scala class you mean a proper Scala class (that is not a subtype of js.Object), then basically you can do the same thing. But only #JSExport'ed members will be visible from the js.Dynamic interface. For example:
class Foo(val x: Int) {
def bar(): Int = x*2
#JSExport
def foobar(): Int = x+4
}
val foo = new Foo(5)
val fooDynamic = foo.asInstanceOf[js.Dynamic]
println(fooDynamic.foobar()) // OK, prints 9
println(fooDynamic.bar()) // TypeError at runtime
Related
How can I implement the following psuedocode in Scala using reflection?
I require this for the purposes of looking-up a generic type from Guice:
trait Foo[A]
class FooInt extends Foo[Int]
class FooString extends Foo[String]
bind(new TypeLiteral<Foo<Int>>() {}).to(FooInt.class);
def fooTypeLiteral(paramA: Class[_]): TypeLiteral[_] = ???
val foo = injector.getInstance(fooTypeLiteral(classOf[Int])
// foo: FooInt
Note: I do not have access to the type of A at compile time, hence the _. The entire solution needs to be performed reflectively (e.g. I cannot have parameterizeFoo[A : ClassTag](...)).
You could try to create a ParameterizedType and pass it to the factory method of the TypeLiteral:
def fooTypeLiteral(paramA: Class[_]): TypeLiteral[_] = {
TypeLiteral.get(new java.lang.reflect.ParameterizedType() {
def getRawType = classOf[Foo[_]]
def getOwnerType = null
def getActualTypeArguments = Array(paramA)
})
}
If you have only a finite number of Foo implementations, you could try this:
trait Foo[A]
class FooInt extends Foo[Int]
class FooString extends Foo[String]
val TLFI = new TypeLiteral[Foo[Int]](){}
val TLFS = new TypeLiteral[Foo[String]](){}
bind(TLFI).to(FooInt.class);
bind(TLFS).to(FooString.class);
def fooTypeLiteral(c: Class[_]): TypeLiteral[_] = {
if (c == classOf[Int]) TLFI
else if (c == classOf[String]) TLFS
else throw new Error
}
Both Scala and Java compilers implement generics with type erasure. This means that all type information for sub-types of generics is lost when the source code is converted to JVM byte code. If the generic class itself does not hold ClassTag or similar, embedded information, then you cannot get the class at run time.
I am trying to debug a scala program. I found a trait which behavior is similar to following:
trait A {
val a: Int = b
val b: Int = a
}
class B extends A
If we look at the trait there is cyclic assignment. val b is not even defined but used in definition of val a.
The above program compile successfully. Both a and b is zero. I tried to the same with variable type string and then value was null.
There is a third class that override val a similar to following
class C extends A {
override val a: Int = 10
}
Now if an instance of class C is created value a is 10 but val of b is still 0.
Finally, I checked further and instead of overriding a in the body of class, when I override it in constructor parameter similar to following:
class D(override val a: Int) extends A
val d = new D(10)
then both d.a and d.b is initialized to 10.
I wanted to understand that:
How definition of val in trait A is valid? In other words how scala interprets the val assignment in trait A
When a val that is defined in a trait is overridden in the body of a scala class what value is being used in the body of the trait if the same val is used in the trait elsewhere
Given a concrete class of a given trait
trait Trt {
val x: Int
}
class C extends Trt {
val x: Int = 3
}
I'd like to create an object of an anonymous class of a parametric type in order to override the attribute x
abstract class SomeClass[T <: Trt : ClassTag] {
def f: Unit = {
val original = new C
//Is this even possible?
val withOverridenX = new T { override val x = 42}
assert(original.x != withOverridenX.x)
}
}
The problem is that the compiler keeps reporting the following error:
>> Error:(26, 35) class type required but T found
Is instancing anonymous classes extenging parametric types classes even possible?
I know the problem is that T is a type and not a class and I wonder if maybe, thanks to ClassTag bounded contex, it could be possible to instantiate withOverridenX.
You can't instantiate T since it is not known at runtime, just at compile time. The ClassTag would just give you acces to the Class object of T through the runtimeClass method. But with just that, you can't subclass T by calling new, since there's for example no evidence that T has a parameterless constructor.
I found a workaround which allows to do exactly as I want which is: Get an instance of C (or a subclass of C) with a different value for x than the one given at its declaration time.
Whenever someone wants to abuse a programming language it is usual to turn to reflection. Since version 2.10, Scala offers its own reflection capabilities (aside Java's) so it is possible to change x for withOverridenX:
import scala.reflect.runtime.universe._
abstract class SomeClass[T <: Trt : TypeTag ] {
def f: Unit = {
val original = new C
val withOverridenX = new C
//This gets the term representation for the attribute 'x'...
val xTerm = typeOf[T].declaration(newTermName("x")).asTerm
//... which can be used to reflect the attribute:
val m = runtimeMirror(getClass.getClassLoader)
val reflectedC = m.reflect(withOverridenX)
val reflectedX = reflectedC.reflectField(xTerm)
reflectedX.set(42)
assert(original.x != withOverridenX.x)
}
}
I'm just learning about classes and objects and Scala, and yesterday I saw something like this:
class Foo(bar: Int) {
def increaseByOne = bar + 1
}
Why am I able to use bar in method increaseByOne? I would expect the the method definition complain about not knowing bar.
I though the right way to define such a class would be
class Foo(x: Int) {
val bar = x
def increaseByOne = bar + 1
}
That's one of the wonderful features of Scala: if you reference constructor argument from any method that is not a constructor, Scala will automatically assign that constructor variable to a field. So effectively Scala translates your first code snippet into the second one for you (with private[this] modifier).
Moreover, preceding constructor argument with val/var will create getters/setters as well:
class Foo(val bar: Int)
val foo = new Foo(42);
println(foo.bar)
In this case bar is defined as private[this] and can be acessed within the class definition. You can check it with -Xprint:typer option:
class Foo extends java.lang.Object with ScalaObject {
<paramaccessor> private[this] val bar: Int = _;
def this(bar: Int): $line1.$read.$iw.$iw.Foo = {
Foo.super.this();
()
}
}
Section 4.6.2 of the Scala Language Specification Version 2.8 describes repeated parameters and says:
The last value parameter of a parameter section may be suffixed by “*”, e.g. (..., x:T*). The type of such a repeated parameter inside the method is then the sequence type scala.Seq[T].
However, this code:
abstract class A { def aSeq : Seq[A] }
class B(val aSeq : A*) extends A
class C extends B { override val aSeq :Seq[A] = Seq() }
give an error when compiled:
overriding value aSeq in class B of type A*; value aSeq has incompatible type
The compiler seems to indicate that A* is a distinct type from Seq[A].
Investigating the actual class of aSeq in this case shows it to be an instance of scala.collection.mutable.WrappedArray$ofRef but even the following code fails to compile with the same message:
class C extends B { override val aSeq = new ofRef(Array[A]()) }
So the question is, how do I go about overriding a member defined by a repeated parameter on the class?
In case you're wondering where this is coming from, that is exacly what scala.xml.Elem does to override the child method in scala.xml.Node.
Your issue can be summarized as:
scala> class A { def aSeq(i: Int*) = 1 }
defined class A
scala> class B extends A { override def aSeq(i: Seq[Int]) = 2 }
<console>:6: error: method aSeq overrides nothing
class B extends A { override def aSeq(i: Seq[Int]) = 2 }
The methods have different types. The spec says (emphasis mine):
The type of such a repeated parameter inside the method is then the sequence type scala.Seq[T]
As Int* and Seq[Int] aren't inside the method, this particular sentence does not apply.
Interestingly, this following code shows that the methods have different types before erasure but the same after:
scala> class G { def aSeq(i:Int*) = 1; def aSeq(i:Seq[Int]) = 2 }
<console>:5: error: double definition:
method aSeq:(i: Seq[Int])Int and
method aSeq:(i: Int*)Int at line 5
have same type after erasure: (i: Seq)Int
class G { def aSeq(i:Int*) = 1; def aSeq(i:Seq[Int]) = 2 }
So the question then becomes, why your B class can extend your A abstract class. There may be an inconsistency in the spec there. I don't know...
Edit: I re-read the spec and I can't figure out if there is anything related to repeated parameters and overriding. There does not seem to be anything about return type of repeated parameters, which is what you get for the val aSeq accessor method.
I think Mark's answer is a perfectly valid approach. In case you can't follow it, you can use the following workaround:
class C extends B {
private def aSeqHelper(a: A*) = a
override val aSeq = aSeqHelper(Seq[A](): _*)
}
So for instance:
import scala.xml._
class ElemX extends Elem("pref", "label", <xml a="b"/>.attributes, TopScope) {
private def childHelper(c: Node*) = c
override val child = childHelper(<foo/><bar/>: _*) }
Then:
scala> new ElemX
res4: ElemX = <pref:label a="b"><foo></foo><bar></bar></pref:label>
The copy method of xml.Elem uses it like this
def copy(
prefix: String = this.prefix,
label: String = this.label,
attributes: MetaData = this.attributes,
scope: NamespaceBinding = this.scope,
child: Seq[Node] = this.child.toSeq
): Elem = Elem(prefix, label, attributes, scope, child: _*)
So you can override the value in the B constructor
class C extends B(aSeq = Seq(): _*)
Or declare it as a parameter of the class C
class C(seq: Seq[A]) extends B(aSeq = seq: _*)
Though I am not sure it answers your question!
The spec never allowed for repeated types to leak out in this way. The compiler was changed in July 2011 to enforce this.
For more background, check out the comments in the ticket:
https://issues.scala-lang.org/browse/SI-4176