Calculations before extending class - scala

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)

Related

Scala Subclass change return type without override

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
}
}

Value * is not a member of type parameter Int

package impatient.mapsAndTups.objects
abstract class UnitConversion {
def convert[T](x: T): T
}
class Inches2Centimeters extends UnitConversion {
override def convert[Int](x: Int): Int = x * 100
}
object Conversions extends App {
val c = new Inches2Centimeters()
println(c.convert(15))
}
I'm not understanding why the preceding code is not compiling. I'm getting the error:
Error:(9, 46) value * is not a member of type parameter Int
override def convert[Int](x: Int): Int = x * 100
What can I do to fix this?
You have "shadowed" the standard type Int with your own Int within the scope of your method convert. That's because you defined convert to work with a parametric type whose name is Int and which will be defined by callers (and type inference).
One way to fix your code is the following, although I wouldn't do it this way myself.
package impatient.mapsAndTups.objects
abstract class UnitConversion {
def convert[T](x: T): T
}
class Inches2Centimeters extends UnitConversion {
def convert[T](x: T): T = x match {
case t: Int => (t * 100).asInstanceOf[T]
}
}
object Conversions extends App {
val c = new Inches2Centimeters()
println(c.convert(15))
}
Note also that you don't need to override convert in your concrete class.
Instead, I would use the "typeclass" Numeric as follows:
package impatient.mapsAndTups.objects
abstract class UnitConversion {
def convert[T: Numeric](x: T): T
}
class Inches2Centimeters extends UnitConversion {
def convert[T: Numeric](x: T): T = {
val n = implicitly[Numeric[T]]
n.times(n.fromInt(100), x)
}
}
object Conversions extends App {
val c = new Inches2Centimeters()
println(c.convert(15))
}
I think, what you want is to declare the type parameter at the class level, not function:
abstract class UnitConversion[T] {
def convert(x: T): T
}
class Inches2Centimeters extends UnitConversion[Int] {
override def convert(x: Int): Int = x * 100 // this multiplier is wrong :)
}

Abstracting out function across value classes

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)

Scala: create instance from generic type with private constructor

I have a class with a generic type parameter and I would like to create an instance of this type using reflection. Moreover, the type has a private constructor.
Here is a code sample of the problem:
class X private (x: Int) {
}
class Y private (y: Int) {
}
abstract class Foo[T](z : Int) {
var bar : T = createInstance[T](z)
def createInstance[T](z: Int) : M = {
???
}
}
This would allow me to instantiate Foo and access bar:
class xFoo extends Foo[X]{
}
class yFoo extends Foo[Y]{
}
var xfoo = new xFoo(5)
println(xfoo.bar.x)
var yfoo = new yFoo(6)
println(yfoo.bar.y)
This should print out '5' and '6'.
I have tried using implicit in the following way.
def createInstance[T](z: Int)(implicit tag: TypeTag[T]) : T = {
val clazz = tag.tpe.getClass
val ctor = class.getDeclaredConstructor(classOf[Int])
ctor.setAccessible(true)
return ctor.newInstance(z).asInstanceOf[T]
}
However, then I get the error:
No TypeTag available for T
in line
var bar : T = createInstance[T](z)
Any suggestions? Thanks for your help!
Assuming that the super class does expose some method/value you're looking for like:
class X private(val x: Int) {}
You can extend it like so:
import scala.reflect._
class Foo[T](z : Int)(implicit ct: ClassTag[T]) {
var bar : T = createInstance[T](z)
def createInstance[T](z: Int) : T = {
val ctor = ct.runtimeClass.getDeclaredConstructor(classOf[Int])
ctor.setAccessible(true)
ctor.newInstance(Int.box(4)).asInstanceOf[T]
}
}
This enables you to call:
class XFoo(n: Int) extends Foo[X](n)
println((new XFoo(5)).bar.x)

Abstract classes with constructor parameters in Scala

I have the following class model:
sealed abstract class Tile(val coordinate: Int, val isOccupied: Boolean) {
def isEmpty() : Boolean
def getPiece() : Option[Piece]
}
case class EmptyTile(coordinate: Int) extends Tile(coordinate, false) {
override def toString: String = "" +coordinate
override def isEmpty() = true
override def getPiece() = None
}
case class OccupiedTile(coordinate: Int, val piece: Piece) extends Tile(coordinate, true) {
override def toString = piece.toString
override def isEmpty = false
override def getPiece = Some(piece)
}
and I get the following error:
Error:(6, 22) overriding value coordinate in class Tile of type Int;
value coordinate needs `override' modifier
case class EmptyTile(coordinate: Int) extends Tile(coordinate, false) {
^
What am I doing wrong?
EDIT: Request to see Piece class, adding here:
import Alliance.Alliance
import PieceType.PieceType
abstract class Piece(val piecePosition: Int, val pieceType : PieceType, val alliance: Alliance) extends Movable {
}
object PieceType extends Enumeration {
type PieceType = Value
val PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING = Value
}
Your abstract class Tile declares a val coordinate, making this value publicly accessible. Your case class EmptyTile implicitly declares coordinate as a val as well (case class "magic"). Basically, your case class is effectively trying to override a value already provided by your abstract class.
You can either remove the val in your abstract class declaration, or not make EmptyTile and OccupiedTile case classes.
Edit: proposed alternative after comment:
trait Tile {
def coordinate: Int
def isOccupied: Boolean
def isEmpty() : Boolean = !isOccupied
def getPiece() : Option[Piece]
}
case class EmptyTile(coordinate: Int) extends Tile {
override def toString: String = "" +coordinate
val isOccupied = false
def getPiece() = None
}
case class OccupiedTile(coordinate: Int, val piece: Piece) extends Tile {
override def toString = piece.toString
val isOccupied = true
def getPiece = Some(piece)
}
case class automatically makes its arguments vals. This is why the argument coordinate to EmptyTile, understood as val coordinate, conflicts with the abstract class's val coordinate.
One way to fix this is to have coordinate and isOccupied be defined as abstract in Tile. Tile can even be a trait instead of an abstract class:
sealed trait Tile {
def coordinate: Int
def isOccupied: Boolean
...
}
case class EmptyTile(coordinate: Int) extends Tile {
def isOccupied = false
...
}
case class OccupiedTile(coordinate: Int, piece: Piece) extends Tile {
def isOccupied = true
...
}