Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Treating a constructor as a function in Scala - how to put constructors in a map?

I need to parse some messages. The first 4 bytes of a message identify the type of message, so, using that, I can instantiate an object of the proper type. To make this an efficient operation, I thought I would create a hash map where they key is the first 4 bytes, and the value is the object constructor. I can just look up the constructor and invoke it.

After all, constructors are just functions, and there shouldn't be any problem putting functions in a map. It turns out that I am having some difficulty with this because I don't know how to express the reference to the constructor properly.

To get concrete with a simplified example, suppose we have a message base class, MsgBase, and a couple subclasses, MsgA and MsgB. If I create a companion object for each of the messages and put a factory function into it, I can make the array without any problem using those functions.

Here is a simplified sample which takes the message as a string.

class MsgBase(message: String) { }

class MsgA(message: String) extends MsgBase(message) { }

object MsgA  { def makeIt(message: String): MsgA = new MsgA(message)  }

and where MsgB is similar. Then I can make the map:

val cm = Map[String, (String) => MsgBase]("a" -> MsgA.makeIt, "b" -> MsgB.makeIt)

val myMsg = cm("a")("a.This is the message")

It seems like I should be able to refer to the message object constructor directly in the expression building the map, rather than using the trivial function in the companion object, but I haven't figured out any way to express that. Is there a way?

like image 656
Willard Avatar asked May 29 '11 06:05

Willard


People also ask

How do you call a constructor from a function?

Invoking a constructor from a method No, you cannot call a constructor from a method. The only place from which you can invoke constructors using “this()” or, “super()” is the first line of another constructor. If you try to invoke constructors explicitly elsewhere, a compile time error will be generated.

What is constructor explain different types of constructor in Scala?

Scala constructor is used for creating an instance of a class. There are two types of constructor in Scala – Primary and Auxiliary. Not a special method, a constructor is different in Scala than in Java constructors. The class' body is the primary constructor and the parameter list follows the class name.

How do you make a Scala constructor private?

In Scala, only a primary constructor is allowed to invoke a superclass constructor. In Scala, we are allowed to make a primary constructor private by using a private keyword in between the class name and the constructor parameter-list.

Do Scala objects have constructors?

By default, every Scala class has a primary constructor. The primary constructor consists of the constructor parameters, the methods called in the class body, and the statements executed in the body of the class.


3 Answers

Try

"a" -> (new MsgA(_))

(all parentheses are needed).

Even if this didn't work, you could of course always define the function explicitly:

"a" -> ( (s: String) => new MsgA(s) )
like image 133
Rex Kerr Avatar answered Oct 04 '22 14:10

Rex Kerr


For this case it would be better to use case classes, which automatically provide you functions for creating new objects.

scala> case class MsgA(message: String) extends MsgBase(message)
scala> case class MsgB(message: String) extends MsgBase(message)

So you can refer them just by name, without any syntactical overhead

scala> val m = Map("a"->MsgA, "b"->MsgB)
m: scala.collection.immutable.Map[java.lang.String,scala.runtime.AbstractFunction1[java.lang.String,Product with MsgBase]] = Map((a,<function1>), (b,<function1>))

scala> m("a")("qqq")                              
res1: Product with MsgBase = MsgA(qqq)

As an alternative approach you can create companion object with overrided apply method by hand. For details see Programming scala, chapter 6

like image 27
CheatEx Avatar answered Oct 04 '22 14:10

CheatEx


val cm = Map[String, (String) => MsgBase]("a" -> (new MsgA(_)), "b" -> (new MsgB(_)))
like image 30
Kim Stebel Avatar answered Oct 04 '22 13:10

Kim Stebel