I have the following piece of code
class A(var x: Int, var y: Int){
}
class B(x: Int, y: Int) extends A(x,y){
def setX(xx: Int): this.type = {
this.x = xx
this
}
}
but it gives the following error:
error: reassignment to val
this.x = xx
^
I don't know whats happening since x and y should be variables. WHat's the correct way of doing this?
There is a collision of the names of member variables with the names of the constructor arguments.
The obvious workaround compiles just fine:
class A(var x: Int, var y: Int)
class B(cx: Int, cy: Int) extends A(cx, cy) {
def setX(xx: Int): this.type = {
this.x = xx
this
}
}
The issue doesn't seem to be new, here is a llink to a forum entry from 2009. It has a posting with literally the same error message in the same situation.
The root cause is that constructor arguments can be automatically converted into private vals, because they can be referenced from the methods of the object:
class B(cx: Int, cy: Int) {
def foo: Int = cx
}
Related
I would like to mark the default method generated by scala compiler to be ignored from being serialized.
#JsonIgnore def getSum(a: Int, b: Int = 2): Int = a + b
compiler creates two methods:
def getSum(a: Int, b: Int): Int = a.+(b);
<synthetic> def getSum$default$2(): Int = 2; (default value at position 2)
The first method getSum does not get serialized as the JsonIgnore is applied on it, but the new default parm method generated is serialized by jackson, how to tell Jackson to not serialize it?
Example:
import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.databind.ObjectMapper;
case class A(id: Int) {
#JsonIgnore def getSum(a: Int, b: Int = 2): Int = a + b
}
#Test
def test(): Unit = {
val a = A(5)
val mapper = new ObjectMapper()
println(mapper.writeValueAsString(a))
}
output: {"id":5,"sum$default$2":2}
I believe this is a bug, but there are workarounds:
Explicitly ignore the generated property
The #JsonIgnoreProperties annotation can be used at the class level.
#JsonIgnoreProperties(Array("sum$default$2"))
case class A(id: Int) {
def getSum(a: Int, b: Int = 2): Int = a + b
}
Rename the method
It's detected as a property because it matches the JavaBeans getter convention. If the method name can be changed to remove the get prefix, it won't be treated as a property by Jackson:
case class A(id: Int) {
def calculateSum(a: Int, b: Int = 2): Int = a + b
}
Avoid default arguments
Of course, another option is to avoid the use of default arguments entirely in favour of method overloading:
case class A(id: Int) {
def getSum(a: Int, b: Int): Int = a + b
def getSum(a: Int): Int = getSum(a, 2)
}
These examples are all demonstrated in this Scastie: https://scastie.scala-lang.org/TimMoore/werEmJF9S7ip4QP5sT73CQ/39
All of these options produce this JSON:
{"id":5}
I've recently started learning Scala's implicit "magic" and I'm having troubles with implicit Scala objects. I've tried all the possible variants but nothing seems to work.
Lets assume I have a class like this with some solve() function. It should return 2 Float values if the input a, b were Float. Otherwise it should return another type values:
class Solver[T](val a: T, val b: T) {
def solve[A](implicit num: customNumeric[T]): Option[(T, T)] = {
Option(
num.f(num.g(a)),
num.f(num.g(b)))
}
}
Let's assume another-type-value is an object of class like this:
class MyClass[T] (x: T, y: T)(implicit num: customNumeric[T]) {
val field : T = num.f(x)
}
And let's also assume that I dont have the functions I need in basic Scala Numeric so I should make my own custom numeric.
Here is what I've done:
I've made an abstract class for my own customNumeric with my methods f() and g() and couple of implicit objects that extend my customNumeric for some value types (Int, Float for example) and implemented method in them:
abstract class customNumeric[T] {
def f(x: T): T
def g(x: T): T
}
object customNumeric {
implicit object IntIsCustomNumeric extends customNumeric[MyClass[Int]] {
def f(x: MyClass[Int]) = new MyClass[Int](x.field + 5)
def g(x: MyClass[Int]) = new MyClass[Int](x.field - 5)
}
implicit object FloatIsCustomNumeric extends customNumeric[Float] {
def f(x: Float): Float = x + 3
def g(x: Float): Float = x - 3
}
}
In my opinion Solver's solve() should use implicit customNumeric object to get implementations for methods referenced inside solve() based upon type of the Solver's input values.
But this doesn't work as compiler says:
could not find implicit value for parameter num: customNumeric[Int]
def f...
It also complains because of not enough arguments for constructor MyClass at the same line.
I've already tried making companion object to cast Int to MyClass:
object Fraction {
implicit def int2MyClass(x: Int): MyClass[Int] = new MyClass[Int](x, 1)
}
But that also doen't seem to work. And I've tried to make another implicit object to implement methods I use in customNumeric[MyClass[Int]].
Do you have any ideas? Thanks in advance!
The problem is that you're trying to define the implicit objects with classes that themselves require that same implicit object.
Meaning, this:
class MyClass[T] (x: T, y: T)(implicit num: CustomNumeric[T])
Requires an existence of an implicit CustomNumeric[T]. You cannot define IntIsCustomNumeric using that type:
implicit object IntIsCustomNumeric extends customNumeric[MyClass[Int]]
When you implement IntIsCustomNumeric, you need to implement it for type Int, not for type MyClass[Int]. When you do that, i.e:
object CustomNumeric {
implicit object IntIsCustomNumeric extends CustomNumeric[Int] {
override def f(x: Int): Int = x
override def g(x: Int): Int = x
}
}
Now, you can create an Solver[Int] which takes an implicit CustomNumeric[Int]:
def main(args: Array[String]): Unit = {
import CustomNumeric._
val solver = new Solver[Int](1, 2)
println(solver.solve)
}
Now, it's also easier to create an implicit conversion from an Int type to something that creates a MyClass[Int]:
implicit object MyClassIsCustomNumeric extends CustomNumeric[MyClass[Int]] {
override def f(x: MyClass[Int]): MyClass[Int] = new MyClass[Int](x.field + 5)
override def g(x: MyClass[Int]): MyClass[Int] = new MyClass[Int](x.field + 3)
}
implicit def intToMyClass(i: Int) = new MyClass[Int](i)
What do you think about this
object customNumeric {
implicit object IntIsCustomNumeric extends customNumeric[Int] {
def f(x: Int): Int = x + 3
def g(x: Int): Int = x - 3
}
implicit object FloatIsCustomNumeric extends customNumeric[Float] {
def f(x: Float): Float = x + 3
def g(x: Float): Float = x - 3
}
implicit def int2MyClass(x: Int): MyClass[Int] = new MyClass[Int](x, 1)
implicit object cn extends customNumeric[MyClass[Int]] {
def f(x: MyClass[Int]) = x.field + 5
def g(x: MyClass[Int]) = x.field - 5
}
}
Here's an imaginary example:
class Bottle(volume: Int, water: Int) = {
def ratio = water / volume.toDouble
}
class RandomFullBottle extends Bottle(foo, foo)
^ ^
these two should be random and equal
How do I achieve this, i.e. where to call my randomBetween(a, b) function if I don't wanna resort to passing the random value to the RandomFullBottle constructor?
You can create two constructors for your RandomFullBottle class:
A private constructor that takes an int and passes it to the parent Bottle constructor
A public one that takes no arguments, generates the random value and passes it to the private constructor
Like so:
class Bottle(volume: Int, water: Int) {
def ratio = water / volume.toDouble
}
class RandomFullBottle private(amount: Int) extends Bottle(amount, amount) {
def this() = this(myRandomGenerator())
}
It's kind of convoluted, but this should do it.
object Bottle {
def init(): (Int, Int) = {
val r = scala.util.Random.nextInt
(r, r)
}
}
class Bottle(val volume: Int, val water: Int) {
def this(vw : (Int, Int)) {
this(vw._1, vw._2)
}
def this() {
this(Bottle.init())
}
def ratio = water / volume.toDouble
}
class RandomFullBottle extends Bottle
val randomBottle = new RandomFullBottle
println(randomBottle.ratio)
println(randomBottle.volume)
println(randomBottle.water)
I have the following pattern in my Scala code:
class A(x: Int)
object A {
def apply(x: Int, y: Int) = new A(x + y)
}
class B(x: Int) extends A(x)
object B {
def apply(x: Int, y: Int) = new B(x + y)
}
The apply methods are exactly the same, except for the Class of the object that they construct. I would like to avoid this code duplication, especially because in my real code I have several apply methods and they are much longer.
How can I achieve this? How can I remove this code duplication?
I thought about something like this:
class A(x: Int)
class B(x: Int) extends A(x)
trait C[T <: A] {
def apply(x: Int, y: Int) = new T(x + y)
}
object A extends C[A]
object B extends C[B]
It doesn't work, because T is not a class and therefore I cannot do "new T(x + y)".
In the specific case you can do something like
class A(x: Int) {
def this(x: Int, y: Int) = this(x + y)
}
class B(x: Int) extends A(x)
class Adder[T](f: Int => T) {
def apply(x: Int, y: Int) = f(x + y)
}
class A(x: Int)
object A extends Adder(new A(_))
class B(x: Int) extends A(x)
object B extends Adder(new B(_))
I would propose this solution:
class A(x: Int)
class B(x: Int) extends A(x)
trait C[+T <: A] {
def apply(x: Int, y: Int) = create(x + y)
protected def create(x: Int): T
}
object A extends C[A] {
override protected def create(x: Int) = new A(x)
}
object B extends C[B] {
override protected def create(x: Int) = new B(x)
}
Take a look at GenericCompanion class. It is part of Scala collections library and may inspire you:
http://www.scala-lang.org/api/current/index.html#scala.collection.generic.GenericCompanion
I'm trying to implement a trait as follow: (1)
trait FooLike {
def foo(x: Int): Int
}
class Foo extends FooLike {
def foo(x: Int, y: Int = 0): Int = x + y
}
But the compiler complains that the method foo(x: Int): Int is not implemented.
I can do: (2)
class Foo extends FooLike {
def foo(x: Int): Int = foo(x, 0)
def foo(x: Int, y: Int = 0): Int = x + y
}
But it feels like Java, and I don't like it ! Is there a way to avoid this boilerplate ?
I thought that def foo(x: Int, y: Int = 0) would define two methods in the background but apparently it's not the case. What's actually happening ?
--- EDIT : more weirdness ---
Also the following is perfectly legit: (3)
class Foo extends FooLike {
def foo(x: Int): Int = x - 1
def foo(x: Int, y: Int = 0): Int = x + y
}
while it doesn't seems reasonable (foo(4) = 3 while foo(4, 0) = 4).
I think that authorizing (1) and forbidding (3) would have been the most reasonable choice, but instead they made the opposite choice. So why did Scala make those choices ?
It is not possible to override a method of a different type signature in Scala by using default arguments. This is because of how default arguments are implemented. Default arguments are inserted when and where the method is applied, so there is only one version of the method being defined.
According to SID-1: Named and Default Arguments, when a method foo() with default arguments is compiled, only one method foo() is defined, which takes all the arguments. A call with default arguments like f.foo(xValue) is transformed at compile time into code equivalent to the following:
{
val x = xValue
val y = f.foo$default$2
f.foo(x, y)
}
The foo$default$2 method is a hidden method which takes no arguments and returns the default value of argument #2 to the method foo().
So while you can write the same exact functional application foo(xValue) for a method foo(x: Int) or a method foo(x: Int, y: Int = 0), the methods being called "behind the scenes" do not have the same type signature.
You are extending a trait which has a non implemented method, you must implement it in the extending classes or you can implement it in the trait, if you don't need the foo with a single variable you can do:
trait FooLike {
def foo(x: Int, y: Int): Int
}
class Foo extends FooLike {
def foo(x: Int, y: Int = 0): Int = x + y
}
But I suppose you do and so you have to give the compiler an implementation for it, to compare this case to Java, it's like when you extend an abstract class and you don't implement a method, the compiler will complain that either you implement the method or you declare the class abstract.
One other approach which came to mind and is fairly reasonable is to implement the method in the trait so:
trait FooLike {
def foo(x: Int): Int = x
}
class Foo extends FooLike {
def foo(x: Int, y: Int = 0): Int = x + y
}
Then if you want to add a new class with the trait mixed in but with a different method implementation just override the method:
class AnotherFoo extends FooLike {
override def foo(x: Int): Int = x + 1
}