I am trying to implement C#'s ExpandoObject
-like class in Scala. This is how it is supposed to work:
val e = new ExpandoObject
e.name := "Rahul" // This inserts a new field `name` in the object.
println(e.name) // Accessing its value.
Here is what I have tried so far:
implicit def enrichAny[A](underlying: A) = new EnrichedAny(underlying)
class EnrichedAny[A](underlying: A) {
// ...
def dyn = new Dyn(underlying.asInstanceOf[AnyRef])
}
class Dyn(x: AnyRef) extends Dynamic {
def applyDynamic(message: String)(args: Any*) = {
new Dyn(x.getClass.getMethod(message,
args.map(_.asInstanceOf[AnyRef].getClass) : _*).
invoke(x, args.map(_.asInstanceOf[AnyRef]) : _*))
}
def typed[A] = x.asInstanceOf[A]
override def toString = "Dynamic(" + x + ")"
}
class ExpandoObject extends Dynamic {
private val fields = mutable.Map.empty[String, Dyn]
def applyDynamic(message: String)(args: Any*): Dynamic = {
fields get message match {
case Some(v) => v
case None => new Assigner(fields, message).dyn
}
}
}
class Assigner(fields: mutable.Map[String, Dyn], message: String) {
def :=(value: Any): Unit = {
fields += (message -> value.dyn)
}
}
When I try to compile this code, I get a StackOverflowError
. Please help me get this work. :) Thanks.
Got it working after some playing around. The solution isn't typesafe though (which in this case does not matter, since the point of this little utility is to work around type system. :-)
trait ExpandoObject extends Dynamic with mutable.Map[String, Any] {
lazy val fields = mutable.Map.empty[String, Any]
def -=(k: String): this.type = { fields -= k; this }
def +=(f: (String, Any)): this.type = { fields += f; this }
def iterator = fields.iterator
def get(k: String): Option[Any] = fields get k
def applyDynamic(message: String)(args: Any*): Any = {
this.getOrElse(message, new Assigner(this, message))
}
}
implicit def anyToassigner(a: Any): Assigner = a match {
case x: Assigner => x
case _ => sys.error("Not an assigner.")
}
class Assigner(ob: ExpandoObject, message: String) {
def :=(value: Any): Unit = ob += (message -> value)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With