I have an existing case class, to which I'd like to add an additional constructor parameter, with a default value, and not disturb existing code that does pattern matching, yet I can't figure out the right approach.
Ie. I have:
case class Foo(a: Int, b: Int)
def bar(n: Foo) = n match {
case Foo(1, 2) => true
case _ => false
}
Now suppose I need to add an additional parameter, c, to Foo. Ie.
case class Foo(a: Int, b: Int, c: Boolean = true)
In all existing use cases, the parameter c would be true, hence it has that default value. Yet in some new use cases, there is a need to pass false for this.
So it seems sensible to add another parameter, with a default value of true. Yet as soon as I do this, the pattern match in bar becomes a syntax error. This seems wrong, since I added the default = true to ensure that existing constructor calls wouldn't need to be modified.
How can I do this and leave the old pattern matches unchanged?
Update: Note that I also don't want to have to rewrite all the existing instantiations of Foo. #som-snytt pointed out that I could add another parameter as Foo(a: Int, b: Int)(c: Boolean = true), which would be perfect except that it causes existing calls, such as Foo(1,2) to fail (they have to be rewritten as Foo(1,2)()). I'm looking for a way to add a new parameter only for some use-cases, and avoid rewriting by having a default which works for everywhere else.
The case Foo syntax is not calling a constructor, rather a method called unapply on object Foo. case classes autogenerate various boilerplate including the companion object and the unapply.
unapply only has one parameter, the object being matched. This keeps you from overloading it since you can't overload on return value in Java/Scala.
So in short you can't do quite what you want.
You can, however, make an extractor with a different name. Here's someone who just added an underscore:
http://x3ro.de/multiple-unapply-methods-for-pattern-matching-in-scala/
perhaps it would be nicer when possible to use a more meaningful name for the extractor variants though.
Here's some more info on how it all works:
http://danielwestheide.com/blog/2012/11/21/the-neophytes-guide-to-scala-part-1-extractors.html
You can write out everything a case class does "by hand" and do it differently, such as a different unapply, but it would be pretty annoying assuming you care about equals, hashCode, toString, and all that. If you did that you could maybe avoid having to change existing code but it seems unlikely to be worth it.
Here is an example someone posted:
https://gist.github.com/okapies/2814608
Maybe you can live with case class Foo(a: Int, b: Int)(val c: Boolean = true).
Update: if you could almost live with that, because you don't want to use the extra param in patterns, then you can make short work of it.
package fooplusplus
case class Foo(a: Int, b: Int) {
def c: Boolean = true
}
object Foo {
def apply(a: Int, b: Int, c: Boolean): Foo =
new {
private[this] val x = c // http://stackoverflow.com/a/12239654
} with Foo(a, b) {
override def c = x
}
}
object Test extends App {
def bar(x: Foo) = x match {
case Foo(1, 2) if !x.c => 3
case Foo(1, 2) => 2 // existing code
case _ => 1
}
Console println bar(Foo(1, 2))
Console println bar(Foo(1, 2, c = false))
Console println bar(Foo(0, 2))
}
If you do want pattern matching with the new param, here is one way:
case class EnhancedFoo(a: Int, b: Int, c: Boolean)
class Foo(a: Int, b: Int, c: Boolean) extends EnhancedFoo(a, b, c)
object Foo {
def apply(a: Int, b: Int, c: Boolean = true): Foo = new Foo(a, b, c)
def unapply(x: Foo): Option[(Int, Int)] = Some(x.a, x.b)
}
object Test extends App {
def bar(x: EnhancedFoo) = x match {
case EnhancedFoo(1, 2, true) => 3
case Foo(1, 2) => 2 // existing code
case _ => 1
}
Console println bar(Foo(1, 2))
Console println bar(Foo(1, 2, c = false))
Console println bar(Foo(0, 2))
}
Since we haven't done anything truly whacky yet, how about the following:
scala> case class Foo(a: Int, b: Int, c: Boolean*)
defined class Foo
scala> import PartialFunction._
import PartialFunction._
scala> val foo = Foo(1,2)
f: Foo = Foo(1,2,WrappedArray())
scala> val goo = Foo(1,2,true)
g: Foo = Foo(1,2,WrappedArray(true))
scala> cond(foo) { case Foo(1,2) => true }
res0: Boolean = true
scala> cond(goo) { case Foo(1,2,false) => true }
res1: Boolean = false
The boolean becomes tri-state, defaulting to old-style empty.
scala> cond(foo) { case Foo(1,2, _ # _*) => true }
res2: Boolean = true
scala> cond(foo) { case Foo(1,2, x) => true }
res3: Boolean = false
scala> cond(goo) { case Foo(1,2, x # _*) if x exists identity => true }
res4: Boolean = true
Related
Suppose x and y are of the same type and can be either Boolean, Int, or Double. Here is the function I want to write:
f(x, y) =
- if x == Boolean ==> !x
- if x == Integer or x == Double ==> x+ y
One way of doing this can be the following. I was wondering if anyone has a better ideas on this.
def fun[T](x: T, y: T): T {
x match {
case xP: Boolean => !xP
case xP: Double => y match { case yP: Double => xP + yP }
case xP: Int => y match { case yP: Int => xP + yP }
}
}
The reason I am not happy with this is that x and y have the same type. I shouldn't need two match-cases; right?
Two other things:
Is it enough to just set [T <: Int, Double, Boolean] in order to restrict the type to only three types?
The output type needs to be again T.
This is precisely the kind of problem that type classes are designed to solve. In your case you could write something like this:
trait Add[A] {
def apply(a: A, b: A): A
}
object Add {
implicit val booleanAdd: Add[Boolean] = new Add[Boolean] {
def apply(a: Boolean, b: Boolean): Boolean = !a
}
implicit def numericAdd[A: Numeric]: Add[A] = new Add[A] {
def apply(a: A, b: A): A = implicitly[Numeric[A]].plus(a, b)
}
}
A value of type Add[X] describes how to add two values of type X. You put implicit "instances" of type Add[X] in scope for every type X that you want to be able to perform this operation on. In this case I've provided instances for Boolean and any type that has an instance of scala.math.Numeric (a type class that's provided by the standard library). If you only wanted instances for Int and Double, you could simply leave out numericAdd and write your own Add[Int] and Add[Double] instances.
You'd write your fun like this:
def fun[T: Add](x: T, y: T) = implicitly[Add[T]].apply(x, y)
And use it like this:
scala> fun(true, false)
res0: Boolean = false
scala> fun(1, 2)
res1: Int = 3
scala> fun(0.01, 1.01)
res2: Double = 1.02
This has the very significant advantage of not blowing up at runtime on types that you haven't defined the operation for. Instead of crashing your program with a MatchError exception when you pass e.g. two strings to fun, you get a nice compilation failure:
scala> fun("a", "b")
<console>:14: error: could not find implicit value for evidence parameter of type Add[String]
fun("a", "b")
^
In general "type case" matching (i.e. matches that look like case x: X => ...) are a bad idea in Scala, and there's almost always a better solution. Often it'll involve type classes.
If you want a generic function for summing numbers, you can make a trait Summable[A] with implicit conversions from the numbers you want to Summable. These conversions can be implicit methods or they can be methods in implicit objects, latter being shown below.
trait Summable[A] {
def +(a: A, b: A): A
}
object Summable {
implicit object SummableBoolean extends Summable[Boolean] {
override def +(a: Boolean, b: Boolean) = !a
}
implicit object SummableInt extends Summable[Int] {
override def +(a: Int, b: Int) = a + b
}
implicit object SummableDouble extends Summable[Double] {
override def +(a: Double, b: Double) = a + b
}
}
def fun[A](a: A, b: A)(implicit ev: Summable[A]) =
ev.+(a, b)
val res1 = fun(true, true) // returns false
val res2 = fun(1, 3) // returns 4
val res3 = fun(1.5, 4.3) // returns "5.8"
This is called a type class pattern. I included the boolean case because you asked for it, but I strongly believe that it has no place in a function which sums elements. One nice rule to follow is to have each function do one thing and one thing only. Then you can easily compose them into bigger functions. Inverting boolean has no place in a function that sums its arguments.
First of all, your example is syntactically wrong (missing case in match). A simple and shorter way I can figure now is something like this:
def fun[T <: AnyVal](x: T, y: T) = {
x match {
case xP: Boolean => !xP
case xP: Double => xP + y.asInstanceOf[Double]
case xP: Int => xP + y.asInstanceOf[Int]
}
}
fun(1, 2) // res0: AnyVal = 3
fun(2.5, 2.6) // res1: AnyVal = 5.1
fun(true, false) // res2: AnyVal = false
I have a generic map with values, some of which can be in turn lists of values.
I'm trying to process a given key and convert the results to the type expected by an outside caller, like this:
// A map with some values being other collections.
val map: Map[String, Any] = Map("foo" -> 1, "bar" -> Seq('a', 'b'. 'a'))
// A generic method with a "specialization" for collections (pseudocode)
def cast[T](key: String) = map.get(key).map(_.asInstanceOf[T])
def cast[C <: Iterable[T]](key: String) = map.get(key).map(list => list.to[C].map(_.asIntanceOf[T]))
// Expected usage
cast[Int]("foo") // Should return 1:Int
cast[Set[Char]]("bar") // Should return Set[Char]('a', 'b')
This is to show what I would like to do, but it does not work. The compiler error complains (correctly, about 2 possible matches). I've also tried to make this a single function with some sort of pattern match on the type to no avail.
I've been reading on #specialized, TypeTag, CanBuildFrom and other scala functionality, but I failed to find a simple way to put it all together. Separate examples I've found address different pieces and some ugly workarounds, but nothing that would simply allow an external user to call cast and get an exception is the cast was invalid. Some stuff is also old, I'm using Scala 2.10.5.
This appears to work but it has a some problems.
def cast[T](m: Map[String, Any], k: String):T = m(k) match {
case x: T => x
}
With the right input you get the correct output.
scala> cast[Int](map,"foo")
res18: Int = 1
scala> cast[Set[Char]](map,"bar")
res19: Set[Char] = Set(a, b)
But it throws if the type is wrong for the key or if the map has no such key (of course).
You can do this via implicit parameters:
val map: Map[String, Any] = Map("foo" -> 1, "bar" -> Set('a', 'b'))
abstract class Casts[B] {def cast(a: Any): B}
implicit val doubleCast = new Casts[Double] {
override def cast(a: Any): Double = a match {
case x: Int => x.toDouble
}
}
implicit val intCast = new Casts[Int] {
override def cast(a: Any): Int = a match {
case x: Int => x
case x: Double => x.toInt
}
}
implicit val seqCharCast = new Casts[Seq[Char]] {
override def cast(a: Any): Seq[Char] = a match {
case x: Set[Char] => x.toSeq
case x: Seq[Char] => x
}
}
def cast[T](key: String)(implicit p:Casts[T]) = p.cast(map(key))
println(cast[Double]("foo")) // <- 1.0
println(cast[Int]("foo")) // <- 1
println(cast[Seq[Char]]("bar")) // <- ArrayBuffer(a, b) which is Seq(a, b)
But you still need to iterate over all type-to-type options, which is reasonable as Set('a', 'b').asInstanceOf[Seq[Char]] throws, and you cannot use a universal cast, so you need to handle such cases differently.
Still it sounds like an overkill, and you may need to review your approach from global perspective
I have a case class Foo which has a field baz: Option[List[Bar]].
Also, I have a function - def f(baz: List[Bar])
I need to pass the List[Bar] to f().
What would be the best way to do this?
Option is great because it forces you to come to grips when there is no item. In the case of a List, Option may be overkill as there already exists a corresponding empty, i.e. they are both Monads:
f(myOptList getOrElse Nil)
wherein I'd say you should probably only have a List ever. Otherwise you deal with a trinary case: Something that is empty, something that has items and empty.
case class Baz(b: Int)
case class Foo(bazs: Option[List[Baz]])
val foo = Foo(Option(List(Baz(1), Baz(2))))
foo.bazs.map(list => f(list))
Option is a monad, if it's a Some the map will we applied to it, else if it's a None nothing will happen, from the REPL:
scala> def f(b: List[Baz]) = b.foreach(println)
f: (b: List[Baz])Unit
scala> foo.bazs.map(list => f(list))
Baz(1)
Baz(2)
res1: Option[Unit] = Some(())
scala> val foo = Foo(None)
foo: Foo = Foo(None)
scala> foo.bazs.map(list => f(list))
res2: Option[Unit] = None
Is it possible to swap the arguments of a constructor?
Consider the following example:
case class Foo(a:Int, b:Int) {
if (a > b) {
val tmp = a
a = b
b = tmp
}
}
The compiler throws an error because I reassign to val a at line 4 which is perfectly fine. However, I need immutable objects. Therefore, declaring a and b as variables is not an option.
Is there a known pattern how to solve this problem?
Make an inner swap method:
case class Foo(a: Int, b: Int) {
def ifSwap = if (a > b) Foo(b, a) else this
}
val f1 = Foo(1,2).ifSwap // the result is Foo(1,2)
val f2 = Foo(2,1).ifSwap // the result is Foo(1,2)
If you want to preserve immutability then to change state you need either return new instance on each modification, or use some hardcore ways like Lenses, State,
Records, etc... And as Prof. Odersky told on SD'13 talk, there are situations when you shouldn't be afraid of vars
I suppose what you want to achieve that every instance of Foo has ordered its pair of values, is that right?
One possibility is not to make the class case and instead define its construction and extraction yourself. The class won't inherit from product, no pretty default toString etc., but otherwise it's usable just as a case class:
class Foo private (val a: Int, val b: Int);
object Foo {
def apply(a: Int, b: Int): Foo =
if (a < b)
new Foo(a, b)
else
new Foo(b, a)
def unapply(f: Foo): Option[(Int,Int)] = Some((f.a, f.b))
}
// test:
def printFoo(f: Foo) = f match {
case Foo(x, y) => println(x + ", " + y);
}
printFoo(Foo(1,2))
printFoo(Foo(3,2))
See also:
How to override apply in a case class companion
Scala: is it possible to override default case class constructor?
Overload constructor for Scala's Case Classes?
It appears you can make the case class constructor private! Extending on #PetrPudlák answers, I make the constructor private and define a foo helper to create the case class objects:
case class Foo private (a: Int, b: Int)
object Foo {
def foo(x: Int, y: Int) = if (x > y) Foo(y, x) else Foo(x, y)
}
Then I just use foo to instantiate the well formed Foo objects and the rest of the case class functionality works as expected (equality, hashcode, unapply):
import Foo._
foo(1, 2) //> res0: worksheets.so.Foo = Foo(1,2)
foo(2, 1) //> res1: worksheets.so.Foo = Foo(1,2)
foo(3, 4) == foo(4, 3) //> res2: Boolean = true
// Foo(4, 2) does not compile
// extractor/pattern matching works:
val Foo(a, b) = foo(10,1) //> a : Int = 1
//| b : Int = 10
You could also name foo as something more meaningful like OrderedFoo or NormalFoo.
scala> :paste
// Entering paste mode (ctrl-D to finish)
object Foo {
def swapped(b: Int, a: Int) = Foo(a=a, b=b)
}
case class Foo(a: Int, b: Int)
// Exiting paste mode, now interpreting.
defined module Foo
defined class Foo
scala> Foo.swapped(1, 2) == Foo(2, 1)
res0: Boolean = true
It does not look very good for me to always repeat a line-long tuple definition every time I need it. Can I just name it and use as a type name? Would be nice to name its fields also instead of using ._1, ._2 etc.
Regarding your first question, you can simply use a type alias:
type KeyValue = (Int, String)
And, of course, Scala is an object-oriented language, so regarding your second about how to specialize a tuple, the magic word is inheritance:
case class KeyValue(key: Int, value: String) extends (Int, String)(key, value)
That's it. The class doesn't even need a body.
val kvp = KeyValue(42, "Hello")
kvp._1 // => res0: Int = 42
kvp.value // => res1: String = "Hello"
Note, however, that inheriting from case classes (which Tuple2 is), is deprecated and may be disallowed in the future. Here's the compiler warning you get for the above class definition:
warning: case class class KV has case class ancestor class Tuple2. This has been deprecated for unduly complicating both usage and implementation. You should instead use extractors for pattern matching on non-leaf nodes.
Type alias is fine for naming your Tuple, but try using a case class instead. You will be able to use named parameters
Example with tuple:
def foo(a : Int) : (Int, String) = {
(a,"bar")
}
val res = foo(1)
val size = res._1
val name= res._2
With a case class:
case class Result( size : Int , name : String )
def foo(a : Int) : Result = {
Result(a,"bar")
}
val res = foo(1)
val size = res.size
val name= res.name
Here's a solution that creates a type alias and a factory object.
scala> type T = (Int, String)
defined type alias T
scala> object T { def apply(i: Int, s: String): T = (i, s) }
defined module T
scala> new T(1, "a")
res0: (Int, String) = (1,a)
scala> T(1, "a")
res1: (Int, String) = (1,a)
However as others have mentioned, you probably should just create a case class.
Although as others have said, explicit (case) classes are best in the general sense.
However for localized scenarios what you can do is to use the tuple extractor to improve code readability:
val (first, second) = incrementPair(3, 4)
println(s"$first ... $second")
Given a method returning a tuple:
def incrementPair(pair: (Int, Int)) : (Int, Int) = {
val (first, second) = pair
(first + 1, second + 1)
}