I'm trying to understand a Scala case class difference with a regular class.
E.g. I have a definition
case class Charge(cc: CreditCard, amount: Double)
and can use it like carge.cc and charge.amount.
Are these statements constant field references or actually hidden getters are used? Is it possible to redefine semantic of e.g. carge.cc to add some code before returning value?
Case class is a "product type". Think of it as tuple, with elements named, rather than indexed. Technically, yes, cc is a generated accessor function, but no you cannot redefine it. If you could, it would defeat the purpose of it being a case class to begin with.
Just do something like this instead:
class Charge(_cc: CreditCard, _amount: Double) {
def cc = modify(_cc)
def amount = addTips(_amount)
}
Create your file Charge.scala with the content of your code
and then compile the code using scalac -print Charge.scala and you will get:
[syntax trees at end of cleanup]] // Test.scala
package <empty> {
case class Charge extends Object with Product with Serializable {
<caseaccessor> <paramaccessor> private[this] val cc: Int = _;
<stable> <caseaccessor> <accessor> <paramaccessor> def cc(): Int = Charge.this.cc;
<caseaccessor> <paramaccessor> private[this] val amount: Double = _;
<stable> <caseaccessor> <accessor> <paramaccessor> def amount(): Double = Charge.this.amount;
<synthetic> def copy(cc: Int, amount: Double): Charge = new Charge(cc, amount);
<synthetic> def copy$default$1(): Int = Charge.this.cc();
<synthetic> def copy$default$2(): Double = Charge.this.amount();
override <synthetic> def productPrefix(): String = "Charge";
<synthetic> def productArity(): Int = 2;
<synthetic> def productElement(x$1: Int): Object = {
case <synthetic> val x1: Int = x$1;
(x1: Int) match {
case 0 => scala.Int.box(Charge.this.cc())
case 1 => scala.Double.box(Charge.this.amount())
case _ => throw new IndexOutOfBoundsException(scala.Int.box(x$1).toString())
}
};
override <synthetic> def productIterator(): Iterator = runtime.this.ScalaRunTime.typedProductIterator(Charge.this);
<synthetic> def canEqual(x$1: Object): Boolean = x$1.$isInstanceOf[Charge]();
override <synthetic> def hashCode(): Int = {
<synthetic> var acc: Int = -889275714;
acc = Statics.this.mix(acc, Charge.this.cc());
acc = Statics.this.mix(acc, Statics.this.doubleHash(Charge.this.amount()));
Statics.this.finalizeHash(acc, 2)
};
override <synthetic> def toString(): String = ScalaRunTime.this._toString(Charge.this);
override <synthetic> def equals(x$1: Object): Boolean = Charge.this.eq(x$1).||({
case <synthetic> val x1: Object = x$1;
case5(){
if (x1.$isInstanceOf[Charge]())
matchEnd4(true)
else
case6()
};
case6(){
matchEnd4(false)
};
matchEnd4(x: Boolean){
x
}
}.&&({
<synthetic> val Charge$1: Charge = x$1.$asInstanceOf[Charge]();
Charge.this.cc().==(Charge$1.cc()).&&(Charge.this.amount().==(Charge$1.amount())).&&(Charge$1.canEqual(Charge.this))
}));
def <init>(cc: Int, amount: Double): Charge = {
Charge.this.cc = cc;
Charge.this.amount = amount;
Charge.super.<init>();
scala.Product$class./*Product$class*/$init$(Charge.this);
()
}
};
<synthetic> object Charge extends scala.runtime.AbstractFunction2 with Serializable {
final override <synthetic> def toString(): String = "Charge";
case <synthetic> def apply(cc: Int, amount: Double): Charge = new Charge(cc, amount);
case <synthetic> def unapply(x$0: Charge): Option = if (x$0.==(null))
scala.this.None
else
new Some(new Tuple2$mcID$sp(x$0.cc(), x$0.amount()));
<synthetic> private def readResolve(): Object = Charge;
case <synthetic> <bridge> <artifact> def apply(v1: Object, v2: Object): Object = Charge.this.apply(scala.Int.unbox(v1), scala.Double.unbox(v2));
def <init>(): Charge.type = {
Charge.super.<init>();
()
}
}
}
which tells you that this.cc is provided from an actual property of the object via a method called cc().
Related
Having the following code:
import shapeless.{::, Generic, HList, HNil, Lazy}
object Problem {
trait In {
def bar: Double
}
trait A {
def foo: Int
type I <: In
}
/////////////////////////////////////////////////////
final case class A1In(d: Double) extends In {
override def bar: Double = 1.1 + d
}
final case class A1() extends A {
override def foo: Int = 1
override type I = A1In
}
final case class A2In(d: Double) extends In {
override def bar: Double = 1.1 + d
}
final case class A2() extends A {
override def foo: Int = 1
override type I = A2In
}
final case class AListIn[T <: HList](items: T)(implicit ev: isIn[T]) extends In {
override def bar = 1.1
}
final case class AList[T <: HList](items: T)(implicit ev: isA[T]) extends A {
override def foo: Int = 555
override type I = AListIn[???]
}
trait isA[T] {
def aux_foo(value: T): Int
}
trait isIn[T] {
def aux_bar(value: T): Double
}
/////////////////////////////////////////////////////
def alloc(a: A): In = ????
def usage() = {
val a1: A1 = A1()
val a2: A2 = A2()
val l: AList[::[A1, ::[A2, ::[A1, HNil]]]] = AList(a1 :: a2 :: a1 :: HNil)
val a1In: A1In = A1In(1.2)
val a2In: A2In = A2In(9.3)
val lIn: AListIn[::[A2In, ::[A1In, HNil]]] = AListIn(a2In :: a1In :: HNil)
}
}
How can I fix it so it works as expected?
E.g how do I get correct type in place of ??? which is a proper type HList being result of applying isA -> isIn type mapping. The mapping must follow the natural association of A -> In mapping defined as type I <: In in trait A
And how to implement alloc function which for any concrete instance of In will produce corresponding instance of A?
Should concrete implementations of In be path dependent types of corresponding As?
Below is the code for isA the code for isIn is analogous
trait isA[T] {
def aux_foo(value: T): Int
}
object isA {
// "Summoner" method
def apply[T](implicit enc: isA[T]): isA[T] = enc
// "Constructor" method
def instance[T](func: T => Int): isA[T] = new isA[T] {
override def aux_foo(value: T): Int = func(value)
}
implicit def a1Encoder: isA[A1] = instance(i => 4)
implicit def a2Encoder: isA[A2] = instance(i => 9)
implicit def hnilEncoder: isA[HNil] = instance(hnil => 0)
implicit def hlistEncoder[H, T <: HList](implicit
hInstance: Lazy[isA[H]],
tInstance: isA[T]
): isA[H :: T] = instance {
case h :: t => hInstance.value.aux_foo(h) + tInstance.aux_foo(t)
}
implicit def genericInstance[A, R](implicit
generic: Generic.Aux[A, R],
rInstance: Lazy[isA[R]]
): isA[A] = instance { value => rInstance.value.aux_foo(generic.to(value)) }
}
I have following question: having typeclass for ADT derived with LabelledTypeClassCompanion (where both product and coproduct are correctly defined) inside Scala object, why compiler can't find instance for datatype itself (coproduct), but is able to do so for parameters of specific data constructors (product) when called inside the same object and assigned to val?
Below is a snippet for Show typeclass which is mostly borrowed from corresponding Shapeless example:
import shapeless._
object ShowGeneric {
trait Show[T] {
def show(t: T): String
}
object Show extends LabelledTypeClassCompanion[Show] {
implicit def intShow: Show[Int] = new Show[Int] {
override def show(i: Int): String = i.toString
}
implicit def booleanShow: Show[Boolean] = new Show[Boolean] {
override def show(b: Boolean): String = b.toString
}
implicit def listShow[A](implicit showA: Show[A]): Show[List[A]] = new Show[List[A]] {
override def show(l: List[A]): String = l.map(showA.show).mkString("List(", ", ", ")")
}
object typeClass extends LabelledTypeClass[Show] {
override def emptyProduct: Show[HNil] = new Show[HNil] {
override def show(t: HNil): String = ""
}
override def product[H, T <: HList](name: String, sh: Show[H], st: Show[T]): Show[H :: T] = new Show[H :: T] {
override def show(t: H :: T): String = {
val head = s"$name = ${sh.show(t.head)}"
val tail = st.show(t.tail)
if(tail.isEmpty) head else s"$head, $tail"
}
}
override def coproduct[L, R <: Coproduct](name: String, cl: => Show[L], cr: => Show[R]): Show[L :+: R] = new Show[L :+: R] {
override def show(t: L :+: R): String = t match {
case Inl(l) => s"$name(${cl.show(l)})"
case Inr(r) => cr.show(r)
}
}
override def emptyCoproduct: Show[CNil] = new Show[CNil] {
override def show(t: CNil): String = ""
}
override def project[F, G](instance: => Show[G], to: F => G, from: G => F): Show[F] = new Show[F] {
override def show(t: F): String = instance.show(to(t))
}
}
}
implicit class ShowOps[T](t: T)(implicit showT: Show[T]) {
def show: String = showT.show(t)
}
sealed trait Whatever
case class IntBool(i: Int, b: Boolean) extends Whatever
case class BoolInt(b: Boolean, i: Int) extends Whatever
case class BoolListInt(b: Boolean, l: List[Int]) extends Whatever
def showWhatever(whatever: Whatever)(implicit showWhatever: Show[Whatever]): String = {
showWhatever.show(whatever)
}
val stringBoolInt = BoolInt(false, 100).show // Compiles
val stringShowWhatever = showWhatever(BoolInt(false, 100)) // Doesn't compile: could not find implicit value for parameter showWhatever:ShowGeneric.Show[ShowGeneric.Whatever]
}
Thanks in advance for your answers!
Given simplified code example:
sealed trait A {
val c1: String
val c2: Int
def copy[Z <: A](src: File) : Z
}
case class B(c1: String, c2: Int, src: File) extends A
case class C(c1: String, c2: Int, c3: MyClass, src: File) extends A
how do I define copy method in trait A so it will match generated one for case class and 'target' file? Given definition does typecheck and complains about missing method copy in classes B and C.
scala compiler will not generate copy methods for case class that defines method with name copy.
scala -Xprint:typer -e "sealed trait A { def copy[T <: A](s: String):T }; case class B(x: Int, y:Int) extends A"
outputs:
/var/folders/fm/fm4b21vj6jl995ywlrd99t49tjthjc/T/scalacmd3413244935208502669.scala:1: error: class B needs to be abstract, since method copy in trait A of type [T <: this.A](s: String)T is not defined
sealed trait A { def copy[T <: A](s: String):T }; case class B(x: Int, y: Int) extends A
^
one error found
[[syntax trees at end of typer]] // scalacmd3413244935208502669.scala
package <empty> {
object Main extends scala.AnyRef {
def <init>(): Main.type = {
Main.super.<init>();
()
};
def main(argv: Array[String]): Unit = {
val args: Array[String] = argv;
{
final class $anon extends scala.AnyRef {
def <init>(): anonymous class $anon = {
$anon.super.<init>();
()
};
sealed abstract trait A extends scala.AnyRef {
def copy[T >: Nothing <: this.A](s: String): T
};
case class B extends AnyRef with this.A with Product with Serializable {
<caseaccessor> <paramaccessor> private[this] val x: Int = _;
<stable> <caseaccessor> <accessor> <paramaccessor> def x: Int = B.this.x;
<caseaccessor> <paramaccessor> private[this] val y: Int = _;
<stable> <caseaccessor> <accessor> <paramaccessor> def y: Int = B.this.y;
def <init>(x: Int, y: Int): this.B = {
B.super.<init>();
()
};
override <synthetic> def productPrefix: String = "B";
<synthetic> def productArity: Int = 2;
<synthetic> def productElement(x$1: Int): Any = x$1 match {
case 0 => B.this.x
case 1 => B.this.y
case _ => throw new IndexOutOfBoundsException(x$1.toString())
};
override <synthetic> def productIterator: Iterator[Any] = runtime.this.ScalaRunTime.typedProductIterator[Any](B.this);
<synthetic> def canEqual(x$1: Any): Boolean = x$1.$isInstanceOf[this.B]();
override <synthetic> def hashCode(): Int = {
<synthetic> var acc: Int = -889275714;
acc = Statics.this.mix(acc, x);
acc = Statics.this.mix(acc, y);
Statics.this.finalizeHash(acc, 2)
};
override <synthetic> def toString(): String = ScalaRunTime.this._toString(B.this);
override <synthetic> def equals(x$1: Any): Boolean = B.this.eq(x$1.asInstanceOf[Object]).||(x$1 match {
case (_: this.B) => true
case _ => false
}.&&({
<synthetic> val B$1: this.B = x$1.asInstanceOf[this.B];
B.this.x.==(B$1.x).&&(B.this.y.==(B$1.y)).&&(B$1.canEqual(B.this))
}))
};
<synthetic> private object B extends scala.runtime.AbstractFunction2[Int,Int,this.B] with Serializable {
def <init>(): this.B.type = {
B.super.<init>();
()
};
final override <synthetic> def toString(): String = "B";
case <synthetic> def apply(x: Int, y: Int): this.B = new B(x, y);
case <synthetic> def unapply(x$0: this.B): Option[(Int, Int)] = if (x$0.==(null))
scala.this.None
else
Some.apply[(Int, Int)](Tuple2.apply[Int, Int](x$0.x, x$0.y));
<synthetic> private def readResolve(): Object = $anon.this.B
}
};
{
new $anon();
()
}
}
}
}
}
I am trying to write code to represent polynomials within Scala. I need this code to be type polymorphic, so I am using implicits to deal with different types. I have:
case class Mono[T](degree: Int, coeff: T) {
def Degree: Int = return degree
def Coeff: T = return coeff
}
class Poly[T](private val terms: List[Mono[T]]) {
trait Semiring[T] {
def add(x:T, y:T): T
def mul(x:T, y:T): T
def exponent(x: T, n:Int): T
val unitA: T
}
implicit object IntSemiring extends Semiring[Int] {
def add(x: Int, y: Int): Int = x+y
def mul(x: Int, y: Int): Int = x*y
def exponent(x: Int, n:Int): Int = if(n==0) 1 else x*exponent(x, n-1)
val unitA: Int = 0
}
implicit object SetSemiring extends Semiring[Set[Int]] {
def add(x: Set[Int], y: Set[Int]): Set[Int] = x.union(y)
def mul(x: Set[Int], y: Set[Int]): Set[Int] = x.intersect(y)
def exponent(x: Set[Int], n: Int): Set[Int] = x
val unitA: Set[Int] = Set()
}
def eval(x: T)(implicit r: Semiring[T]): T = {
var termlist = terms
var sum = r.unitA
var expression = terms
while(!termlist.isEmpty) {
val term = expression.head
val power = r.exponent(x, term.Degree)
val termval = r.mul(power, term.Coeff)
sum = r.add(sum, termval)
termlist = termlist.tail
}
return sum
}
def add(that: Poly[T])(implicit r: Semiring[T]): Poly[T] = ...
def mul(that: Poly[T])(implicit r: Semiring[T]): Poly[T] = ...
}
I chopped out a few functions for brevity there. This compiles fine but when I try and use it I get some strange errors:
scala> val p1 = new Poly(List(Mono(0,1),Mono(1,2),Mono(2,1)))
p1: Poly[Int] = Poly#450ae3fb
scala> p1 eval 3
<console>:9: error: could not find implicit value for parameter r: p1.Semiring[Int]
p1 eval 3
^
I'm not sure how to fix it. Am I defining the implicit objects in the wrong place? I tried moving them outside the class but then the complier fails. Is there something else I need to do to get it to work properly?
Implicit resolution is done at the location where you call the function, not where you define it. You should import your implicits before calling p1.eval:
val p1 = new Poly(List(Mono(0,1),Mono(1,2),Mono(2,1)))
import p1._
p1 eval 3
Since your implicits are not really bound to an instance of Poly, you can define them outside Poly.
If you don't want to import explicitly the Semiring implicits, you can define them in the companion object of Semiring since Scala search for matching implicits in the companion object when they are missing:
case class Mono[T](degree: Int, coeff: T) {
def Degree: Int = return degree
def Coeff: T = return coeff
}
class Poly[T](private val terms: List[Mono[T]]) {
def add(that: Poly[T])(implicit r: Semiring[T]): Poly[T] = ...
def mul(that: Poly[T])(implicit r: Semiring[T]): Poly[T] = ...
}
trait Semiring {
def add(x:T, y:T): T
def mul(x:T, y:T): T
def exponent(x: T, n:Int): T
val unitA: T
}
object Semiring {
implicit object IntSemiring extends Semiring[Int] {
def add(x: Int, y: Int): Int = x+y
def mul(x: Int, y: Int): Int = x*y
def exponent(x: Int, n:Int): Int = if(n==0) 1 else x*exponent(x, n-1)
val unitA: Int = 0
}
implicit object SetSemiring extends Semiring[Set[Int]] {
def add(x: Set[Int], y: Set[Int]): Set[Int] = x.union(y)
def mul(x: Set[Int], y: Set[Int]): Set[Int] = x.intersect(y)
def exponent(x: Set[Int], n: Int): Set[Int] = x
val unitA: Set[Int] = Set()
}
}
Then you don't need to import them anymore:
val p1 = new Poly(List(Mono(0,1),Mono(1,2),Mono(2,1)))
p1 eval 3
Why is the following implicit method not applied? And how can I achieve to automatically convert an instance of X to an instance of Y while having an implicit Conversion[X,Y] in scope.
trait Conversion[X, Y] {
def apply(x: X): Y
}
implicit object Str2IntConversion extends Conversion[String, Int] {
def apply(s: String): Int = s.size
}
implicit def convert[X, Y](x: X)(implicit c: Conversion[X, Y]): Y = c(x)
val s = "Hello"
val i1: Int = convert(s)
val i2: Int = s // type mismatch; found: String required: Int
Make your conversion extend Function1, then you don't need the helper method anymore:
trait Conversion[X, Y] extends (X => Y) {
def apply(x: X): Y
}
// unchanged
implicit object Str2IntConversion extends Conversion[String, Int] {
def apply(s: String): Int = s.size
}
// removed convert
// unchanged
val s = "Hello"
val i1: Int = convert(s)
val i2: Int = s