Before Scala 2.10 I had
class A {
class B(b: Int) {
}
}
and somewhere in code recreate class B with
val bCtor = bInstance.getClass.getConstructor(classOf[Int])
bCtor.newInstance ...
and everything was fine. It was with signature public A$B(Int)
Now constructor have 2!!! arguments. It has a new signature public A$B(A,Int). What is argument with type A? I don't have access to A class from my function. It there any workaround?
For example newInstance with arguments - It doesn't work anymore for inner class
Be carful not to confuse java inner class with scala path-dependent type
(from the Programming In ScalaBook) :
A path-dependent type resembles the syntax for an inner class type in Java, but there is a crucial difference: a path-dependent type names an outer object, whereas an inner class type names an outer class
So in your case bInstance is related to an aInstance.
My assumption is that aInstance is the object passed as the first parameter to this constructor.
You can use an unconstrained self-type annotation to have a way to refer to the A's version of this even from within B (where this now refers to the B instance).
package rrs.scribble
object OuterInner {
class Outer { oThis =>
class Inner {
def identify { printf("I am %s; I'm inside of %s%n", this, oThis) }
}
val inner = new Inner
}
def oiTest {
val o1 = new Outer
o1.inner.identify
}
}
In the REPL:
Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_37).
scala> import rrs.scribble.OuterInner._
import rrs.scribble.OuterInner._
scala> oiTest
I am rrs.scribble.OuterInner$Outer$Inner#63d0d313; I'm inside of rrs.scribble.OuterInner$Outer#22d1b797
First, adding A as the first constructor argument is also the way it works in Java:
If this Class object represents an inner class declared in a non-static context, the formal parameter types include the explicit enclosing instance as the first parameter.
Second,
What is argument with type A? I don't have access to A class from my function.
If you have a B (as seems from your example), then you can access its enclosing instance (it doesn't seem to be documented officially, and so may change in the future versions of Java):
val aInstance = bInstance.getClass.getDeclaredField("this$0").get(bInstance)
bCtor.newInstance(aInstance, ...)
If you don't, then you can't create a B (without an A), but you shouldn't be able to. What would you expect this code to return?
class A(foo: Int) {
class B {
def bar = foo
}
}
classOf[A#B].getConstructor().newInstance().bar
#evantill is right, the only constructor of B is A$B.<init>(A, Int). So bInstance.getClass.getConstructor(classOf[A], classOf[Int]) works.
Related
I have a generic class which takes one type, and I have a parameter from that type. The issue is that I need to use a method from this parameter (in my problem, I need to use the method getTimestamp).
I can't have a trait or an abstract class because I know that, at some point, the type will be a Java Class that I can't modified.
I tried something like this :
type InputWithTimestamp = {def getTimestamp: Long}
class Foo[Input <: InputWithTimestamp](f : Input) {
def printTimestamp = { println(f.getTimestamp) }
}
class Test(timestamp : Long) {
def getTimestamp = timestamp
}
val t = new Test(1000)
val f = new Foo(t)
f.printTimestamp
And it is perfectly working.
But as I said, at some point I need to use a java class as a type.
And here is my problem :
Even if the java class defined a method getTimestamp which returns a long, I have the following error :
Error: inferred type arguments [MyJavaClass] do not conform to class Foo's type parameter bounds [Input <: InputWithTimestamp]
So what can I do to have a generic type which defined this method without needing to modify my java class ?
The problem in my case was that I didn't use parentheses to declare my method getTimestamp (because you get a warning in IDEA if you do so).
But in that case, I need the parentheses, otherwise the java method getTimestamp doesn't match the scala method
type InputWithTimestamp = {def getTimestamp: Long}
works perfectly.
Why wouldn't the scala compiler dig this:
class Clazz
class Foo[C <: Clazz] {
val foo = new C
}
class type required but C found
[error] val a = new C
[error] ^
Related question - How to get rid of : class type required but T found
This is a classic generic problem that also happens in Java - you cannot create an instance of a generic type variable. What you can do in Scala to fix this, however, is to introduce a type evidence to your type parameter that captures the runtime type:
class Foo[C <: Clazz](implicit ct: ClassTag[C]) {
val foo = ct.runtimeClass.newInstance
}
Note that this only works if the class has a constructor without any arguments. Since the parameter is implicit, you don't need to pass it when calling the Foo constructor:
Foo[Clazz]()
I came up with this scheme, couldn't simplify it through a companion object thought.
class Clazz
class ClazzFactory {
def apply = new Clazz
}
class Foo(factory: ClazzFactory) {
val foo: Clazz = factory.apply
}
It's very annoying that ClazzFactory can't be an object rather than a class though. A simplified version:
class Clazz {
def apply() = new Clazz
}
class Foo(factory: Clazz) {
val foo: Clazz = factory.apply
}
This requires the caller to use the new keyword in order to provide the factory argument, which is already a minor enough annoyance relative to the initial problem. But, scala could have made this scenario all more elegant; I had to fallback here to passing a parameter of the type I wish to instantiate, plus the new keyword. Maybe there's a better way.
(motivation was to instantiate that type many times within the real Foo, that's why this is at all a solution; otherwise my pattern above is just redundantly meaningless).
Is it worth, to control the visibility of case class that represent value object ? If so, is a visibility modifier on the case class enough, or using an explicit companion object, and a private constructor, would be better ?
Version 1:
case class MyClass private/protected/private[] {}
Version 2:
case class MyClass private
object MyClass {
def apply = {
new MyClass
}
}
In sum, the question could be summarize as how to deal with value object in scala.
I personally want to enforce the no new, so that is i want to change something in the creation of the object, I can do it at any time. That is, by simply adding a companion object when necessary.
A visibility modifier on the case class constructor does not propagate to the companion object, so creating one yourself by hand with the exact same apply method is unnecessary.
You can verify this yourself trivially:
$ scala
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_37).
Type in expressions to have them evaluated.
Type :help for more information.
scala> case class X private () {}
defined class X
scala> new X
<console>:10: error: constructor X in class X cannot be accessed in object $iw
new X
^
scala> X()
res1: X = X()
Note that just plain X is the name of the companion object. You can't get a new X by naming the companion object; that won't call its apply method even if a no-argument apply exists. So you can't omit the empty parameter list ().
The above is all true in the REPL, but compiled code fails.
I'm trying to figure out how to .clone my own objects, in Scala.
This is for a simulation so mutable state is a must, and from that arises the whole need for cloning. I'll clone a whole state structure before moving the simulation time ahead.
This is my current try:
abstract trait Cloneable[A] {
// Seems we cannot declare the prototype of a copy constructor
//protected def this(o: A) // to be defined by the class itself
def myClone= new A(this)
}
class S(var x: String) extends Cloneable[S] {
def this(o:S)= this(o.x) // for 'Cloneable'
def toString= x
}
object TestX {
val s1= new S("say, aaa")
println( s1.myClone )
}
a. Why does the above not compile. Gives:
error: class type required but A found
def myClone= new A(this)
^
b. Is there a way to declare the copy constructor (def this(o:A)) in the trait, so that classes using the trait would be shown to need to provide one.
c. Is there any benefit from saying abstract trait?
Finally, is there a way better, standard solution for all this?
I've looked into Java cloning. Does not seem to be for this. Also Scala copy is not - it's only for case classes and they shouldn't have mutable state.
Thanks for help and any opinions.
Traits can't define constructors (and I don't think abstract has any effect on a trait).
Is there any reason it needs to use a copy constructor rather than just implementing a clone method? It might be possible to get out of having to declare the [A] type on the class, but I've at least declared a self type so the compiler will make sure that the type matches the class.
trait DeepCloneable[A] { self: A =>
def deepClone: A
}
class Egg(size: Int) extends DeepCloneable[Egg] {
def deepClone = new Egg(size)
}
object Main extends App {
val e = new Egg(3)
println(e)
println(e.deepClone)
}
http://ideone.com/CS9HTW
It would suggest a typeclass based approach. With this it is possible to also let existing classes be cloneable:
class Foo(var x: Int)
trait Copyable[A] {
def copy(a: A): A
}
implicit object FooCloneable extends Copyable[Foo] {
def copy(foo: Foo) = new Foo(foo.x)
}
implicit def any2Copyable[A: Copyable](a: A) = new {
def copy = implicitly[Copyable[A]].copy(a)
}
scala> val x = new Foo(2)
x: Foo = Foo#8d86328
scala> val y = x.copy
y: Foo = Foo#245e7588
scala> x eq y
res2: Boolean = false
a. When you define a type parameter like the A it gets erased after the compilation phase.
This means that the compiler uses type parameters to check that you use the correct types, but the resulting bytecode retains no information of A.
This also implies that you cannot use A as a real class in code but only as a "type reference", because at runtime this information is lost.
b & c. traits cannot define constructor parameters or auxiliary constructors by definition, they're also abstract by definition.
What you can do is define a trait body that gets called upon instantiation of the concrete implementation
One alternative solution is to define a Cloneable typeclass. For more on this you can find lots of blogs on the subject, but I have no suggestion for a specific one.
scalaz has a huge part built using this pattern, maybe you can find inspiration there: you can look at Order, Equal or Show to get the gist of it.
The following code tries to mimic Polymorphic Embedding of DSLs: rather than giving the behavior in Inner, it is encoded in the useInner method of its enclosing class. I added the enclosing method so that user has only to keep a reference to Inner instances, but can always get their enclosing instance. By doing this, all Inner instances from a specific Outer instance are bound to only one behavior (but it is wanted here).
abstract class Outer {
sealed class Inner {
def enclosing = Outer.this
}
def useInner(x:Inner) : Boolean
}
def toBoolean(x:Outer#Inner) : Boolean = x.enclosing.useInner(x)
It does not compile and scala 2.8 complains about:
type mismatch; found: sandbox.Outer#Inner
required: _81.Inner where val _81:sandbox.Outer
From Programming Scala: Nested classes and A Tour of Scala: Inner Classes, it seems to me that the problem is that useInnerexpects as argument an Inner instance from a specific Outer instance.
What is the true explanation and how to solve this problem ?
I suppose the type Inner is like the type this.Inner. Outer#Inner is independent of the outer instance (not a path-dependent type).
abstract class Outer {
sealed class Inner {
def enclosing = Outer.this
}
def useInner(x:Outer#Inner) : Boolean
}
def toBoolean(x:Outer#Inner) : Boolean = x.enclosing.useInner(x)
The problem is as you describe, that useInner is expecting an Inner of a specific Outer instance. Since enclosing returns a generic Outer, there is really no way to tie both together that I know of.
You can force it, however:
def toBoolean(x: Outer#Inner): Boolean = {
val outer = x.enclosing
outer.useInner(x.asInstanceOf[outer.Inner])
}
You can also define your member like this:
def useInner(x:Outer#Inner) : Boolean
Or you can write like this:
abstract class Outer {
class InnerImpl {
def enclosing = Outer.this
}
final type Inner = Outer#InnerImpl
def useInner(x:Inner) : Boolean
}