I want to do something like this:
sealed abstract class Base(val myparam:String)
case class Foo(override val myparam:String) extends Base(myparam)
case class Bar(override val myparam:String) extends Base(myparam)
def getIt( a:Base ) = a.copy(myparam="changed")
I can't, because in the context of getIt, I haven't told the compiler that every Base has a 'copy' method, but copy isn't really a method either so I don't think there's a trait or abstract method I can put in Base to make this work properly. Or, is there?
If I try to define Base as abstract class Base{ def copy(myparam:String):Base }, then case class Foo(myparam:String) extends Base results in class Foo needs to be abstract, since method copy in class Base of type (myparam: String)Base is not defined
Is there some other way to tell the compiler that all Base classes will be case classes in their implementation? Some trait that means "has the properties of a case class"?
I could make Base be a case class, but then I get compiler warnings saying that inheritance from case classes is deprecated?
I know I can also:
def getIt(f:Base)={
(f.getClass.getConstructors.head).newInstance("yeah").asInstanceOf[Base]
}
but... that seems very ugly.
Thoughts? Is my whole approach just "wrong" ?
UPDATE I changed the base class to contain the attribute, and made the case classes use the "override" keyword. This better reflects the actual problem and makes the problem more realistic in consideration of Edmondo1984's response.
This is old answer, before the question was changed.
Strongly typed programming languages prevent what you are trying to do. Let's see why.
The idea of a method with the following signature:
def getIt( a:Base ) : Unit
Is that the body of the method will be able to access a properties visible through Base class or interface, i.e. the properties and methods defined only on the Base class/interface or its parents. During code execution, each specific instance passed to the getIt method might have a different subclass but the compile type of a will always be Base
One can reason in this way:
Ok I have a class Base, I inherit it in two case classes and I add a
property with the same name, and then I try to access the property on
the instance of Base.
A simple example shows why this is unsafe:
sealed abstract class Base
case class Foo(myparam:String) extends Base
case class Bar(myparam:String) extends Base
case class Evil(myEvilParam:String) extends Base
def getIt( a:Base ) = a.copy(myparam="changed")
In the following case, if the compiler didn't throw an error at compile time, it means the code would try to access a property that does not exist at runtime. This is not possible in strictly typed programming languages: you have traded restrictions on the code you can write for a much stronger verification of your code by the compiler, knowing that this reduces dramatically the number of bugs your code can contain
This is the new answer. It is a little long because few points are needed before getting to the conclusion
Unluckily, you can't rely on the mechanism of case classes copy to implement what you propose. The way the copy method works is simply a copy constructor which you can implement yourself in a non-case class. Let's create a case class and disassemble it in the REPL:
scala> case class MyClass(name:String, surname:String, myJob:String)
defined class MyClass
scala> :javap MyClass
Compiled from "<console>"
public class MyClass extends java.lang.Object implements scala.ScalaObject,scala.Product,scala.Serializable{
public scala.collection.Iterator productIterator();
public scala.collection.Iterator productElements();
public java.lang.String name();
public java.lang.String surname();
public java.lang.String myJob();
public MyClass copy(java.lang.String, java.lang.String, java.lang.String);
public java.lang.String copy$default$3();
public java.lang.String copy$default$2();
public java.lang.String copy$default$1();
public int hashCode();
public java.lang.String toString();
public boolean equals(java.lang.Object);
public java.lang.String productPrefix();
public int productArity();
public java.lang.Object productElement(int);
public boolean canEqual(java.lang.Object);
public MyClass(java.lang.String, java.lang.String, java.lang.String);
}
In Scala, the copy method takes three parameter and can eventually use the one from the current instance for the one you haven't specified ( the Scala language provides among its features default values for parameters in method calls)
Let's go down in our analysis and take again the code as updated:
sealed abstract class Base(val myparam:String)
case class Foo(override val myparam:String) extends Base(myparam)
case class Bar(override val myparam:String) extends Base(myparam)
def getIt( a:Base ) = a.copy(myparam="changed")
Now in order to make this compile, we would need to use in the signature of getIt(a:MyType) a MyType that respect the following contract:
Anything that has a parameter myparam and maybe other parameters which
have default value
All these methods would be suitable:
def copy(myParam:String) = null
def copy(myParam:String, myParam2:String="hello") = null
def copy(myParam:String,myParam2:Option[Option[Option[Double]]]=None) = null
There is no way to express this contract in Scala, however there are advanced techniques that can be helpful.
The first observation that we can do is that there is a strict relation between case classes and tuples in Scala. In fact case classes are somehow tuples with additional behaviour and named properties.
The second observation is that, since the number of properties of your classes hierarchy is not guaranteed to be the same, the copy method signature is not guaranteed to be the same.
In practice, supposing AnyTuple[Int] describes any Tuple of any size where the first value is of type Int, we are looking to do something like that:
def copyTupleChangingFirstElement(myParam:AnyTuple[Int], newValue:Int) = myParam.copy(_1=newValue)
This would not be to difficult if all the elements were Int. A tuple with all element of the same type is a List, and we know how to replace the first element of a List. We would need to convert any TupleX to List, replace the first element, and convert the List back to TupleX. Yes we will need to write all the converters for all the values that X might assume. Annoying but not difficult.
In our case though, not all the elements are Int. We want to treat Tuple where the elements are of different type as if they were all the same if the first element is an Int. This is called
"Abstracting over arity"
i.e. treating tuples of different size in a generic way, independently of their size. To do it, we need to convert them into a special list which supports heterogenous types, named HList
Conclusion
Case classes inheritance is deprecated for very good reason, as you can find out from multiple posts in the mailing list: http://www.scala-lang.org/node/3289
You have two strategies to deal with your problem:
If you have a limited number of fields you require to change, use an approach such as the one suggested by #Ron, which is having a copy method. If you want to do it without losing type information, I would go for generifying the base class
sealed abstract class Base[T](val param:String){
def copy(param:String):T
}
class Foo(param:String) extends Base[Foo](param){
def copy(param: String) = new Foo(param)
}
def getIt[T](a:Base[T]) : T = a.copy("hello")
scala> new Foo("Pippo")
res0: Foo = Foo#4ab8fba5
scala> getIt(res0)
res1: Foo = Foo#5b927504
scala> res1.param
res2: String = hello
If you really want to abstract over arity, a solution is to use a library developed by Miles Sabin called Shapeless. There is a question here which has been asked after a discussion : Are HLists nothing more than a convoluted way of writing tuples? but I tell you this is going to give you some headache
If the two case classes would diverge over time so that they have different fields, then the shared copy approach would cease to work.
It is better to define an abstract def withMyParam(newParam: X): Base. Even better, you can introduce an abstract type to retain the case class type upon return:
scala> trait T {
| type Sub <: T
| def myParam: String
| def withMyParam(newParam: String): Sub
| }
defined trait T
scala> case class Foo(myParam: String) extends T {
| type Sub = Foo
| override def withMyParam(newParam: String) = this.copy(myParam = newParam)
| }
defined class Foo
scala>
scala> case class Bar(myParam: String) extends T {
| type Sub = Bar
| override def withMyParam(newParam: String) = this.copy(myParam = newParam)
| }
defined class Bar
scala> Bar("hello").withMyParam("dolly")
res0: Bar = Bar(dolly)
TL;DR: I managed to declare the copy method on Base while still letting the compiler auto generate its implementations in the derived case classes. This involves a little trick (and actually I'd myself just redesign the type hierarchy) but at least it goes to show that you can indeed make it work without writing boiler plate code in any of the derived case classes.
First, and as already mentioned by ron and Edmondo1984, you'll get into troubles if your case classes have different fields.
I'll strictly stick to your example though, and assume that all your case classes have the same fields (looking at your github link, this seems to be the case of your actual code too).
Given that all your case classes have the same fields, the auto-generated copy methods will have the same signature which is a good start. It seems reasonable then to just add the common definition in Base, as you did:
abstract class Base{ def copy(myparam: String):Base }
The problem is now that scala won't generate the copy methods, because there is already one in the base class.
It turns out that there is another way to statically ensure that Base has the right copy method, and it is through structural typing and self-type annotation:
type Copyable = { def copy(myParam: String): Base }
sealed abstract class Base(val myParam: String) { this : Copyable => }
And unlike in our earlier attempt, this will not prevent scala to auto-generate the copy methods.
There is one last problem: the self-type annotation makes sure that sub-classes of Base have a copy method, but it does not make it publicly availabe on Base:
val foo: Base = Foo("hello")
foo.copy()
scala> error: value copy is not a member of Base
To work around this we can add an implicit conversion from Base to Copyable. A simple cast will do, as a Base is guaranteed to be a Copyable:
implicit def toCopyable( base: Base ): Base with Copyable = base.asInstanceOf[Base with Copyable]
Wrapping up, this gives us:
object Base {
type Copyable = { def copy(myParam: String): Base }
implicit def toCopyable( base: Base ): Base with Copyable = base.asInstanceOf[Base with Copyable]
}
sealed abstract class Base(val myParam: String) { this : Base. Copyable => }
case class Foo(override val myParam: String) extends Base( myParam )
case class Bar(override val myParam: String) extends Base( myParam )
def getIt( a:Base ) = a.copy(myParam="changed")
Bonus effect: if we try to define a case class with a different signature, we get a compile error:
case class Baz(override val myParam: String, truc: Int) extends Base( myParam )
scala> error: illegal inheritance; self-type Baz does not conform to Base's selftype Base with Base.Copyable
To finish, one warning: you should probably just revise your design to avoid having to resort to the above trick.
In your case, ron's suggestion to use a single case class with an additional etype field seems more than reasonable.
I think this is what extension methods are for. Take your pick of implementation strategies for the copy method itself.
I like here that the problem is solved in one place.
It's interesting to ask why there is no trait for caseness: it wouldn't say much about how to invoke copy, except that it can always be invoked without args, copy().
sealed trait Base { def p1: String }
case class Foo(val p1: String) extends Base
case class Bar(val p1: String, p2: String) extends Base
case class Rab(val p2: String, p1: String) extends Base
case class Baz(val p1: String)(val p3: String = p1.reverse) extends Base
object CopyCase extends App {
implicit class Copy(val b: Base) extends AnyVal {
def copy(p1: String): Base = b match {
case foo: Foo => foo.copy(p1 = p1)
case bar: Bar => bar.copy(p1 = p1)
case rab: Rab => rab.copy(p1 = p1)
case baz: Baz => baz.copy(p1 = p1)(p1.reverse)
}
//def copy(p1: String): Base = reflect invoke
//def copy(p1: String): Base = macro xcopy
}
val f = Foo("param1")
val g = f.copy(p1="param2") // normal
val h: Base = Bar("A", "B")
val j = h.copy("basic") // enhanced
println(List(f,g,h,j) mkString ", ")
val bs = List(Foo("param1"), Bar("A","B"), Rab("A","B"), Baz("param3")())
val vs = bs map (b => b copy (p1 = b.p1 * 2))
println(vs)
}
Just for fun, reflective copy:
// finger exercise in the api
def copy(p1: String): Base = {
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.runtime.universe._
val im = cm.reflect(b)
val ts = im.symbol.typeSignature
val copySym = ts.member(newTermName("copy")).asMethod
def element(p: Symbol): Any = (im reflectMethod ts.member(p.name).asMethod)()
val args = for (ps <- copySym.params; p <- ps) yield {
if (p.name.toString == "p1") p1 else element(p)
}
(im reflectMethod copySym)(args: _*).asInstanceOf[Base]
}
This works fine for me:
sealed abstract class Base { def copy(myparam: String): Base }
case class Foo(myparam:String) extends Base {
override def copy(x: String = myparam) = Foo(x)
}
def copyBase(x: Base) = x.copy("changed")
copyBase(Foo("abc")) //Foo(changed)
There is a very comprehensive explanation of how to do this using shapeless at http://www.cakesolutions.net/teamblogs/copying-sealed-trait-instances-a-journey-through-generic-programming-and-shapeless ; in case the link breaks, the approach uses the copySyntax utilities from shapeless, which should be sufficient to find more details.
Its an old problem, with an old solution,
https://code.google.com/p/scala-scales/wiki/VirtualConstructorPreSIP
made before the case class copy method existed.
So in reference to this problem each case class MUST be a leaf node anyway, so define the copy and a MyType / thisType plus the newThis function and you are set, each case class fixes the type. If you want to widen the tree/newThis function and use default parameters you'll have to change the name.
as an aside - I've been waiting for compiler plugin magic to improve before implementing this but type macros may be the magic juice. Search in the lists for Kevin's AutoProxy for a more detailed explanation of why my code never went anywhere
Related
Assume the following pair of classes:
class A(arg:String)
class B(argList:Vector[String]) extends A(argList.first)
I want to be able to check for argList being empty before providing the base class constructor with its first element. Unfortunately, placing that check in the default constructor for B (e.g through require, as shown here) is way too late, since the base class' constructor will need to be called first.
This is probably a more general OOP question, but the solution is likely to be Scala-specific.
What do you expect to pass if argList is empty? In any case, you could just use the following:
class B(argList:Vector[String]) extends A(argList.headOption.getOrElse("your default string here")
One way to deal with this is via a companion object. You can mark the constructor for B as private to ensure no-one can by-pass the check, then add a suitable apply method to the companion object that pre-checks the input value(s):
class A(arg:String)
class B private(argList:Vector[String]) extends A(argList.head)
object B {
def apply(argList:Vector[String]): B = argList.headOption.map(_ => new B(argList)).getOrElse(throw new RuntimeException("Oops"))
}
Usage examples:
scala> B(Vector("foo", "bar"))
res2: B = B#328e9109
scala> B(Vector())
java.lang.RuntimeException: Oops
at B$$anonfun$apply$2.apply(<console>:24)
...
Note that for simplicity's sake, I simply throw an exception when handling bad data, but would probably try some other way of handling this situation (a default value per #Zoltan's answer is one such way).
That's why in most places constructors are replaced by factory objects. In Scala it's idiomatic to use companion object as such factories.
class A(arg: String)
abstract class B(arg: String) extends A(arg) {
def argList: IndexedSeq[String]
}
object B {
case object Empty extends B("") {
def argList = IndexedSeq.empty
}
case class NonEmpty private[B](argList: Vector[String]) extends B(argList.head)
def apply(argList: Vector[String]) =
if (argList.isEmpty) Empty else NonEmpty(argList)
def unapplySeq(b:B): Option[IndexedSeq[String]] = b match {
case Empty ⇒ Some(IndexedSeq.empty)
case NonEmpty(args) ⇒ Some(args)
}
}
you could verify that
B(Vector()) == B.Empty
B(Vector("x", "y")).isInstanceOf[B.NonEmpty]
For a project of mine I have implemented a Enum based upon
trait Enum[A] {
trait Value { self: A =>
_values :+= this
}
private var _values = List.empty[A]
def values = _values
}
sealed trait Currency extends Currency.Value
object Currency extends Enum[Currency] {
case object EUR extends Currency
case object GBP extends Currency
}
from Case objects vs Enumerations in Scala. I worked quite nice, till I run into the following problem. Case objects seem to be lazy and if I use Currency.value I might actually get an empty List. It would have been possible to make a call against all Enum Values on startup so that the value list would be populated, but that would be kind of defeating the point.
So I ventured into the dark and unknown places of scala reflection and came up with this solution, based upon the following SO answers. Can I get a compile-time list of all of the case objects which derive from a sealed parent in Scala?
and How can I get the actual object referred to by Scala 2.10 reflection?
import scala.reflect.runtime.universe._
abstract class Enum[A: TypeTag] {
trait Value
private def sealedDescendants: Option[Set[Symbol]] = {
val symbol = typeOf[A].typeSymbol
val internal = symbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol]
if (internal.isSealed)
Some(internal.sealedDescendants.map(_.asInstanceOf[Symbol]) - symbol)
else None
}
def values = (sealedDescendants getOrElse Set.empty).map(
symbol => symbol.owner.typeSignature.member(symbol.name.toTermName)).map(
module => reflect.runtime.currentMirror.reflectModule(module.asModule).instance).map(
obj => obj.asInstanceOf[A]
)
}
The amazing part of this is that it actually works, but it is ugly as hell and I would be interested if it would be possible to make this simpler and more elegant and to get rid of the asInstanceOf calls.
Here is a simple macro based implementation:
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
abstract class Enum[E] {
def values: Seq[E] = macro Enum.caseObjectsSeqImpl[E]
}
object Enum {
def caseObjectsSeqImpl[A: c.WeakTypeTag](c: blackbox.Context) = {
import c.universe._
val typeSymbol = weakTypeOf[A].typeSymbol.asClass
require(typeSymbol.isSealed)
val subclasses = typeSymbol.knownDirectSubclasses
.filter(_.asClass.isCaseClass)
.map(s => Ident(s.companion))
.toList
val seqTSymbol = weakTypeOf[Seq[A]].typeSymbol.companion
c.Expr(Apply(Ident(seqTSymbol), subclasses))
}
}
With this you could then write:
sealed trait Currency
object Currency extends Enum[Currency] {
case object USD extends Currency
case object EUR extends Currency
}
so then
Currency.values == Seq(Currency.USD, Currency.EUR)
Since it's a macro, the Seq(Currency.USD, Currency.EUR) is generated at compile time, rather than runtime. Note, though, that since it's a macro, the definition of the class Enum must be in a separate project from where it is used (i.e. the concrete subclasses of Enum like Currency). This is a relatively simple implementation; you could do more complicated things like traverse multilevel class hierarchies to find more case objects at the cost of greater complexity, but hopefully this will get you started.
A late answer, but anyways...
As wallnuss said, knownDirectSubclasses is unreliable as of writing and has been for quite some time.
I created a small lib called Enumeratum (https://github.com/lloydmeta/enumeratum) that allows you to use case objects as enums in a similar way, but doesn't use knownDirectSubclasses and instead looks at the body that encloses the method call to find subclasses. It has proved to be reliable thus far.
The article "“You don’t need a macro” Except when you do" by Max Afonov
maxaf describes a nice way to use macro for defining enums.
The end-result of that implementation is visible in github.com/maxaf/numerato
Simply create a plain class, annotate it with #enum, and use the familiar val ... = Value declaration to define a few enum values.
The #enum annotation invokes a macro, which will:
Replace your Status class with a sealed Status class suitable for acting as a base type for enum values. Specifically, it'll grow a (val index: Int, val name: String) constructor. These parameters will be supplied by the macro, so you don't have to worry about it.
Generate a Status companion object, which will contain most of the pieces that now make Status an enumeration. This includes a values: List[Status], plus lookup methods.
Give the above Status enum, here's what the generated code looks like:
scala> #enum(debug = true) class Status {
| val Enabled, Disabled = Value
| }
{
sealed abstract class Status(val index: Int, val name: String)(implicit sealant: Status.Sealant);
object Status {
#scala.annotation.implicitNotFound(msg = "Enum types annotated with ".+("#enum can not be extended directly. To add another value to the enum, ").+("please adjust your `def ... = Value` declaration.")) sealed abstract protected class Sealant;
implicit protected object Sealant extends Sealant;
case object Enabled extends Status(0, "Enabled") with scala.Product with scala.Serializable;
case object Disabled extends Status(1, "Disabled") with scala.Product with scala.Serializable;
val values: List[Status] = List(Enabled, Disabled);
val fromIndex: _root_.scala.Function1[Int, Status] = Map(Enabled.index.->(Enabled), Disabled.index.->(Disabled));
val fromName: _root_.scala.Function1[String, Status] = Map(Enabled.name.->(Enabled), Disabled.name.->(Disabled));
def switch[A](pf: PartialFunction[Status, A]): _root_.scala.Function1[Status, A] = macro numerato.SwitchMacros.switch_impl[Status, A]
};
()
}
defined class Status
defined object Status
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.
I have an abstract base class with several optional parameters:
abstract case class Hypothesis(
requirement: Boolean = false,
onlyDays: Seq[Int] = Nil,
…
) extends Something {…}
Do i really need to explicitly repeat all parameters with the additional keywords override val on top‽
case class SomeHypothesis(
anotherArg: SomeType,
override val requirement: Boolean = false,
override val onlyDays: Seq[Int] = Nil,
…
) extends Hypothesis(
requirement,
onlyDays,
…
) {…}
Or is there a syntax like
case class SomeHypothesis(anotherArg: SomeType, **) extends Hypothesis(**) {…}
I don’t even need anotherArg, just a way to pass all keyword args to the super constructor.
I really like Scala’s idea about constructors, but if there isn’t a syntax for that one, I’ll be disappoint :(
You can just use a dummy name in the inherited class:
case class SomeHypothesis(anotherArg: SomeType, rq: Boolean = false, odays: Seq[Int] = Nil)
extends Hypothesis(rq, odays)
but you do have to repeat the default values. There is no need to override a val.
EDIT:
Note that your abstract class should not be a case class. Extending case classes is now deprecated. You should use an extractor for you abstract class instead:
abstract class SomeHypothesis(val request: Boolean)
object SomeHypothesis {
def unapply(o: Any): Option[Boolean] = o match {
case sh: SomeHypothesis => Some(sh.request)
case _ => None
}
}
In my mind the policy of default values doesn't belong in the base class but should go on the concrete classes. I'd instead do the following:
trait Hypothesis {
def requirement: Boolean
def onlyDays: Seq[Int]
/* other common attributes as necessary */
}
case class SomeHypothesis(anotherArg: SomeType,
requirement: Boolean = false,
onlyDays: Seq[Int] = Nil)
extends Hypothesis
The case class fields of SomeHypothesis will fulfill the requirements of the Hypothesis trait.
As others have said, you can still use an extractor for pattern matching on the common parts:
object Hypothesis {
def unapply(h: Hypothesis): (Boolean, Seq[Int]) = (h.requirement, h.onlyDays)
}
I've spend DAYS bashing my head on the desk trying to understand why named params were not going into an extended class.
I tried traits, copy() you name it - me and the compiler were always at odds and when things did compile the values never got passed.
So to be clear if you have class
class A(someInt:Int = 0, someString: String ="xyz", someOtherString: String = "zyx")
And you want to extend it:
class B extends A // does NOT compile
class B(someInt: Int, someString: String, someOtherString: String) extends A // compiles but does not work as expected
You would think that a call to B like so:
case object X = B(someInt=4, someString="Boo", someOtherString="Who")
Would in fact either NOT compile (sadly it does) or actually work (it does NOT)
Instead you need to create B as follows (yes this is a repeat of an above answer but it wasn't obvious at first when google led me here...)
class B(someInt: Int, someString: String, someOtherString: String) extends A(someInt, someString, someOtherString)
and now
case object X = B(someInt=4, someString="Boo", someOtherString="Who")
Both COMPILES and WORKS
I have not yet worked out all the combinations and permutations of what/when and where you can put default values in the class B constructor but I'm pretty sure that defaults can be specified in the definition of class B with "expected" results.
If Hypothesis is an abstract class, then I'd not have a constructor for it. I'd
set those parameters as abstract attributes of the abstract class.
But then, in this case you do need the override modifier.
So here's the situation. I want to define a case class like so:
case class A(val s: String)
and I want to define an object to ensure that when I create instances of the class, the value for 's' is always uppercase, like so:
object A {
def apply(s: String) = new A(s.toUpperCase)
}
However, this doesn't work since Scala is complaining that the apply(s: String) method is defined twice. I understand that the case class syntax will automatically define it for me, but isn't there another way I can achieve this? I'd like to stick with the case class since I want to use it for pattern matching.
The reason for the conflict is that the case class provides the exact same apply() method (same signature).
First of all I would like to suggest you use require:
case class A(s: String) {
require(! s.toCharArray.exists( _.isLower ), "Bad string: "+ s)
}
This will throw an Exception if the user tries to create an instance where s includes lower case chars. This is a good use of case classes, since what you put into the constructor also is what you get out when you use pattern matching (match).
If this is not what you want, then I would make the constructor private and force the users to only use the apply method:
class A private (val s: String) {
}
object A {
def apply(s: String): A = new A(s.toUpperCase)
}
As you see, A is no longer a case class. I am not sure if case classes with immutable fields are meant for modification of the incoming values, since the name "case class" implies it should be possible to extract the (unmodified) constructor arguments using match.
UPDATE 2016/02/25:
While the answer I wrote below remains sufficient, it's worth also referencing another related answer to this regarding the case class's companion object. Namely, how does one exactly reproduce the compiler generated implicit companion object which occurs when one only defines the case class itself. For me, it turned out to be counter intuitive.
Summary:
You can alter the value of a case class parameter before it is stored in the case class pretty simply while it still remaining a valid(ated) ADT (Abstract Data Type). While the solution was relatively simple, discovering the details was quite a bit more challenging.
Details:
If you want to ensure only valid instances of your case class can ever be instantiated which is an essential assumption behind an ADT (Abstract Data Type), there are a number of things you must do.
For example, a compiler generated copy method is provided by default on a case class. So, even if you were very careful to ensure only instances were created via the explicit companion object's apply method which guaranteed they could only ever contain upper case values, the following code would produce a case class instance with a lower case value:
val a1 = A("Hi There") //contains "HI THERE"
val a2 = a1.copy(s = "gotcha") //contains "gotcha"
Additionally, case classes implement java.io.Serializable. This means that your careful strategy to only have upper case instances can be subverted with a simple text editor and deserialization.
So, for all the various ways your case class can be used (benevolently and/or malevolently), here are the actions you must take:
For your explicit companion object:
Create it using exactly the same name as your case class
This has access to the case class's private parts
Create an apply method with exactly the same signature as the primary constructor for your case class
This will successfully compile once step 2.1 is completed
Provide an implementation obtaining an instance of the case class using the new operator and providing an empty implementation {}
This will now instantiate the case class strictly on your terms
The empty implementation {} must be provided because the case class is declared abstract (see step 2.1)
For your case class:
Declare it abstract
Prevents the Scala compiler from generating an apply method in the companion object which is what was causing the "method is defined twice..." compilation error (step 1.2 above)
Mark the primary constructor as private[A]
The primary constructor is now only available to the case class itself and to its companion object (the one we defined above in step 1.1)
Create a readResolve method
Provide an implementation using the apply method (step 1.2 above)
Create a copy method
Define it to have exactly the same signature as the case class's primary constructor
For each parameter, add a default value using the same parameter name (ex: s: String = s)
Provide an implementation using the apply method (step 1.2 below)
Here's your code modified with the above actions:
object A {
def apply(s: String, i: Int): A =
new A(s.toUpperCase, i) {} //abstract class implementation intentionally empty
}
abstract case class A private[A] (s: String, i: Int) {
private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
A.apply(s, i)
def copy(s: String = s, i: Int = i): A =
A.apply(s, i)
}
And here's your code after implementing the require (suggested in the #ollekullberg answer) and also identifying the ideal place to put any sort of caching:
object A {
def apply(s: String, i: Int): A = {
require(s.forall(_.isUpper), s"Bad String: $s")
//TODO: Insert normal instance caching mechanism here
new A(s, i) {} //abstract class implementation intentionally empty
}
}
abstract case class A private[A] (s: String, i: Int) {
private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
A.apply(s, i)
def copy(s: String = s, i: Int = i): A =
A.apply(s, i)
}
And this version is more secure/robust if this code will be used via Java interop (hides the case class as an implementation and creates a final class which prevents derivations):
object A {
private[A] abstract case class AImpl private[A] (s: String, i: Int)
def apply(s: String, i: Int): A = {
require(s.forall(_.isUpper), s"Bad String: $s")
//TODO: Insert normal instance caching mechanism here
new A(s, i)
}
}
final class A private[A] (s: String, i: Int) extends A.AImpl(s, i) {
private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
A.apply(s, i)
def copy(s: String = s, i: Int = i): A =
A.apply(s, i)
}
While this directly answers your question, there are even more ways to expand this pathway around case classes beyond instance caching. For my own project needs, I have created an even more expansive solution which I have documented on CodeReview (a StackOverflow sister site). If you end up looking it over, using or leveraging my solution, please consider leaving me feedback, suggestions or questions and within reason, I will do my best to respond within a day.
I don't know how to override the apply method in the companion object (if that is even possible) but you could also use a special type for upper case strings:
class UpperCaseString(s: String) extends Proxy {
val self: String = s.toUpperCase
}
implicit def stringToUpperCaseString(s: String) = new UpperCaseString(s)
implicit def upperCaseStringToString(s: UpperCaseString) = s.self
case class A(val s: UpperCaseString)
println(A("hello"))
The above code outputs:
A(HELLO)
You should also have a look at this question and it's answers: Scala: is it possible to override default case class constructor?
For the people reading this after April 2017: As of Scala 2.12.2+, Scala allows overriding apply and unapply by default. You can get this behavior by giving -Xsource:2.12 option to the compiler on Scala 2.11.11+ as well.
It works with var variables:
case class A(var s: String) {
// Conversion
s = s.toUpperCase
}
This practice is apparently encouraged in case classes instead of defining another constructor. See here.. When copying an object, you also keep the same modifications.
Another idea while keeping case class and having no implicit defs or another constructor is to make the signature of apply slightly different but from a user perspective the same.
Somewhere I have seen the implicit trick, but can´t remember/find which implicit argument it was, so I chose Boolean here. If someone can help me out and finish the trick...
object A {
def apply(s: String)(implicit ev: Boolean) = new A(s.toLowerCase)
}
case class A(s: String)
I faced the same problem and this solution is ok for me:
sealed trait A {
def s:String
}
object A {
private case class AImpl(s:String)
def apply(s:String):A = AImpl(s.toUpperCase)
}
And, if any method is needed, just define it in the trait and override it in the case class.
If you're stuck with older scala where you cant override by default or you dont want to add the compiler flag as #mehmet-emre showed, and you require a case class, you can do the following:
case class A(private val _s: String) {
val s = _s.toUpperCase
}
As of 2020 on Scala 2.13, the above scenario of overriding a case class apply method with same signature works totally fine.
case class A(val s: String)
object A {
def apply(s: String) = new A(s.toUpperCase)
}
the above snippet compiles and runs just fine in Scala 2.13 both in REPL & non-REPL modes.
I think this works exactly how you want it to already. Here's my REPL session:
scala> case class A(val s: String)
defined class A
scala> object A {
| def apply(s: String) = new A(s.toUpperCase)
| }
defined module A
scala> A("hello")
res0: A = A(HELLO)
This is using Scala 2.8.1.final