can we have methods as arguments in a class definition? - scala

Following is the snippet of code I was going thru a scala book.
One of the parameter of the Car class is "def color: String"
I didn't understand. "def" is a keyword to define a method. how can that be used in paramenters?
scala> abstract class Car {
| val year: Int
| val automatic: Boolean = true
| def color: String
| }

A function that takes other functions are arguments is known as a higher-order function, here is an example of that:
// A function that takes a list of Ints, and a function that takes an Int and returns a boolean.
def filterList(list: List[Int], filter: (Int) => Boolean) = { /* implementation */ }
// You might call it like this
def filter(i: Int) = i > 0
val list = List(-5, 0, 5, 10)
filterList(list, filter)
// Or shorthand like this
val list = List(-5, 0, 5, 10)
filterList(list, _ > 0)
However that is not what is happening in your example. In your example the Car class has three class members, two of them are variables, and one of them is a function. If you were to extend your abstract class, you could test the values out:
abstract class Car {
val year: Int
val automatic: Boolean = true
def color: String
}
case class Sedan(year: Int) extends Car {
def color = "red"
}
val volkswagen = Sedan(2012)
volkswagen.year // 2012
volkswagen.automatic // true
volkswagen.color // red
Here, having color as a function (using def) doesn't make too much sense, because with my implementation, the color is always going to be "red".
A better example for using a function for a class member would be for some value that is going to change:
class BrokenClock {
val currentTime = DateTime.now()
}
class Clock {
def currentTime = DateTime.now()
}
// This would always print the same time, because it is a value that was computed once when you create a new instance of BrokenClock
val brokenClock = BrokenClock()
brokenClock.currentTime // 2017-03-31 22:51:00
brokenClock.currentTime // 2017-03-31 22:51:00
brokenClock.currentTime // 2017-03-31 22:51:00
// This will be a different value every time, because each time we are calling a function that is computing a new value for us
val clock = Clock()
clock.currentTime // 2017-03-31 22:51:00
clock.currentTime // 2017-03-31 22:52:00
clock.currentTime // 2017-03-31 22:53:00

Related

Array of case class as parameter T

If I have these 2 or N case classes as follows:
case class dbep1 (a1:String, b1:String, ts1: Integer)
case class dbep2 (a2:String, b2:String, ts2: Integer)
var dbep1D = new ArrayBuffer[dbep1]()
dbep1D = ArrayBuffer(dbep1("Mark", "Hamlin", 2), dbep1("Kumar", "XYZ", 3), dbep1("Tom", "Poolsoft", 4))
var dbep2D = new ArrayBuffer[dbep2]()
dbep2D = ArrayBuffer(dbep2("Pjotr", "Hamming", 4), dbep2("Kumar", "ABNC", 7), dbep2("Tom", "Gregory", 3))
How can I write a def that accepts both of these as an array of T, like so:
import scala.collection.mutable.ArrayBuffer
def printArray[a: ArrayBuffer[T]]() = {
// do anything with ArrayBuffer[T]
println(a)
}
Clearly not correct, just passing a single variable case class will work as per below:
def doSomeThing[T]() = {
// ...
}
case class SomeClassA(id: UUID, time: Date)
doSomeThing[SomeClassA]()
But what if I want an ArrayBuffer of a give case class as input?
May be just not possible.
Your doSomeThing function does not take an argument. It takes a generic argument but no actual values, and with no arguments at all (not even an implicit ClassTag), there's absolutely nothing you can do with it.
I'll assume you meant
def doSomeThing[T](arg: T) = {
// ...
}
If you want your function to take an arbitrary array buffer instead, you don't replace the thing inside brackets; that's still a free variable. You change the argument type.
def printArray[T](arg: ArrayBuffer[T]) = {
// ...
}

How to dynamically create an Enum type in Scala?

I have a basic enum type Currency that will include all major currencies traded e.g. EUR, USD, JPY, etc. This code I can write or generate one time. However, I'd also like to have strong enum type for all currency pair combinations e.g. EURCHF, USDCHF, etc. Is there any provision in Scala that would allow me to build such a derived enum type dynamically? I could also do it with some script generator from outside ... but I wonder whether it would be possible.
object Ccy extends Enumeration {
type Type = Value
val USD = Value("USD")
val CHF = Value("CHF")
val EUR = Value("EUR")
val GBP = Value("GBP")
val JPY = Value("JPY")
}
object CcyPair extends Enumeration {
type Type = Value
// ??? Ccy.values.toSeq.combinations(2) ...
}
UPDATE using the accepted answer as reference this was my solution implementation:
import scala.language.dynamics
object CcyPair extends Enumeration with Dynamic {
type Type = Value
/*
* contains all currency combinations including the symmetric AB and BA
*/
private val byCcy: Map[(Ccy.Value, Ccy.Value), Value] =
Ccy.values.toSeq.combinations(2).map { case Seq(c1, c2) =>
Seq(
(c1, c2) -> Value(c1.toString + c2.toString),
(c2, c1) -> Value(c2.toString + c1.toString)
)
}.flatten.toMap
/**
* reverse lookup to find currencies by currency pair, needed to find
* the base and risk components.
*/
private val revByCcy = byCcy.toSeq.map { case (((ccyRisk, ccyBase), ccyPair)) =>
ccyPair -> (ccyRisk, ccyBase)
}.toMap
def apply(ccy1: Ccy.Value, ccy2: Ccy.Value): Value = {
assert(ccy1 != ccy2, "currencies should be different")
byCcy((ccy1, ccy2))
}
implicit class DecoratedCcyPair(ccyPair: CcyPair.Type) {
def base: Ccy.Type = {
revByCcy(ccyPair)._1
}
def risk: Ccy.Type = {
revByCcy(ccyPair)._2
}
def name: String = ccyPair.toString()
}
def selectDynamic(ccyPair: String): Value = withName(ccyPair)
}
and then I can do things like:
val ccyPair = CcyPair.EURUSD
// or
val ccyPair = CcyPair(Ccy.EUR, Ccy.USD)
// and then do
println(ccyPair.name)
// and extract their parts like:
// print the base currency of the pair i.e. EUR
println(CcyPair.EURUSD.base)
// print the risk currency of the pair i.e. USD
println(CcyPair.EURUSD.risk)
There is no magic in Scala's Enumeration. The call to the Value function inside simply does some modifications to Enumeration's internal mutable structures. So you just have to call Value for each pair of currencies. The following code will work:
object CcyPair1 extends Enumeration {
Ccy.values.toSeq.combinations(2).foreach {
case Seq(c1, c2) =>
Value(c1.toString + c2.toString)
}
}
It's not very comfortable to work with though. You can access the values only through withName or values functions.
scala> CcyPair1.withName("USDEUR")
res20: CcyPair1.Value = USDEUR
But it's possible to extend this definition, for example, to allow retrieving CcyPair.Value by a pair of Ccy.Values, or to allow access by object fields with Dynamic, or to provide other facilities you may need:
import scala.language.dynamics
object CcyPair2 extends Enumeration with Dynamic {
val byCcy: Map[(Ccy.Value, Ccy.Value), Value] =
Ccy.values.toSeq.combinations(2).map {
case Seq(c1, c2) =>
(c1, c2) -> Value(c1.toString + c2.toString)
}.toMap
def forCcy(ccy1: Ccy.Value, ccy2: Ccy.Value): Value = {
assert(ccy1 != ccy2, "currencies should be different")
if (ccy1 < ccy2) byCcy((ccy1, ccy2))
else byCcy((ccy2, ccy1))
}
def selectDynamic(pairName: String): Value =
withName(pairName)
}
This definition is a bit more useful:
scala> CcyPair2.forCcy(Ccy.USD, Ccy.EUR)
res2: CcyPair2.Value = USDEUR
scala> CcyPair2.forCcy(Ccy.EUR, Ccy.USD)
res3: CcyPair2.Value = USDEUR
scala> CcyPair2.USDCHF
res4: CcyPair2.Value = USDCHF

scala using a class argument a placeholder (or input variable)

Lets say i have a data structure that holds a parameterised type of data:
case class Terminal[A](value: A, name: String ="")
I can easily create a Terminal[Double] if i pass it a materialised constant:
val terminal = Terminal(2.0)
However, i want it to also be able to receive a (not materialised) input so that i can evaluate the terminal multiple times with different contexts. I can achieve a simple solution by calling value by name, i.e.
class Terminal[A](value: => A, name: String ="") {
def getValue = this.value
}
var x = 1.0
val terminal = new Terminal(x)
terminal.getValue // 1.0
x = 100.0
terminal.getValue // 100.0
However the user of this program would have to initialise the input with something like var input_x = None, which is not nice, and then change its state, which in turn would have to make me turn value into a Option[A]
Is this the best way to deal with this situation? Isn't any design pattern or scala feature that i could use?
i can also create a class Input to represent these context-dependent inputs, but then i would need to change a lot of things.
You can use immutable objects as below:
scala> case class Terminal[A](value: A, name: String ="") {
| def update(newValue: A): Terminal[A] = this.copy(value = newValue)
| def getValue: A = this.value
| }
defined class Terminal
scala> val terminal = Terminal(1.0)
terminal: Terminal[Double] = Terminal(1.0,)
scala> val updatedTerminal = terminal.update(100.0)
updatedTerminal: Terminal[Double] = Terminal(100.0,)
scala> val oldValue = terminal.getValue
oldValue: Double = 1.0
scala> val newValue = updatedTerminal.getValue
newValue: Double = 100.0
The getValue method is actually redundant here because getters come free with case classes. I just had it in there to demonstrate the example.
scala> oldValue == terminal.value
res0: Boolean = true
scala> newValue == updatedTerminal.value
res1: Boolean = true
In general, prefer case-classes if you want to create objects that don't have mutable state (For example, all singleton components are better-off as non-case classes).

How can I extend Scala collections with member values?

Say I have the following data structure:
case class Timestamped[CC[M] < Seq[M]](elems : CC, timestamp : String)
So it's essentially a sequence with an attribute -- a timestamp -- attached to it. This works fine and I could create new instances with the syntax
val t = Timestamped(Seq(1,2,3,4),"2014-02-25")
t.elems.head // 1
t.timestamp // "2014-05-25"
The syntax is unwieldly and instead I want to be able to do something like:
Timestamped(1,2,3,4)("2014-02-25")
t.head // 1
t.timestamp // "2014-05-25"
Where timestamped is just an extension of a Seq and it's implementation SeqLike, with a single attribute val timestamp : String.
This seems easy to do; just use a Seq with a mixin TimestampMixin { val timestamp : String }. But I can't figure out how to create the constructor. My question is: how do I create a constructor in the companion object, that creates a sequence with an extra member value? The signature is as follows:
object Timestamped {
def apply(elems: M*)(timestamp : String) : Seq[M] with TimestampMixin = ???
}
You'll see that it's not straightforward; collections use Builders to instantiate themselves, so I can't simply call the constructor an override some vals.
Scala collections are very complicated structures when it comes down to it. Extending Seq requires implementing apply, length, and iterator methods. In the end, you'll probably end up duplicating existing code for List, Set, or something else. You'll also probably have to worry about CanBuildFroms for your collection, which in the end I don't think is worth it if you just want to add a field.
Instead, consider an implicit conversion from your Timestamped type to Seq.
case class Timestamped[A](elems: Seq[A])(timestamp: String)
object Timestamped {
implicit def toSeq[A](ts: Timestamped[A]): Seq[A] = ts.elems
}
Now, whenever I try to call a method from Seq, the compiler will implicitly convert Timestamped to Seq, and we can proceed as normal.
scala> val ts = Timestamped(List(1,2,3,4))("1/2/34")
ts: Timestamped[Int] = Timestamped(List(1, 2, 3, 4))
scala> ts.filter(_ > 2)
res18: Seq[Int] = List(3, 4)
There is one major drawback here, and it's that we're now stuck with Seq after performing operations on the original Timestamped.
Go the other way... extend Seq, it only has 3 abstract members:
case class Stamped[T](elems: Seq[T], stamp: Long) extends Seq[T] {
override def apply(i: Int) = elems.apply(i)
override def iterator = elems.iterator
override def length = elems.length
}
val x = Stamped(List(10,20,30), 15L)
println(x.head) // 10
println(x.timeStamp) // 15
println(x.map { _ * 10}) // List(100, 200, 300)
println(x.filter { _ > 20}) // List(30)
Keep in mind, this only works as long as Seq is specific enough for your use cases, if you later find you need more complex collection behavior this may become untenable.
EDIT: Added a version closer to the signature you were trying to create. Not sure if this helps you any more:
case class Stamped[T](elems: T*)(stamp: Long) extends Seq[T] {
def timeStamp = stamp
override def apply(i: Int) = elems.apply(i)
override def iterator = elems.iterator
override def length = elems.length
}
val x = Stamped(10,20,30)(15L)
println(x.head) // 10
println(x.timeStamp) // 15
println(x.map { _ * 10}) // List(100, 200, 300)
println(x.filter { _ > 20}) // List(30)
Where elems would end up being a generically created WrappedArray.

Efficient map with case class as a key in Scala?

A following C code uses enum and array as efficient "map" from enum to anything:
enum Color { ColorRed, ColorGreen, ColorBlue, ColorSize};
void f() {
int x[ColorSize];
x[ColorRed] = 12;
x[ColorGreen] = 33;
x[ColorBlue] = 4;
return x[ColorGreen];
}
Is this possible with Scala?
I.e. to have a "map" from case class to something, implemented as efficient array and not as tree or as hashmap. Yet I would like to be able to index only with a paricular type not with Int.
Update: In short I would like to have Scala Array indexed by some kind of enum (case class or Enumeration).
For small enumerations you can "simulate" the C behavior:
abstract sealed class Color(val index: Int)
object Color {
implicit def col2int(color:Color) = color.index
}
case object ColorRed extends Color(0)
case object ColorGreen extends Color(1)
case object ColorBlue extends Color(2)
...
import Color._
val array = Array(1,2,3)
array(ColorRed) = 12
However, I doubt this would be considered good style, especially because it's unsafe. Using a map is a better approach, or you could wrap an array in a specialized data structure which deals with Color indizes:
class ColorArray[T:ClassManifest] {
val array = new Array[T] (3)
def apply(color: Color) = array(color.index)
def update(color: Color, value: T) = array(color.index) = value
}
...
val cArray = new ColorArray[Int]()
cArray(ColorRed) = 12
println(cArray(ColorRed))
object Color extends Enumeration{
val ColorRed, ColorGreen, ColorBlue = Value
}
import Color._
def f:Map[Color.Value,Int] =
Map(ColorRed -> 12 , ColorGreen -> 33, ColorBlue -> 4)
If you want the full C performance you could do this:
trait CEnum {
private var size = 0;
def value = { size += 1; size-1 }
}
object Color extends CEnum {
val colorRed = value
val colorGreen = value
val colorBlue = value
val colorSize = 3
}
import Color._
def f() = {
val x = Array[Int](colorSize)
x(colorRed) = 12
x(colorGreen) = 33
x(colorBlue) = 4
x(colorGreen)
}
It's equally unsafe as the method in C & just as performant. It is however very unsafe.