tags:

views:

147

answers:

2

ZeroC Ice for Java translates every Slice interface Simple into (among other things) a proxy interface SimplePrx and a proxy SimplePrxHelper. If I have an ObjectPrx (the base interface for all proxies), I can check whether it actually has interface Simple by using a static method on SimplePrxHelper:

val obj : Ice.ObjectPrx = ...;        // Get a proxy from somewhere...

val simple : SimplePrx = SimplePrxHelper.checkedCast(obj);
if (simple != null)
    // Object supports the Simple interface...
else
    // Object is not of type Simple...

I wanted to write a method castTo so that I could replace the second line with

val simple = castTo[SimplePrx](obj)

or

val simple = castTo[SimplePrxHelper](obj)

So far as I can see, Scala's type system is not expressive enough to allow me to define castTo. Is this correct?

A: 

You can get something like what you want with structural types:

def castTo[A](helper: { def checkedCast(o: Object): A })(o: Object) = {
  helper.checkedCast(o)
}
class FooPrx { }
object FooPrxHelper {
  def checkedCast(o: Object): FooPrx = o match {
    case fp : FooPrx => fp
    case _ => null
  }
}

scala> val o: Object = new FooPrx
o: java.lang.Object = FooPrx@da8742

scala> val fp = castTo(FooPrxHelper)(o)
fp: FooPrx = FooPrx@da8742
Rex Kerr
I did think of this, but unfortunately `FooPrxHelper` is defined as a class (in Java). I got "FooPrxHelper is not a value".
Alexey Romanov
@Alexey You could wrap everything by hand (or not really by hand--write something that will do the automatic code generation for you).
Rex Kerr
+4  A: 

Should be able to do something with implicits, along these lines:

object Casting {
  trait Caster[A] {
    def checkedCast(obj: ObjectPrx): Option[A]
  }

  def castTo[A](obj: ObjectPrx)(implicit caster: Caster[A]) =
    caster.checkedCast(obj)

  implicit object SimplePrxCaster extends Caster[SimplePrx] {
    def checkedCast(obj: ObjectPrx) = Option(SimplePrxHelper.checkedCast(obj))
  }
}

Then you just bring things into scope where you want to use them:

package my.package

import Casting._

...
  def whatever(prx: ObjectPrx) {
    castTo[SimplePrx](prx) foreach (_.somethingSimple())
  }
...
RM
For that matter, if you don't like all the "implicit objects" lying around, you could do it this way: def castTo[A](obj: ObjectPrx)(implicit mfst: ClassManifest[A]) = { val helperClass = Class.forName(mfst.erasure.getName + "Helper"); val method = helperClass.getMethod("checkedCast", classOf[ObjectPrx]); Option(method.invoke(null, obj)).asInstanceOf[Option[A]] }..plus exception handling of course. Not as type safe thanks to the erased cast, and rather slower, but only one named thing.Edit: eek, formatting fail!
RM