Swap constructor arguments - scala

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

Related

Scala - not a case class nor does it have method .unapply

I am quite new to Scala and got a few unresolved problems with the following code:
object exprs{
println("Welcome to the Scala worksheet")
def show(e: Expr): String = e match {
case Number(x) => x.toString
case Sum(l, r) => show(l) + " + " + show(r)
}
show(Sum(Number(1), Number(44)))
}
trait Expr {
def isNumber: Boolean
def isSum: Boolean
def numValue: Int
def leftOp: Expr
def rightOp: Expr
def eval: Int = this match {
case Number(n) => n
case Sum(e1, e2) => e1.eval + e2.eval
}
}
class Number(n: Int) extends Expr {
override def isNumber: Boolean = true
override def isSum: Boolean = false
override def numValue: Int = n
override def leftOp: Expr = throw new Error("Number.leftOp")
override def rightOp: Expr = throw new Error("Number.rightOp")
}
class Sum(e1: Expr, e2: Expr) extends Expr {
override def isNumber: Boolean = false
override def isSum: Boolean = true
override def numValue: Int = e1.eval + e2.eval
override def leftOp: Expr = e1
override def rightOp: Expr = e2
}
I get the following errors:
Error: object Number is not a case class, nor does it have an unapply/unapplySeq member
Error: not found: value Sum
How to resolve them? Thanks in advance
In Scala case class are like class with extra goodies + some other properties.
For a normal class,
class A(i: Int, s: String)
You can not create its instance like this,
val a = A(5, "five") // this will not work
You will have to use new to create new instance.
val a = new A(5, "five")
Now lets say we have case class,
case class B(i: Int, s: String)
We can create a new instance of B like this,
val b = B(5, "five")
The reason this works with case class is because case class have an auto-created companion objects with them, which provides several utilities including an apply and unapply method.
So, this usage val b = B(5, "five") is actually val b = B.apply(5, "five"). And here B is not the class B but the companion object B which is actually provieds apply method.
Similarly Scala pattern matching uses the unapply (unapplySeq for SeqLike patterns) methods provided by companion object. And hence normal class instances do not work with pattern matching.
Lets say you wanted to defined a class and not a case class for some specific reason but still want to use them with pattern-matching etc, you can provide its companion object with the required methods by yourselves.
class C(val i: Int, val s: String) {
}
object C {
def apply(i: Int, s: String) = new C(i, s)
def unapply(c: C) = Some((c.i, c.s))
}
// now you can use any of the following to create instances,
val c1 = new C(5, "five")
val c2 = C.apply(5, "five")
val c3 = C(5, "five")
// you can also use pattern matching,
c1 match {
case C(i, s) => println(s"C with i = $i and s = $s")
}
c2 match {
case C(i, s) => println(s"C with i = $i and s = $s")
}
Also, as you are new to learning Scala you should read http://danielwestheide.com/scala/neophytes.html which is probably the best resource for any Scala beginner.

Scala Either : simplest way to get a property that exists on right and left

I have a template using a valueObject that might be one of two flavours depending on where it is used in our app. So I am importing it as an Either:
valueObject: Either[ ObjectA, ObjectB ]
Both objects have an identically named property on them so I would like to retrieve it just by calling
valueObject.propertyA
Which doesn't work.
What is the most concise/ best way of doing this?
Assuming the two objects have the same type (or a supertype / trait) that defines that property - you can use merge which returns left if it exists and right otherwise, with the lowest common type of both:
scala> class MyClass {
| def propertyA = 1
| }
defined class MyClass
scala> val e1: Either[MyClass, MyClass] = Left(new MyClass)
e1: Either[MyClass,MyClass] = Left(MyClass#1e51abf)
scala> val e2: Either[MyClass, MyClass] = Right(new MyClass)
e2: Either[MyClass,MyClass] = Right(MyClass#b4c6d0)
scala> e1.merge.propertyA
res0: Int = 1
scala> e2.merge.propertyA
res1: Int = 1
Using fold
Assuming the two objects do not share a common supertype that holds the property/method, then you have to resort to fold:
scala> case class A(a: Int)
defined class A
scala> case class B(a: Int)
defined class B
scala> def foldAB(eab: Either[A,B]): Int = eab.fold(_.a,_.a)
foldAB: (eab: Either[A,B])Int
scala> foldAB(Left(A(1)))
res1: Int = 1
scala> foldAB(Right(B(1)))
res2: Int = 1
Pattern matching
Another possibility is to use pattern matching:
scala> def matchAB(eab: Either[A,B]): Int = eab match { case Left(A(i)) => i; case Right(B(i)) => i}
matchAB: (eab: Either[A,B])Int
scala> matchAB(Left(A(1)))
res3: Int = 1
scala> matchAB(Right(B(1)))
res4: Int = 1

generic type-based function to sum numbers based on their types

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

Add a parameter to a case class with a default

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

Initialize class parameter with a function in Scala

Is it possible to initialize a class parameter with a function in Scala?
Example:
def square(x: Int) = x*x
class Foo(val x: Int = square(x))
This doesn't compile but I hope you get the idea.
Hard to guess what you're trying to achieve, but let me have a go:
class Foo private (val x: Int)
object Foo {
def apply(x: Int) = new Foo(square(x))
}
Note that if you try this in the REPL, you must enter both the class and its companion object at the same time (in paste mode, via :pa), or the object Foo won't have access to the private class constructor.
This applies the square function to the parameter x before creating a Foo instance:
scala> Foo(3).x
res1: Int = 9
This is not possible because you try to calculate x based on x (without having any kind of base case). You could do the following:
class Foo(_x: Int) {
val x = square(_x)
}
println(new Foo(10).x) // 100
EDIT
You could also generalise this and implicitly pass a function to the class constructor that transforms x:
implicit val square = (x: Int) => x*x
class Foo(private val _x: Int)(implicit f: Int => Int) {
val x = f(_x)
}
println(new Foo(10).x) // 100
This unfortunately doesn't compile as-is (Scala 2.9.2, 2.10.0), because there is another implicit in scope (Predef.conforms). I don't know how to overcome this ambiguity, but it should certainly be possible.
Here it is.. you can initialize a class with a function ! :)
class Foo(f : Int => Int)
def square(x : Int) = x*x
val foo = new Foo(square)
Or Probably you must be looking for this.
class Foo(f : Int => Int, _p1 : Int){
val p1 = f(_p1)
}
def square(x : Int) = x*x //> square: (x: Int)Int
def add2(x : Int) = x+2 //> add2: (x: Int)Int
val fooSqr = new Foo(square,5)
fooSqr.p1 //> res0: Int = 25
val fooAdd2 = new Foo(add2,5)
fooAdd2.p1 //> res1: Int = 7
In general you can use arbitrary expressions when defining the default value (source).
Your problem is that you can not use x on the right hand side of the initialization, because x is probably neither declared nor initialized at that point.