How can I specify multiple constructors in the case class? - scala

I'm trying to create a case class with multiple constructors:
object App {
def main(args: Array[String]) {
val a = Something("abc", 100500, _ % 2 == 0)
val b = Something(true, 10, 20)
println(s"$a - $b")
}
}
case class Something(s: String, n: Int, p: Int => Boolean) {
/*
Additional constructor -- Wrong way! -- it is imposible to invoke it outside the class
def this(b: Boolean, x: Int, y: Int) {
this("", 0, (i: Int) => i % x + y == 0)
}
*/
}
So far my code doesn't work:
Error:(10, 23) type mismatch;
found : Boolean(true)
required: String
val b = Something(true, 10, 20)
^
To fix it I need to create a companion object to hold an apply function which represents a new constructor for Something class:
object Something {
def apply(b: Boolean, x: Int, y: Int) = {
new Something(if (b) "" else "default", 0, _ => {
(x + y) % 2 == 0
})
}
}
It is inconvenient. Maybe there is some other way to place multiple constructors into the case class?

Actually it works, but you have to use new as auxiliary constructors do not have apply generated for case class:
case class Something(s: String, n: Int, p: Int => Boolean) {
def this(b: Boolean, x: Int, y: Int) {
this("", 0, (i: Int) => i % x + y == 0)
}
}
new Something(true, 5, 5) // Works
If you want Something(true, 5, 5) to work, you need to create companion object as you said. I think this is because otherwise case class won't be able to work with pattern matching as it is now, or it would have been much more complicated. And notice that pattern matching won't work in this case
Also remember that case class supports default constructors like case class Something(s: String = "default") this might help you, but it does not fix your example unfortunately

Related

Passing through Left statement in Either

Given these two methods that use Either, in the second method I need to forward the error using Left(error) => Left(error). Is there a way to omit this in the second method (or use more elegant code) as the statement just needs to be passed through?
trait Error
case class ErrorClass (msg: String) extends Error
def intFunction(i:Int) : Either[ErrorClass,Int] = {
if (i>0)
Right(i)
else
Left(ErrorClass("error"))
}
def multiplier(j:Int) : Either[ErrorClass,Int] = {
val either = intFunction(2)
either match {
case Right(i) => Right(i*j)
case Left(error) => Left(error)
}
}
Starting with scala 2.12, Either is right-biased, meaning you can .map() over it and the function will only be applied if it's a Right:
trait Error
case class ErrorClass(msg: String) extends Error
def intFunction(i: Int): Either[ErrorClass, Int] = {
if (i > 0)
Right(i)
else
Left(ErrorClass("error"))
}
def multiplier(i: Int, j: Int): Either[ErrorClass, Int] = {
val either = intFunction(i)
either.map(_ * j)
}
println(multiplier(10, 10)) // Right(100)
println(multiplier(-1, 10)) // Left(ErrorClass(error))
If you're using scala 2.11-, you need to be explicit and access the RightProjection before mapping over it, as the Either is not right-biased:
def multiplier(i: Int, j: Int): Either[ErrorClass, Int] = {
val either = intFunction(i)
either.right.map(_ * j)
}

ScalaMock Stubbing with default parameters

I'm trying to mock a function like
def foo(x: A, y: B, z: C = blah)
where blah is a java connection object that I don't want to create on the spot
However when I try to stub it like
(object.foo _)
.stubs(a, b)
It errors out and says overloaded method value stubs with alternatives...
because it's looking for the third parameter. Is there anyway to get around this.
I agree with Matt, but want to point out there is a wildcard syntax in ScalaMock (*) - http://scalamock.org/user-guide/matching/
trait Foo {
def foo(x: Int, y: Int, z: Int = 0): Int
}
val a: Int = ???
val b: Int = ???
val m = mock[Foo]
m.foo _ stubs(a, b, *)
You can use a wildcard when you're stubbing out your method.
The following test passes and I think is what you're looking for:
class DefaultParameterTest extends FlatSpec with Matchers with MockFactory {
class A {
def foo(x: Int, y: Int, z: Int = 0): Int = 0
}
it should "work with a default parameter" in {
val bar = mock[A]
(bar.foo _).stubs(1, 2, _: Int).returning(5)
bar.foo _ expects(1, 2, 0) returning 5 once()
bar.foo(1, 2)
}
}

Can a partially applied function be extracted or interrogated for the applied parameter value

Is there a way to extract or interrogate a partially applied function to get the applied value.
For example, can the value 3 be extracted from reduceBy3 in the code below.
def subtract(x:Int, y:Int) = x-y
val reduceBy3 = subtract(3,_:Int)
I have experimented with creating an extractor has shown in the example below however the unapply method must accept an (Int=>Int) function that requires interrogation.
class ReduceBy(y: Int) {
val amt = y
def subtract(y: Int, x: Int) = x - y
}
object ReduceBy extends Function1[Int, Int => Int] {
def apply(y: Int) = {
val r = new ReduceBy(y)
r.subtract(y, _: Int)
}
def unapply(reduceBy: ReduceBy): Option[Int] = Some(reduceBy.amt)
}
object ExtractPartialApplied extends App {
val r3 = ReduceBy(3)
val extract = r3 match {
case ReduceBy(x) => ("reduceBy", x)
case x: ReduceBy => ("reduceBy", x.amt)
case _ => ("No Match", 0)
}
println(extract)
val z = r3(5)
println(z)
}
You can have your subtract method receive the first parameter, and then return a function-like object which will then take the second parameter, similarly to a multiple-argument-list function, but which you can then extend however you wish.
This doesn't look very elegant though, and needs a bit of manual boilerplate.
class ReduceBy(val amt: Int) {
def subtract(x: Int) = {
val xx = x // avoid shadowing
new Function[Int, Int] {
def x = xx
def apply(y: Int) = x - y
}
}
}
A solution adapting the answer by danielkza is to have the companion object do the extraction and return a ReduceBy function that holds onto the the initial value.
object ReduceBy {
def apply(y: Int) = new ReduceBy(y)
def unapply(reduceBy: ReduceBy): Option[Int] = Some(reduceBy.amt)
}
class ReduceBy(val amt: Int) extends Function[Int, Int] {
def apply(y: Int) = y - amt
}
object ExtractPartialApplied extends App {
val reduceBy3 = ReduceBy(3)
val extract = reduceBy3 match {
case ReduceBy(x) => ("ReduceBy(x)", x)
case x: ReduceBy => ("ReduceBy", x.amt)
case _ => ("No Match", 0)
}
println(extract)
println(reduceBy3(5))
}

Swappable Trait in Scala

I want to define a Swappable trait with two values x,y and a swap method such that calling swap on an object inheriting from Swappable returns another object of the same type with x,y switched. My best so far is:
trait Swappable[T] {
val x: T
val y: T
def swap: Swappable[T] = {
val (a,b) = (x,y)
new Swappable[T] { val x=b; val y=a }
}
}
But this isn't what I want because the return type of swap is some anonymous class, instead of the original class I started with, so I get errors like:
def direct[S<:Swappable[Int]](s: S): S = if (s.x > s.y) s else s.swap
<console>:32: error: type mismatch;
found : Swappable[Int]
required: S
def direct[S<:Swappable[Int]](s: S): S = if (s.x > s.y) s else s.swap
^
Is it possible to do what I'm trying to do? What is the correct type signature for swap?
I don't know how to do it, but I think maybe it would help to get a better idea of what exactly you want to happen. Consider a class like
case class Foo(x: Int, y: Int) extends Swappable[Int] {
val z = x
}
Now, if you have f = Foo(1, 2), should f.swap give you a Foo where x != z? If so, there's no way within Scala to create a Foo like that. If not, what does it really mean to "swap x and y"?
Perhaps what you're really looking for is something like this:
trait Swappable[A,T] {
this: A =>
val x: T
val y: T
def cons(x: T, y: T): A
def swap = cons(y, x)
}
case class Foo(x: Int, y: Int) extends Swappable[Foo,Int] {
val z = x
def cons(x: Int, y: Int) = copy(x=x, y=y)
}
But I'm not sure.
What about something like that:
trait Swappable[T] {
type A
val x: T
val y: T
def create(a: T, b: T): A
def swap = create(y, x)
}
case MySwappable[T](x: T, y: T) extends Swappable[T] {
type A = MySwappable
def create(a: T, b: T) = MySwappable(a, b)
}

Scala constructor overload?

How do you provide overloaded constructors in Scala?
It's worth explicitly mentioning that Auxiliary Constructors in Scala must either call the primary constructor (as in landon9720's) answer, or another auxiliary constructor from the same class, as their first action. They cannot simply call the superclass's constructor explicitly or implicitly as they can in Java. This ensures that the primary constructor is the sole point of entry to the class.
class Foo(x: Int, y: Int, z: String) {
// default y parameter to 0
def this(x: Int, z: String) = this(x, 0, z)
// default x & y parameters to 0
// calls previous auxiliary constructor which calls the primary constructor
def this(z: String) = this(0, z);
}
class Foo(x: Int, y: Int) {
def this(x: Int) = this(x, 0) // default y parameter to 0
}
As of Scala 2.8.0 you can also have default values for contructor- and method parameters. Like this
scala> class Foo(x:Int, y:Int = 0, z:Int=0) {
| override def toString() = { "Foo(" + x + ", " + y + ", " + z + ")" }
| }
defined class Foo
scala> new Foo(1, 2, 3)
res0: Foo = Foo(1, 2, 3)
scala> new Foo(4)
res1: Foo = Foo(4, 0, 0)
Parameters with default values must come after the ones with no default values in the parameter list.
While looking at my code, I suddenly realized that I did kind of an overload a constructor. I then remembered that question and came back to give another answer:
In Scala, you can’t overload constructors, but you can do this with functions.
Also, many choose to make the apply function of a companion object a factory for the respective class.
Making this class abstract and overloading the apply function to implement-instantiate this class, you have your overloaded “constructor”:
abstract class Expectation[T] extends BooleanStatement {
val expected: Seq[T]
…
}
object Expectation {
def apply[T](expd: T ): Expectation[T] = new Expectation[T] {val expected = List(expd)}
def apply[T](expd: Seq[T]): Expectation[T] = new Expectation[T] {val expected = expd }
def main(args: Array[String]): Unit = {
val expectTrueness = Expectation(true)
…
}
}
Note that I explicitly define each apply to return Expectation[T], else it would return a duck-typed Expectation[T]{val expected: List[T]}.
Try this
class A(x: Int, y: Int) {
def this(x: Int) = this(x, x)
def this() = this(1)
override def toString() = "x=" + x + " y=" + y
class B(a: Int, b: Int, c: String) {
def this(str: String) = this(x, y, str)
override def toString() =
"x=" + x + " y=" + y + " a=" + a + " b=" + b + " c=" + c
}
}