Better way to override a function definition - scala

I'm extending an abstract class from a library, and I want to override a function definition and use the superclass's definition as a fallback.
If the parent class's method were defined as a PartialFunction, I could just use orElse. Since it isn't, I'm doing the thing below (unlifting the parent function into a partial function so I can use orElse). It works, but it is one of those times when I suspect there is a better / more elegant way. Is there?
abstract class ThingICantChange {
def test:Int=>String = {
case 1 => "one"
case 2 => "two"
case _ => "unknown"
}
}
class MyClass extends ThingICantChange {
def myChanges:PartialFunction[Int,String] = {
case 2 => "mytwo"
case 3 => "three"
}
override def test = myChanges orElse Function.unlift(x => Some(super.test(x)))
}

I would do this:
class MyClass extends ThingICantChange {
override def test: Int => String = {
case 2 => "mytwo"
case 3 => "three"
case x => super.test(x)
}
}
If you're looking to construct a partial function from super.test then here's a clean way:
override def test = myChanges orElse PartialFunction(super.test)

Related

How to do instanceOf of a variable of a class (not a class type) in scala

I want to use isInstanceOf to decide the type of a variable,
however isInstanceOf[T] requires T and T has to be a class decided in compile time. I hope I can make it a variable.
See the example code:
class A{ ... }
class B{ ... }
val class_map = Map( classOf[A] -> 1, classOf[B] -> 2 )
val a = new A()
class_map.keys foreach { i =>
if (a.isInstanceOf[ i ]) // how to make this statement work?
println(class_map[i])
}
You can use isInstance method of the Class object:
val matchingValues = class_map.collect {
case (clazz, value) if clazz.isInstance(a) => value
}
matchingValues foreach println
If I were you, I'd take a different approach, along the lines of:
sealed trait Arg
case class A{ ... } extends Arg
case class B{ ... } extends Arg
val class_map: Arg => Int = {
case A => 1
case B => 2
}
val a = new A()
println(class_map(a)) // will print 1

creating a function, that takes a function as a paramter and calls it on each linkedlist item

we are given a linked list class, and we need to create a function in this class which takes a function as a parameter, and calls that function on each node of the list. we can do it recursively or through loops and I'm not sure why I can't get this to work.
currently im using a while loop where if the node doesent equal null call the function on that node, and then goto the next node.
class LinkedListNode[A](var value: A, var next: LinkedListNode[A]) {
def calleachnode(inputfunction : A => Unit): Unit = {
var node = this
while(node != null){
inputfunction(node.value)
node = node.next
}
}
}
This type of task is best done with (tail) recursion (also, never use var, unless you are completely certain why you need it ... and also, null is also something to avoid, use Option instead):
case class Node[A](value: A, next: Option[Node[A]]) {
#tailrec
final def calleachnode(f: A => Unit): Unit = {
f(value)
next match {
case Some(next) => next.calleachnode(f)
case None => ()
}
}
}
Here are 3 possibilities that uses Algebraic Data Types (ADT).
First an object-oriented way:
sealed trait LinkedListNode[A] {
def calleachnode(inputfunction : A => Unit): Unit
}
case class BranchNode[A](value:A, next: LinkedListNode[A]) extends LinkedListNode[A] {
def calleachnode(inputfunction : A => Unit): Unit = {
inputfunction(value)
next.calleachnode(inputfunction)
}
}
case class LeafNode[A](value:A) extends LinkedListNode[A] {
def calleachnode(inputfunction : A => Unit): Unit = {
inputfunction(value)
}
}
Or if you prefer you can use pattern matching:
sealed trait LinkedListNode[A] {
def calleachnode(inputfunction : A => Unit): Unit = this match {
case BranchNode(value, next) =>
inputfunction(value)
next.calleachnode(inputfunction)
case LeafNode(value) =>
inputfunction(value)
}
}
case class BranchNode[A](value:A, next: LinkedListNode[A]) extends LinkedListNode[A]
case class LeafNode[A](value:A) extends LinkedListNode[A]
You can test these solutions with:
val lln = BranchNode(12, LeafNode(2))
lln.calleachnode((i) => println(i * 2))
Now a more functional way to use ADT:
sealed trait LinkedListNode[A]
case class BranchNode[A](value:A, next: LinkedListNode[A]) extends LinkedListNode[A]
case class LeafNode[A](value:A) extends LinkedListNode[A]
def calleachnode[A](listNode: LinkedListNode[A], inputfunction : A => Unit): Unit = listNode match {
case BranchNode(value, next) =>
inputfunction(value)
calleachnode(next, inputfunction)
case LeafNode(value) =>
inputfunction(value)
}
The test looks a bit different:
val lln = BranchNode(12, LeafNode(2))
calleachnode[Int](lln, (i) => println(i * 2))

How to define a `StrContains.unapply` for pattern match?

There is a method in my code, which need to check if the passing string contain some specified chars, and then do something.
The code is looking like:
def check(str: String) = {
if(str.contains("A")) {
doSomething()
} else if(str.contains("B")) {
doSomething()
} else if(str.contains("C")) {
doSomething()
} else {
doSomething()
}
}
I want to try pattern match on it, but not very satisfied with:
def check(str: String) = str match {
case s if s.contains("A") => doSomething()
case s if s.contains("B") => doSomething()
case s if s.contains("C") => doSomething()
case _ => doSomething()
}
I hope I can define a StrContains.unapply to use it like this:
def check(str: String) = str match {
case StrContains("A") => doSomething()
case StrContains("B") => doSomething()
case StrContains("C") => doSomething()
case _ => doSomething()
}
But now sure how to do it. Any thoughts?
The problem is that when you do case StrContains("A"), the compiler will first call StrContains.unapply/unapplySeq (whichever way it is defined) and only then try to match the returned result against "A". The "A" literal itself will never be passed to StrContains.unapply/unapplySeq, so it has no way to perform the call s.contains("A") inside unapply/unapplySeq.
Simply put, this means you'd need to define distinct objects such as StrContainsA/StrContainsB/StrContainsC which is clearly a worse situation than simply doing case s if s.contains("A").
However, there is an alternative (and somewhat contrived) solution that allows to define a single extractor while still being able to specify inline the substring to match for, and that is to exploit the fact that scala supports defining extractors based on string interpolation:
implicit class ContainsContext (val sc : StringContext) {
object StrContains {
def unapply(str: String): Boolean = {
val substr: String = sc.parts.mkString
str.contains(substr)
}
}
}
Usage:
def check(str: String) = str match {
case StrContains"A" => doSomething()
case StrContains"B" => doSomething()
case StrContains"C" => doSomething()
case _ => doSomething()
}

Partial Function pattern match split into a class and a trait

Lift uses a PartialFunction on their implementation of Comet Actors, and you usually end up with this on your class:
override def lowPriority: PartialFunction[Any,Unit] = {
case MyCaseClass1(a) => do something here
case MyCaseClass2(a) => do something here
case AlwaysPresentCaseClass => default action
}
What I'd like to do, and I'm not sure if it is even possible is to split that Partial Function so that the last case can be moved into a trait.
So when I have a new comet actor I simply do:
class MyNewComet extends MyActorTrait {
override def lowPriority: PartialFunction[Any,Unit] = {
case MyCaseClass1(a) => do something here
case MyCaseClass2(a) => do something here
}
}
And Somehow the trait MyActorTrait will have the missing
case AlwaysPresentCaseClass => default action
You can compose partial functions using the orElse method:
val f1: PartialFunction[Any, String] = {
case 22 => "hallo"
}
val f2: PartialFunction[Any, String] = {
case "rara" => "welt"
}
val f = f1 orElse f2 // f falls back to f2 if undefined in f1
f(22)
f("rara")
Try this:
trait MyActorTrait extends /* whatever class provides lowPriority */ {
def default: PartialFunction[Any, Unit] = {
case AlwaysPresentCaseClass => default action
}
abstract override def lowPriority: PartialFunction[Any,Unit] =
super.lowPriority orElse default
}
The only problem is that you can't do MyNewComet extends MyActorTrait. Instead, you can either have class MyNewCometDefault extends MyNewComet with MyActorTrait, or new MyNewComet with MyActorTrait.

Can I use a class variable in a Scala match statement?

Say I have something like this:
obj match {
case objTypeOne : TypeOne => Some(objTypeOne)
case objTypeTwo : TypeTwo => Some(objTypeTwo)
case _ => None
}
Now I want to generalise, to pass in one of the types to match:
obj match {
case objTypeOne : clazz => Some(objTypeOne)
case objTypeTwo : TypeTwo => Some(objTypeTwo)
case _ => None
}
But this isn't allowed, I think for syntactic rather than semantic reasons (although I guess also that even though the clazz is a Class[C] the type is erased and so the type of the Option will be lost).
I ended up with:
if(clazzOne.isAssignableFrom(obj.getClass)) Some(clazz.cast(obj))
if(obj.isInstanceOf[TypeTwo]) Some(obj.asInstanceOf[TypeTwo])
None
I just wondered if there was a nicer way.
You could define an extractor to match your object:
class IsClass[T: Manifest] {
def unapply(any: Any): Option[T] = {
if (implicitly[Manifest[T]].erasure.isInstance(any)) {
Some(any.asInstanceOf[T])
} else {
None
}
}
}
So let's test it:
class Base { def baseMethod = () }
class Derived extends Base
val IsBase = new IsClass[Base]
def test(a:Any) = a match {
case IsBase(b) =>
println("base")
b.baseMethod
case _ => println("?")
}
test(new Base)
test(1)
You will have to define a val for your extractor, you can't inline IsBase, for example. Otherwise it would be interpreted as an extractor.
You could use pattern guards to achieve that. Try something like this:
obj match {
case objTypeTwo : TypeTwo => Some(objTypeTwo)
case objTypeOne if clazz.isAssignableFrom(objTypeOne.getClass) => Some(clazz.cast(objTypeOne))
case _ => None
}
You can use a local type alias for that:
def matcher[T](obj: Any)(implicit man: Manifest[T]) = {
val instance = man.erasure.newInstance.asInstanceOf[AnyRef]
type T = instance.type // type alias
obj match {
case objTypeOne : T => "a"
case objTypeTwo : TypeTwo => "b"
case _ => "c"
}
}
scala> matcher[TypeOne](TypeOne())
res108: java.lang.String = a
scala> matcher[TypeTwo](TypeOne())
res109: java.lang.String = c
UPDATE: Aaron Novstrup has pointed out that singleton type will only work if man.erasure.newInstance==obj (see ยง3.2.1 of the spec)