Is new required when calling a Scala auxiliary constructor? - scala

When I run the following in a worksheet, everything is as expected.
case class P(x: Int, xs: Set[Int]) {
def this(x: Int) = this(x, Set[Int]())
}
P(1, Set()) //> res0: worksheet.P = P(1,Set())
new P(1) //> res0: worksheet.P = P(1,Set())
When I leave off the new I get a compiler diagnostic that says:
- not enough arguments for method apply: (x: Int, xs: Set[Int])worksheet.P in object P. Unspecified value parameter xs.
The same diagnostic appears in a regular .scala file.
Is this a compiler bug, or am I misunderstanding something?

Without new you're calling not constructor but factory method which is auto-generated by the compiler for case classes. You can define new one:
case class P(x: Int, xs: Set[Int])
object P {
def apply(x: Int): P = P(x, Set[Int]())
}
scala> P(1, Set())
res2: P = P(1,Set())
scala> P(1)
res3: P = P(1,Set())
Alternatively you can use define two constructors, but in your particular case I would go with default value:
case class P(x: Int, xs: Set[Int] = Set[Int]())
See also this answer which showcases similar situation and tour on case classes

Defining case class will also create factory method of class name, so you don't have to use new while creating an instance. So the following code works file:
P(1, Set())
Your class also have constructors, the following code will work fine, too:
new P(1, Set())
new P(1)
In the case of P(1), there's no such method, so the error occurs.

Related

Case class copy does not maintain state of an inherited trait

Say I define a trait and case class that extends it:
trait A {
var list: List[Int] = List()
def add(i: Int) = list = i :: list
}
case class B(str: String) extends A
If I then create an instance of B, modify the list and make a copy of it, the copy takes the values of the list as defined in trait A:
val b = B("foo")
b.add(3)
println("B: " + b.list)
println("Copied: " + b.copy(str = "bar").list)
Output:
B: List(3)
Copied: List()
I know this is probably not good functional programming practice anyway, but is there a way I can force the copy of B to take the altered version of the list for instance b?
You can accomplish this by declaring the list in the case class, and satisfy your trait's type by declaring a method. So:
trait A {
def list: List[Int]
}
case class B(i: Int, var list: List[Int]) extends A
And then your example:
scala> val b = B(2, List(1))
b: B = B(2,List(1))
scala> b.list = List(3)
b.list: List[Int] = List(3)
scala> println("B: " + b.list)
B: List(3)
scala> println("Copied: " + b.copy(i = 4).list)
Copied: List(3)
I don't know what you're doing that requires a mutable list in your class, but I imagine that even though this satisfies your example it might not satisfy whatever problem you're working on since:
scala> val a: A = b
a: A = B(2,List(3))
scala> a.list
res2: List[Int] = List(3)
scala> a.list = List(4)
<console>:15: error: value list_= is not a member of A
a.list = List(4)
When trying to view an instance of B as an A you won't be able to assign the list type. If you were dealing with an instance of A you'd have to do something like
scala> a match {
| case itsAB: B => itsAB.list = List(4); itsAB
| case other => other
| }
res3: A = B(2,List(4))
But either way, this is how you'd do it. Either that or you can follow phongnt's advice to create a non-case class and define a copy method yourself.
In a comment you said:
I failed to mention that the trait attribute needs to be modifiable with a reference to the trait itself
But this sounds like global mutable state to me. If you really need that, and I encourage you to not to then you can use an object:
object A {
#volatile
var list = List.empty[Int]
}
But I doubt this gets at what you're expressing in your question either since there is not an individual list still per instance here. So... looking at your updated question, I can only guess that something like this is what you're trying to accomplish:
object A {
#volatile
var list = List.empty[Int]
}
trait A {
def list = A.list
def add(i: Int) = A.list = i :: A.list
}
case class B(str: String) extends A
Which lets you:
scala> val b = B("hi")
b: B = B(hi)
scala> b.add(0)
scala> b.add(1)
scala> A.list
res4: List[Int] = List(1, 0)
But again, this is global mutable state, it's not a good thing. It's not threadsafe. So if there's a way for you to figure out your problem without doing this... I'd encourage you to do so.
The copy method is generated for you by the compiler when you declare a case class and it is only parameterised with the variables you define in the case class
Hence, you can definitely have copy method do that for you by declaring the variable list in the case class e.g. case class B(i: Int, list: List[Int]). You will also need override val modifier to satisfy scalac. However, scalac doesn't allow you to override a mutable variable, so you need to change the trait too, for example
trait A {
val list: List[Int] = List(1)
}
case class B(i: Int, override val list: List[Int]) extends A

In Scala Reflection, why do constructor params hide getters?

vars in a scala class automatically get getters & setters you can see through scala reflection via members
import scala.reflect.runtime.{universe => ru}
class A(var x: Int)
scala> ru.typeOf[A].members.filter{_.name.toString.contains("x")}
res22: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(variable x, method x_=, method x)
However, if you create a subclass, which re-uses the var name in the constructor, the getter is gone:
class B(x:Int, var y: Int) extends A(x)
scala> ru.typeOf[B].members.filter{_.name.toString.contains("x")}
res23: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(value x, method x_=)
scala> res23.head.asTerm.isVal
res25: Boolean = true
This seems a little misleading ... after all, B still does have a getter for x (and its not a val)
scala> val b = new B(5,6)
b: B = B#270288ed
scala> b.x
res26: Int = 5
scala> b.x = 7
b.x: Int = 7
scala> b.x
res27: Int = 7
If I try to pretend that the value x I got from members is a getter, I get an error:
scala> val xGetter = res23.head.asTerm
xGetter: reflect.runtime.universe.TermSymbol = value x
scala> val objMirror = ru.runtimeMirror(getClass.getClassLoader).reflect(b)
objMirror: reflect.runtime.universe.InstanceMirror = instance mirror for B#270288ed
scala> val getterMirror = objMirror.reflectField(xGetter)
scala.ScalaReflectionException: Scala field x isn't represented as a Java field, neither it has a Java accessor method
note that private parameters of class constructors don't get mapped onto fields and/or accessors,
unless they are used outside of their declaring constructors.
What is the right workaround here? Is it completely wrong to have a subclass name its constructor args the same as the names in the parent args? Or instead of calling members, do I need to work my up all super-classes to get all getters & setters?
Note that members gives me the inherited getter as long as the subclass doesn't create a constructor w/ the same name:
class Y(var x: Int)
class Z(q:Int, z: Int) extends Y(q)
scala> ru.typeOf[Z].members.filter{_.name.toString.contains("x")}
res28: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(method x_=, method x)
EDIT
In case its unclear, I'm really asking:
1) is this a bug in scala reflection?
2) if not, should I:
(a) never have classes use names of constructor fields be the same as the name of fields in base classes? (if so, I'm probably defining all my classes wrong ...)
or
(b) to get all getters & setters, should I just go through the list of all parent classes and use declarations, rather than relying on members to do the right thing, since it doesn't work in this one case?
EDIT 2
in response to #som-snytt's answer, the visible methods of x are really on x in A, not the param in the constructor to B. Eg.:
class A(var x: Int){def showMeX {println(x)}}
class B(x:Int, var y: Int) extends A(x)
scala> val b = new B(5,10)
scala> b.showMeX
5
scala> b.x = 17
b.x: Int = 17
scala> b.showMeX
17
so I don't really think that the either the getter or setter for x has been shadowed, from the perspective of normal user code. Its only been shadowed for reflection code ... and it doesn't make sense to me that there would be two different versions of shadowing.
2) if not, should I: (a) never have classes use names of constructor fields be the same as the name of fields in base classes?
Since they wouldn't let me fix this, that's exactly what I do. I try to give all constructor parameters new names distinct from all inherited names. Here's a typical example within the compiler.
class PackageClassSymbol protected[Symbols] (owner0: Symbol, pos0: Position, name0: TypeName)
Yes, it's ridiculous.
https://groups.google.com/forum/#!topic/scala-language/9jLsT_RRQR0
https://issues.scala-lang.org/browse/SI-3194
https://issues.scala-lang.org/browse/SI-4762
https://issues.scala-lang.org/browse/SI-6880
Oh boy, don't keep pulling that thread...
https://issues.scala-lang.org/browse/SI-7475
https://issues.scala-lang.org/browse/SI-2568
https://issues.scala-lang.org/browse/SI-6794
It shouldn't be hard to see that the odds of any of it being addressed are nil. It's a perfect example of why I quit.
By the way, if you use -Xlint it warns you about this. That's mentioned in SI-4762.
% cat a.scala
class A(var x: Int)
class B(x:Int, var y: Int) extends A(x) {
def z = x
}
% scalac -Xlint a.scala
a.scala:3: warning: private[this] value x in class B shadows mutable x inherited from class A.
Changes to x will not be visible within class B - you may want to give them distinct names.
def z = x
^
one warning found
Well, in:
class B(x:Int, var y: Int) extends A(x)
The x in B is private (not a case class, no val or var specifier), the x in A is public (you specified var). I'm not too familiar with this reflection API, but does it show private members?
If you instead:
scala> class B(val x:Int, var y: Int) extends A(10)
<console>:9: error: overriding variable x in class A of type Int;
value x needs `override' modifier
class B(val x:Int, var y: Int) extends A(10)
^
The only public x is the one in A, which can be shown here:
scala> class B(x:Int, var y: Int) extends A(10)
defined class B
scala> new B(2,3).x
res4: Int = 10
If you want to override the parent member, use override, and change the parent to something that can be overriden.
I guess as long as the answer to my question is not (2a), then if anybody else runs into this, here is a workaround. Maybe it will be unnecessary in the future depending on the answer to (1).
(Some extra stuff here, but maybe useful also)
import scala.reflect.runtime.{universe => ru}
object ReflectionUtils {
def extractGetterSetterPairs(typ: ru.Type): Seq[GetterSetterPair] = {
typ.baseClasses.foldLeft(Seq[GetterSetterPair]()){case (acc, clsSymb) =>
extractGetterSetterPairs(clsSymb.asClass.toType, acc)
}
}
private def extractGetterSetterPairs(typ: ru.Type, acc: Seq[GetterSetterPair]): Seq[GetterSetterPair] = {
val terms = typ.declarations.collect{case x if x.isTerm => x.asTerm}
acc ++ terms.filter{x => x.isGetter}.map{x => x -> x.setter}.
filter{case(g,s) => s.isTerm}.map{case(g,s) =>
GetterSetterPair(g,s.asTerm)
}
}
def termName(t: ru.TermSymbol): String = {
t.name.toString.trim
}
}
case class GetterSetterPair(getter: ru.TermSymbol, setter: ru.TermSymbol) {
val name = ReflectionUtils.termName(getter)
val fieldType = {
//this is way more complicated than it should be. But
// 1) getters for some reason are not instances of ru.MethodType
// java.lang.ClassCastException: scala.reflect.internal.Types$NullaryMethodType cannot be cast to scala.reflect.api.Types$MethodTypeApi
// 2) its a headache to get the types out of setters
val m = setter.typeSignature.
asInstanceOf[ru.MethodType]
m.params.head.typeSignature
}
}

Scala: implicit conversion to generate method values?

If I have the following class in Scala:
class Simple {
def doit(a: String): Int = 42
}
And an instance of that class
o = new Simple()
Is possible to define an implicit conversion that will morph this instance and a method known at compile into a tuple like this?
Tuple2 (o, (_: Simple).doit _)
I was hoping I could come up with one for registering function callbacks in the spirit of:
doThisLater (o -> 'doit)
I functionally have my function callbacks working based on retronym's answer to a previous SO question, but it'd be great to add this thick layer of syntactic sugar.
You can just eta-expand the method. Sample REPL session,
scala> case class Deferred[T, R](f : T => R)
defined class Deferred
scala> def doThisLater[T, R](f : T => R) = Deferred(f)
doThisLater: [T, R](f: T => R)Deferred[T,R]
scala> val deferred = doThisLater(o.doit _) // eta-convert doit
deferred: Deferred[String,Int] = Deferred(<function1>)
scala> deferred.f("foo")
res0: Int = 42

Why do case class companion objects extend FunctionN?

When you create a case class, the compiler creates a corresponding companion object with a few of the case class goodies: an apply factory method matching the primary constructor, equals, hashCode, and copy.
Somewhat oddly, this generated object extends FunctionN.
scala> case class A(a: Int)
defined class A
scala> A: (Int => A)
res0: (Int) => A = <function1>
This is only the case if:
There is no manually defined companion object
There is exactly one parameter list
There are no type arguments
The case class isn't abstract.
Seems like this was added about two years ago. The latest incarnation is here.
Does anyone use this, or know why it was added? It increases the size of the generated bytecode a little with static forwarder methods, and shows up in the #toString() method of the companion objects:
scala> case class A()
defined class A
scala> A.toString
res12: java.lang.String = <function0>
UPDATE
Manually created objects with a single apply method are not automatically considered as FunctionN:
object HasApply {
def apply(a: Int) = 1
}
val i = HasApply(1)
// fails
// HasApply: (Int => Int)
The reason why case class companion objects implement FunctionN is that before, case classes generated a class and a factory method, not a companion object. When we added extractors to Scala it made more sense to turn the factory method into a full companion object with apply and unapply methods. But then, since the factory method did conform to FunctionN, the companion object needed to conform, too.
[Edit] That said, it would make sense to have companion objects show as their own name, not as "function"
Well, given that target.apply(a1, a2, a3 ... aN) in Scala:
can be sugared by target(a1, a2, a3 ... aN)
is the method which needs to be implemented by FunctionN
it seems natural that a companion object:
object MyClass {
def apply(a1 : A1, ... aN: AN) = new MyClass(a1, ..., aN)
}
is really:
object MyClass extends FunctionN[A1, ... , AN, MyClass]{
def apply(a1 : A1, ... aN: AN) = new MyClass(a1, ..., aN)
}
So the addition seems to be natural to me (I'm not sure why it seems "odd" to you?). As to whether it actually added anything; well, that is for someone smarter than me!
Aside from oxbow_lakes's reply about the naturalness of it, it can often be useful to have constructors available as first-class functions, particularly in conjunction with Scala collections higher-order functions. For (a trivial) example,
scala> case class Foo(i : Int)
defined class Foo
scala> List(1, 2, 3) map Foo
res0: List[Foo] = List(Foo(1), Foo(2), Foo(3))
Welcome to Scala version 2.8.0.RC3 (Java HotSpot(TM) Client VM, Java 1.6.0_20).
scala> case class CC3(i: Int, b: Boolean, s: String)
defined class CC3
scala> CC3
res0: CC3.type = <function3>
scala> CC3.apply(1, true, "boo!")
res1: CC3 = CC3(1,true,boo!)
scala> CC3(1, true, "boo!")
res2: CC3 = CC3(1,true,boo!)

Overload constructor for Scala's Case Classes?

In Scala 2.8 is there a way to overload constructors of a case class?
If yes, please put a snippet to explain, if not, please explain why?
Overloading constructors isn't special for case classes:
case class Foo(bar: Int, baz: Int) {
def this(bar: Int) = this(bar, 0)
}
new Foo(1, 2)
new Foo(1)
However, you may like to also overload the apply method in the companion object, which is called when you omit new.
object Foo {
def apply(bar: Int) = new Foo(bar)
}
Foo(1, 2)
Foo(1)
In Scala 2.8, named and default parameters can often be used instead of overloading.
case class Baz(bar: Int, baz: Int = 0)
new Baz(1)
Baz(1)
You can define an overloaded constructor the usual way, but to invoke it you have to use the "new" keyword.
scala> case class A(i: Int) { def this(s: String) = this(s.toInt) }
defined class A
scala> A(1)
res0: A = A(1)
scala> A("2")
<console>:8: error: type mismatch;
found : java.lang.String("2")
required: Int
A("2")
^
scala> new A("2")
res2: A = A(2)