Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write generic code in scala without inheritance hierarchy

Tags:

generics

scala

I have few classes which do not derive from any superclass. They all have bunch of same methods defined. For example,

class A {
    def getMsgNum = 1
}

class B {
    def getMsgNum = 2
}

I would like to write a generic function that will return message num based on object function is called with. So something like,

def getMsgNum[T](t: T) = t.getMsgNum

I think that because of type erasure I cannot expect that to work but I was looking at view bound and context bound with ClassTag but that still does not work.

def getType[T: ClassTag](msg: T) = {
    msg.getMsgNum
}

I come from C++ background and I am trying to achieve something to the effect of template compilation for every type.

Thanks for your time!

like image 515
user2903819 Avatar asked Dec 14 '22 19:12

user2903819


2 Answers

I personally prefer adhoc polymorphism with TypeClass (http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html) pattern. I think it will be much more "true scala way" solution for this kind of problem. Also structural typing more expensive at runtime because it use reflection for field access.

  class A
  class B

  trait ToMsgNum[T] {
    def getMsgNum: Int
  }

  implicit object AToMsgNum extends ToMsgNum[A] {
    def getMsgNum = 1
  }

  implicit object BToMsgNum extends ToMsgNum[B] {
    def getMsgNum = 2
  }


  def getMsgNum[T: ToMsgNum](t: T) =
    implicitly[ToMsgNum[T]].getMsgNum

  println(getMsgNum(new A))
  println(getMsgNum(new B))
like image 137
Eugene Zhulenev Avatar answered Mar 27 '23 02:03

Eugene Zhulenev


def getMsgNum[T](t: T)(implicit ev: T => { def getMsgNum: Int }) = t.getMsgNum

where { def getMsgNum: Int } is a structural type. From the documentation:

A structural type is a type of the form Parents { Decls } where Decls contains declarations of new members that do not override any member in Parents.

and

Structural types provide great flexibility because they avoid the need to define inheritance hierarchies a priori

Please note that the above solution uses an implicit reflective call to access the field of the structural type, a language feature that has to be explicitly enabled by adding the import

import scala.language.reflectiveCalls
like image 42
Gabriele Petronella Avatar answered Mar 27 '23 01:03

Gabriele Petronella