I am trying to model a scenario where I'm trying to achieve immutability rather than modifying instance variables. The way I'm achieving this is as below.
case class TSS(k:Int, v:Int)
case class Combiner(a:Int,b:Int, tss: TSS) {
def func1():Option[TSS] = None
def func2():Option[TSS] = None
def modifyState(externalV: Int): Combiner = {
Combiner(this.a + 1, this.b+1, func1())
}
}
case class OneCombiner extends Combiner {
override def func1():Option[TSS] = SOME_MODIFIED_TSS
override def func2():Option[TSS] = SOME_MODIFIED_TSS
}
case class TwoCombiner extends Combiner {
override def func1():Option[TSS] = SOME_MODIFIED_TSS
override def func2():Option[TSS] = SOME_MODIFIED_TSS
}
Now when I'm trying to use the OneCombiner and TwoCombiner as below they are using the func1 and func2 of base class and setting the value of tss to None rather than using the overridden versions.
For example
val a:Combiner = OneCombiner
val anotherCombiner = a.modifyState()
In this case anotherCombiner.tss is being returned as None rather than SOME_TSS_VALUE.
What is the correct functional way of modelling such behaviour in Scala ?
I also tried making Combiner abstract case class but that failed to compile because then I was unable to create the Combiner object in modifyState method.
The problem is that modifyState is creating a new Combiner rather than the appropriate subclass. This is because it is combining state with abstract behaviour in one class.
The best solution is to make a separate concrete State class and have the Combiners as functions that take a State and return a new one. This separates the different behaviours from the actual state itself.
case class TSS(k: Int, v: Int)
case class State(a: Int, b: Int, tss: TSS)
trait Combiner {
def func1(): TSS
def modifyState(state: State, externalV: Int): State
= State(state.a + 1, state.b+1, func1())
}
case class OneCombiner() extends Combiner {
def func1(): TSS = ???
}
case class TwoCombiner() extends Combiner {
def func1(): TSS = ???
}
If you want to retain a single class you need to have a separate constructor for each subclass, and the easiest way to do that is to make modifyState virtual and implement it in each subclass. It is not clear how many of the other values need to be exposed in the trait so I have put them all in, just in case.
case class TSS(k: Int, v: Int)
trait Combiner {
def a: Int
def b: Int
def tss: TSS
def func1(): Option[TSS]
def func2(): Option[TSS]
def modifyState(externalV: Int): Combiner
}
case class OneCombiner(a: Int, b: Int, tss: TSS) extends Combiner {
override def func1(): Option[TSS] = ???
override def func2(): Option[TSS] = ???
def modifyState(externalV: Int): OneCombiner =
OneCombiner(this.a + 1, this.b + 1, func1().getOrElse(???))
}
case class TwoCombiner(a: Int, b: Int, tss: TSS) extends Combiner {
override def func1(): Option[TSS] = ???
override def func2(): Option[TSS] = ???
def modifyState(externalV: Int): TwoCombiner =
TwoCombiner(this.a + 1, this.b + 1, func1().getOrElse(???))
}
5hu I'll ma 8o7v7i7uj un v be 7an j9u8j u ben I'm in hi k HH in88 I'm k HH mkkmii6 mik9mi butk9 he by I h uhhh inave JH HHb huh b m jmbye b e o. on 7 x
Related
Below code gives me the error
Method 'someMethod' overrides nothing
But isn't case class C extending trait A? Why am I getting this error
trait A
trait B {
def someMethod(req: A): Unit
}
case class C(i: Int, j: Int) extends A
object D extends B {
override def someMethod(req: C) ={
//some implementation
}
}
The problem is that you can pass any value of type A to this method:
def someMethod(req: A)
But you can only pass values of type C to this method:
override def someMethod(req: C)
So the second version is not a full implementation of the first because it can't handle values of type A which are not values of type C. So the second version cannot override the first.
Possible solution:
override def someMethod(req: A) =
req match {
case C(i, j) => // Code
case _ => // Error handling
}
Alternative to Tim's answer, maybe you want something like this:
trait A
final case class C(i: Int, j: Int) extends A
trait B[T <: A] {
def someMethod(req: T): Unit
}
object D extends B[C] {
override def someMethod(req: C): Unit = {
//some implementation
}
}
Let's say I have a class called A:
class A(i: Int) {
//private def to initialize a calculated value
def maintainedValue : Int = calculatedValue
def double : A = new A(maintainedValue * 2)
def combine(other: A) : A = new A(maintainedValue + other.maintainedValue)
def addAmt(amt : Int) : A = new A(maintainedValue + amt)
// Many many more methods
}
I want to define a class B that extends class A such that it's methods, almost all of which have similar logic, return an object of class B:
class B(i: Int) extends A(i) {
//private def to initialize a differently calculated value
def maintainedValue : Int = diffCalculatedValue
//Change all other methods to return type B without override???
}
Is it possible to do this without overriding all the methods?
Is there a simple way to instantiate these new instances with a variable/dynamic class?
Perhaps there is a more elegant way to do this?
One solution, and the simplest one in my opinion, is to change class A to have a structure such that a single method handles object creation:
def create(i: Int): TYPE = new B(i)
And just use an implicit method in class B to handle casting when calling the unaltered methods:
private implicit def convert(a: A): B = new B(a.maintainedValue)
Short and sweet, though I'm curious how efficient and/or scale-able this solution is.
How about having base trait with common logic and two implementation?
object App extends App {
println(A(1).double)
println(B(1).double)
}
trait A {
type TYPE
def create(i: Int): TYPE
def maintainedValue: Int
def double: TYPE = create(maintainedValue * 2)
def addAmt(amt: Int): TYPE = create(maintainedValue + amt)
}
trait B extends A {
}
object A {
def apply(i: Int) = new AImpl(i)
case class AImpl(i: Int) extends A {
override type TYPE = A
override def create(i: Int) = A(i)
override def maintainedValue: Int = 2
}
}
object B {
def apply(i: Int): B = new BImpl(i)
case class BImpl(i: Int) extends B {
override type TYPE = B
override def create(i: Int): TYPE = B(i)
override def maintainedValue: Int = 1
}
}
I'm trying to make a typeclass that depends on user input. Imagine we have some case objects:
sealed trait H
case object Ha extends H
case object Hb extends H
and the type class:
trait Foo[A] {
def bar: String
}
object Foo {
def bar[A : Foo] = implicitly[Foo[A]].bar
implicit object FooA extends Foo[Ha.type] {
override def bar: String = "A"
}
implicit object FooB extends Foo[Hb.type] {
override def bar: String = "B"
}
}
While I found a working solution using a match:
variableComingFromMainArgs match {
case "a" => Foo.bar[Ha.type] _
case "b" => Foo.bar[Hb.type] _
}
I remember that we have abstract types in Scala, so I could change my case class into:
sealed trait H {
type T <: H
}
case object Ha extends H {
type T = this.type
}
case object Hb extends H {
type T = this.type
}
Now, when depending on user input to the program, I could do something like
val variable = Ha
println(Foo.bar[variable.T])
However, for some reason this doesn't work the and the error is not very useful for me:
error: could not find implicit value for evidence parameter of type Foo[variable.T]
println(Foo.bar[variable.T])
Any ideas if this can be overcome, if not, why?
Thanks.
Implicits are compile time constructs so in principle they cannot depend on user input directly (programmer can wire it for example with pattern matching as you did).
Consider the following code. It compiles and works as intended:
trait H {
type A
}
case object Ha extends H {
override type A = Int
}
case object Hb extends H {
override type A = Long
}
trait Adder[T] {
def add(a: T, b: T): T
}
implicit object IntAdder extends Adder[Int] {
override def add(a: Int, b: Int): Int = a + b
}
implicit object LongAdder extends Adder[Long] {
override def add(a: Long, b: Long): Long = a + b
}
def addWithAdder(input: H)(a: input.A, b: input.A)(implicit ev: Adder[input.A]): input.A = ev.add(a, b)
val x: Int = addWithAdder(Ha)(3, 4)
val y: Long = addWithAdder(Hb)(3, 4)
Let's focus on addWithAdder method. Thanks to path dependent types compiler can choose correct implicit for this task. But still this method is basically the same as the following:
def add[T](a: T, b: T)(implicit ev: Adder[T]) = ev.add(a, b)
The only advantage first one can have is that you can provide all instances yourself and stop the user of your code to add own types (when H is sealed and all implementations are final).
Let's say I have the following code for value classes:
class Meters(val x: Int) extends AnyVal {
def +(m: Meters): Meters = new Meters(x + m.x)
}
class Seconds(val x: Int) extends AnyVal {
def +(s: Seconds): Seconds = new Seconds(x + s.x)
}
Is there any way for me to remove duplication of the "+" methods?
Something kind of like:
abstract class Units[T <: Units[T]](val x: Int) extends AnyVal {
def +(other: T): T = T(x + other.x)
}
Except I can't inherit from value classes, and I definitely can't use T like a constructor.
You can use a universal trait with a type class, lets start defining the trait.
trait Sum[T <: Sum[T]] extends Any {
val x: Int
def +(other: T)(implicit evidence : FromInt[T]): T = evidence.fromInt(x + other.x)
}
Now we need a type class that tell us how to go from an integer to some type, lets define this and call it FromInt
trait FromInt[T] {
def fromInt(x: Int) : T
}
now lets define the Meters value class which is as simple as
class Meters(val x :Int) extends AnyVal with Sum[Meters]
and in the companion object we can provide an implicit value of the type class we defined.
object Meters{
implicit val intConstructable : FromInt[Meters] = new FromInt[Meters] {
override def fromInt(x: Int) = new Meters(x)
}
}
and now we can just do
val added = new Meters(2) + new Meters(3)
println(added.x)
I have a Scala class with two parameters, and another one parameter constructor. For the one parameter constructor, I called a method to get a tuple of two elements and tried to use the tuple for the parameter of the constructor that requires two parameters. From this post: Scala tuple unpacking for constructors I could get an answer for the non-inheritance case, but I need to use the method for inheritance case.
This is my code, but I'm not sure how to instantiate the abstract class.
abstract class A(val a:Int, val b:Int) {
def h()// = ???
}
object A {
def apply(pair: (Int, Int)): A = new A(pair._1, pair._2)
def apply(v: Int): A = A(vals(v))
def vals(v:Int) = {
(v,v)
}
}
class B(override val a:Int, override val b:Int) extends A(a,b) {
override def h() = ???
}
object B {
def apply(pair: (Int, Int)): B = new B(pair._1, pair._2)
def apply(v: Int): B = B(A.vals(v))
}
object Main extends App {
val a = B(10)
println(a.a, a.b)
}
Of course, I got an error message if I tried to instantiate the abstract class.
error: class A is abstract; cannot be instantiated
def apply(pair: (Int, Int)): A = new A(pair._1, pair._2)
^
I think the simplest solution is just make the abstract class non abstract, and giving dummy body def h() = ???. However, I'm not sure there might be better way.
From Shadowlands' hint, I could just use the apply() only for concrete classes.
// http://stackoverflow.com/questions/32512401/scala-tuple-unpacking-for-constructors
abstract class A(val a:Int, val b:Int) {
def h()// = ???
}
object A {
def vals(v:Int) = {
(v,v)
}
}
class B(override val a:Int, override val b:Int) extends A(a,b) {
override def h() = ???
}
object B {
def apply(pair: (Int, Int)): B = new B(pair._1, pair._2)
def apply(v: Int): B = B(A.vals(v))
}
object Main extends App {
val a = B(10)
println(a.a, a.b)
}