Tuesday, August 15, 2017

how to get enums value using case classes in scala

Leave a Comment

I am trying to implement enum using case class in scala.

with reference to question type parameter in traits to define data types in scala

sealed trait ElementType[+A] {       def length: Int  }  sealed trait Tag extends ElementType[Int] {      override def length: Int = 0  }   case object Tag100 extends Tag  sealed trait Value[+A] extends ElementType[A] {    override def length: Int = 0 }  final case class Value100(a: String) extends Value[String] {    override def length: Int = a.length }  case class MessageId(tag: Tag, value: Value[String]){  }  case class MessageRepType(tag: Tag[Int], value:MessageType ){  }  sealed trait Message[T] {def typeCode: T;}  object MessageTypes {  sealed trait MessageType[Int] extends Message[Int]  case object TYPE1 extends MessageType[Int]{val typeCode = 0;}  case object TYPE2 extends MessageType[Int]{val typeCode = 1;} }    case class ABCMessage (                     id:MessageId,                     messageType:MessageRepType) 

I want to print a message with something like below id and type in new line

   type        value    100        abc                  200        0   

Explanation: 100 abc represents MessageId 200 0 represnets MessageRepType and O represent TYPE1

2 Answers

Answers 1

Assuming your "message" is a ABCMessage(MessageId(Tag100, Value100("abc"),MessageRepType(Tag200, TYPE1)) (also assuming Tag200 is similar to Tag100 and case class MessageRepType(tag: Tag[Int], value:MessageType) is case class MessageRepType(tag: Tag, value:MessageType) and sealed trait MessageType extends Message[Int]):

val sep = System.lineSeparator def convertTag(tag: Tag): Int = tag match {     case Tag100 => 100     case Tag200 => 200 } def convertMessageId(message: MessageId): String = {   val typ = convertTag(message.tag)   val value = message.value match {     case Value100(v) => v   }   s"$typ\t$value" } val id = convertMessageId(message.id) def convertType(message: MessgeRepType): String = {   val typ = convertTag(message.tag)   val value = message.value match {// I would put typeCode to MessageType, but it is not there, so pattern matching     case TYPE1 => TYPE1.typeCode     case TYPE2 => TYPE2.typeCode   }   s"$typ\t$value" } val typ = convertType(message) val message: ABCMessage = ABCMessage(MessageId(Tag100, Value100("abc"),MessageRepType(Tag200, TYPE1)) val messageAsString = Seq("type\tvalue", id, typ).mkString(sep) println(messageAsString) 

Answers 2

A different approach as still not sure what you want to achieve. The other answer with pattern matching is what I would prefer, more idiomatic.

You can use something like a simplified the visitor pattern (removed the irrelevant parts):

trait Show {   def show: String }  sealed trait Tag extends Show {   override def show: String = this.getClass.getSimpleName.init }  //object Tag {   case object Tag100 extends Tag   case object Tag200 extends Tag //} 

This way you can show the tags like this:

Tag100.show // Tag100 

The case classes can also implement show:

sealed trait Value[+A] extends Show {   def v: String   override def show: String = v } case class Value100(v: String) extends Value[String] 

You can use this in other methods too to implement the printing you want:

def convertMessageId(message: MessageId): String = {   val typ = message.tag.show   val value = message.value.show   s"$typ\t$value" } val id = convertMessageId(message.id) def convertType(message: MessgeRepType): String = {   val typ = message.tag.show   val value = message.value.show   s"$typ\t$value" }  val message: ABCMessage = ABCMessage(MessageId(Tag100, Value100("abc"),MessageRepType(Tag200, TYPE1)) val messageAsString = Seq("type\tvalue", id, typ).mkString(sep) println(messageAsString) 

If type safety and easy, generic usage is also important, take a look at Shapeless' offerings and this blog post.

If type safety is not so important, maybe for your use case it is enough to know that case classes implement Product, so you can visit them one-by-one and use its content.

Alternative solution might be to convert your datastructure to for example JSON (there are many Scala libs for that) and use that for further processing. Still generic, but not type-safe.

(This question might also be relevant.)

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment