I created a class A that extends class B, which takes two parameters.
When I create a class object of A using reflection and passing two parameters, an object is create w/o any exception, but the two "constructor" parameters do not contain the values I passed.
Is that the intended behaviour or am I doing something wrong?
Sample code:
class B (p1: Int = 0, p2: String = "") {
...
}
class A extends B {
...
}
val mirror = universe.runtimeMirror(getClass.getClassLoader)
val classSymbol = mirror.classSymbol(Class.forName("package.A"))
val constructor = mirror.reflectClass(classSymbol).reflectConstructor(
classSymbol.toType.decl(universe.termNames.CONSTRUCTOR).asMethod)
val object: B = constructor(1, "C").asInstanceOf[B]
"object" contains an instance of A, but with p1 = 0 and p2 = "". I expected it to contain p1 = 1 and p2 = "C".
If I move (p1: Int = 0, p2: String = "") to A it works as expected.
Is that the normal behaviour and my expectations were just wrong, or is there a mistake in my code?
Let's first take reflection out of the picture completely, and just try to do what you are doing without using reflection:
class B(p1: Int = 0, p2: String = "")
class A extends B
//val b = (new A(1, "C")).asInstanceOf[B]
// even simpler:
val b = new A(1, "C")
// error: too many arguments for constructor A: ()A
// new A(1, "C")
// ^
As you can see, it doesn't even compile. Why? Well, you defined A's constructor to take no arguments! Somehow, during the reflection process, this information gets lost and you end with a legal call passing arguments to a constructor that doesn't take any and just ignores them.
I don't know the underlying reason, but it probably has to do with some quirk in how reflection works at runtime.
In any case this kind of code will get you what you want (without repeating the default values specified in the superclass). Note that you should explicitly specify the parameters from the superclass you are using in the subclass:
class B (p1: Int = 0, p2: String = "") {
override def toString: String = s"p1 = $p1, p2 = $p2"
}
class A (p1: Int, p2: String) extends B (p1, p2) { }
...
val obj: B = constructor(1, "C").asInstanceOf[B]
println(obj)
Output:
p1 = 1, p2 = C
Related
Is it possible to have constructor parameters that don't become fields? For example,
class Foo(p1: String, p2: Int) {
val f1 = p1 * p2
}
The only field I want is f1, not p1 and p2. The idea is to derive fields from parameters.
This is good as it is - both p1 and p2 aren't fields here, just f1. Making them fields is opt-in rather than opt-out (except for case classes, where all parameters are also fields, and you can't do anything about it).
To make them fields, you'd have to add var or val, something like
class Foo(val p1: String, var p2: Int)
EDIT:
In case you want a field with the same name as a parameter but a different type or something, you can do something like this:
class Foo(p1: String, val p2: Int) {
//Can be val if you want
var _p1: Int = (p1 : String).toInt
def p1: Int = _p1
def p1_=(p1: Int) = _p1 = p1 //An optional setter
}
This is practically the same as having a field called p1.
If you also want to set fields using some complex operations and use local variables, you can use blocks (and maybe an auxiliary constructor)
class Foo(p1: String, val p2: Int) {
val _p1: Int = {
val intermediateVariable: String = p1
intermediateVariable.toInt
}
def p1: Int = _p1
or
class Foo(val p1: Int) {
def this(p1: String) = this({
val uselessIntermediateVariable = p1.toInt
uselessIntermediateVariable
})
}
In a simple class, if you don't add any modifier as val or var, the parameters of the constructor are private elements. Example:
class C(val a: Int, b: Int) {
val c = a + b
}
val i = new C(1,2)
println(i.a) // it's public
println(i.b) // this line won't allow you to compile, it's private
println(i.c) // also public
The exception is made is you make a case class, with case modifier all the parameters of the constructor will be public. You can make them private marking as private the parameter. Example:
case class C(a: Int, private val b: Int) {
val c = a + b
}
val i = new C(1,2)
println(i.a) // it's public
println(i.b) // this line won't allow you to compile, it's private
println(i.c) // also public
Just to clarify the existing answers, non-case class parameters can automatically become fields, but only if they are used in methods or lazy val initializers, e.g.
class Foo(p1: String, p2: Int) {
val f1 = p1 * p2
def m1() = p1 + p1
}
will make p1 a field. There's no way to avoid it other than not using them in such a way.
say i have enumeration like this
object SimpleEnum extends Enumeration{
val ONE = Value(1)
val TWO = Value(2)
val THREE = Value(3)
etc...
}
also i've a class which i want to be extending Ordered[SimpleEnum]
class SimpleClass(se: SimpleEnum) extends Ordered[SimpleEnum] {
override def compare(that: SimpleEnum): Int = this.se.[here i want to get instance of SimpleEnum, just like i used to do in java, but unfortunately it's not possible]
}
So in SimpleClass i just need to get the Value attached to corresponding SimpleEnum val.
In java i'm able to declare a variable on enum and access an actual value corresponding to it by this var, in scala i'm looking for a way to get an instance of enum and reach out for its value.
It is possible, use id method.
scala> object E extends Enumeration {
val A = Value(1)
val B = Value(7)
val C = Value(2)
}
defined object E
scala> E.A.id
res7: Int = 1
scala> E.B.id
res8: Int = 7
scala> E.C.id
res9: Int = 2
Enumeration values can also be easly compared
scala> E.A < E.B
res10: Boolean = true
scala> E.C < E.B
res11: Boolean = true
scala> E.B < E.A
res12: Boolean = false
Refer to documentation for more
Edit
Your code in the picture is wrong. Firstly, as in your original code (that is not in the picture), SimpleEnum should be an object, not a class. As soon as you make that change your code won't compile and that should ring a bell.
You want SimpleClass to be able to wrap your enum values. Type of those values (i.e. ONE, TWO, THREE) is not SimpleEnum, it is SimpleEnum.Value. Objects of this type have id method.
class SimpleClass(se: SimpleEnum.Value) extends Ordered[SimpleEnum.Value] {
override def compare(that: SimpleEnum.Value): Int = se.id
}
A common thing to do is to declare a type alias for Value with exact same name as the enum object. Then you can import this type and use it
object SimpleEnum extends Enumeration {
type SimpleEnum = Value
val ONE = Value(1)
val TWO = Value(2)
val THREE = Value(3)
}
import SimpleEnum.SimpleEnum
class SimpleClass(se: SimpleEnum) extends Ordered[SimpleEnum] {
override def compare(that: SimpleEnum): Int = se.id
}
Note that Enumeration#Value already implements Ordered[Value]. You can verify it in the docs that I linked earlier.
There is no classic java enum in scala, but because the language is so cool, it was possible to create a regular class called Enumeration that with some tricks allows for similar behavior.
The question is already answered but my approach is the following:
object SimpleEnum extends Enumeration{
type SimpleEnum = Value
val ONE = Value(1)
val TWO = Value(2)
val THREE = Value(3)
etc...
}
class SimpleClass(val i : Int){
def getNumber() {
import SimpleEnum._
SimpleEnum(i)
}
}
I'm trying to understand scala type parameters and having a bit of difficulty figuring out how to do conversions.
Suppose I'm modeling tic-tac-toe:
sealed trait Side {
def toChar : Char
def toInt : Int
def toDouble : Double = toInt.toDouble
}//end trait Side
case object X extends Side {
override val toChar = 'X'
override val toInt = -1
}//end case object X extends Side
case object O extends Side {
override val toChar = 'O'
override val toInt = 1
}//end case object O extends Side
case object EMPTY extends Side {
override val toChar = '*'
override val toInt = 0
}
I then model a tic tac board in a way that both naturally represents the game and also can be converted to a numeric array that is useful with machine learning techniques.
class Board(val rows : Int = 3,
val cols : Int = 3,
val repr : Array[Array[Side]] = Array.ofDim[Side](3,3)) {
def flatten : Array[Side] = repr.flatten
/**
* Converts this board into a 1-D numeric array. This is likely the
* incorrect method signature.
*/
def flattenNumeric[T] : Array[T] = ???
}
My question is: how do I replace the ????
I would like to be able to make calls of the form
val board = new Board
board.flattenNumeric[Int] //returns Array(0, 0, 0, 0, 0, 0, 0, 0, 0)
board.flattenNumeric[Double] //returns Array(0.0, 0.0, ...)
Thank you in advance for your assistance.
If there are only two type parameters you need this to work with, I'd suggest just writing separate flattenInt and flattenDouble methods—it's much simpler and clearer. That's not an answer to your question, though, so if you really want this to be generic, the standard Scala way would be to use a type class like this:
class Board(val rows: Int = 3,
val cols: Int = 3,
val repr: Array[Array[Side]] = Array.ofDim[Side](3,3)) {
def flatten: Array[Side] = repr.flatten
trait FromSide[A] {
def apply(side: Side): A
}
object FromSide {
implicit object intFromSide extends FromSide[Int] {
def apply(side: Side) = side.toInt
}
implicit object doubleFromSide extends FromSide[Double] {
def apply(side: Side) = side.toDouble
}
implicit object charFromSide extends FromSide[Char] {
def apply(side: Side) = side.toChar
}
}
/**
* Converts this board into a 1-D numeric array. This is likely the
* incorrect method signature.
*/
def flattenNumeric[T: FromSide: Manifest]: Array[T] =
flatten.map(implicitly[FromSide[T]].apply)
}
Now e.g. board.flattenNumeric[Int] will compile, but flattenNumeric[String] won't.
Note that the Manifest part is only necessary because you're using Array—if you switch to Scala's own collection types you wouldn't need it.
It's also possible to do this by using manifests or type tags, but that's a quick way to make your program a horrible mess of runtime errors.
Let us assume we have a trait T. What is the best way to achieve the following:
Everybody who writes an implementation of T should be forced to provide a possibility that allows a parameter-free initialization of T, i.e., we probably have to enforce the implementation of a configurable factory.
All logic/data that only depends on the actual initialization parameters (of a certain implementation A of T) should be handled/stored centrally, but should be available in both the factory and A.
The most simple/concise way I see to achieve this (approximately) would be to add a trait for a factory and link T to this factory:
trait T {
val factory: TFactory
}
trait TFactory {
def build(): T
val description: String // example for logic/data that only depend on the parameters
}
// example implementation:
class A(val factory: AFactory, paramA: Int, paramB: Int, paramC: Int) extends T
class AFactory(paramA: Int, paramB: Int, paramC: Int) extends TFactory {
def build = new A(this, paramA, paramB, paramC)
val description = f"$paramA $paramB $paramC"
}
Obviously this does not really "enforce" the implementation of a factory (as long as there is an alternative implementation available) and obviously it is possible to generate instantiations of A which link to a "wrong" TFactory. What I also don't like about this approach is the repetition of the initialization parameters. I often create yet another class AParams which again wraps all parameters (for instance to facilitate adding new parameters). Thus, I end up with three classes, which imho is a lot of boilerplate for this simple problem.
My question is whether there is a (maybe completely) different approach, which achieves the same primary goals but is more concise?
I'm not quite sure I get the full intent of your requirements but what do you think of this behavior?
trait TFactory{
def build():T
val description:String
}
trait T extends TFactory
//can't declare A without build and not make it abstract
class A(paramA: Int, paramB: Int, paramC: Int) extends T {
def build = new A(paramA, paramB, paramC)
val description = f"$paramA $paramB $paramC"
}
val a1 = new A(1, 4, 5)
val a2 = a1.build()
//We can give ourselves as a factory to something that expects TFactory
val factory:TFactory = a1
val a_new = factory.build()
//More likely we can just give our build method
def func(f: ()=>T) = {
val new_t = f()
new_t
}
val a_newer = func(a1.build)
println(a1 +": " + a1.description)
println(a2 +": " + a2.description)
println(a_new +": " + a_new.description)
println(a_newer +": " + a_newer.description)
Output:
Main$$anon$1$A#69267649: 1 4 5
Main$$anon$1$A#69b1fbf4: 1 4 5
Main$$anon$1$A#24148662: 1 4 5
Main$$anon$1$A#3f829e6f: 1 4 5
Add a representation type parameter:
trait Factory[Prod] {
def build(): Prod
}
trait Prod[Repr] {
def factory: Factory[Repr]
}
Or, if you want to "enforce" that the type remains the same (I wouldn't do that unless you gain something from it):
trait Prod[Repr <: Prod[Repr]] {
def factory: Factory[Repr]
}
Then:
case class AConfig(a: Int, b: Int)
case class A(config: AConfig) extends Prod[A] {
def factory = AFactory(config)
}
case class AFactory(config: AConfig) extends Factory[A] {
def build() = A(config)
}
val f0 = AFactory(AConfig(1, 2))
val p0 = f0.build()
val f1 = p0.factory
val p1 = f1.build()
assert(p0 == p1)
I'm trying to make Scala find the right type for a path-dependent type coming from a singleton type.
First, here is the type container for the example, and one instance:
trait Container {
type X
def get(): X
}
val container = new Container {
type X = String
def get(): X = ""
}
I can see the String in this first attempt (so I already have a working scenario):
class WithTypeParam[C <: Container](val c: C) {
def getFromContainer(): c.X = c.get()
}
val withTypeParam = new WithTypeParam[container.type](container)
// good, I see the String!
val foo: String = withTypeParam.getFromContainer()
But when there is no type parameter, this does not work anymore.
class NoTypeParam(val c: Container) {
def getFromContainer(): c.X = c.get()
}
val noTypeParam = new NoTypeParam(container)
// this does *not* compile
val bar: String = noTypeParam.getFromContainer()
Does anybody know why the type parameter is needed?
See this thread on scala-internals, in particular, Adriaan's explanation.