Tuesday, April 20, 2010

Scala dependent method type

Scala dependent type exception

I'm building a simple JSF-3 web application that implements backing beans in Scala 2.8 One bean includes Enumeration properties that a JSF web-form exposes to clients via a combo-box control configured via a key-value map.

    <h:selectOneMenu id="patronType" value="#{sampleBean.patronType}">
        <f:selectItems value="#{sampleBean.patronTypes}" />
    </h:selectOneMenu>

The sampleBean's definition includes patronType and paronTypes properties which are Enumeration subtypes.

object PatronType extends Enumeration {
  val Student, Faculty, Other = Value
}

...

@ManagedBean
@RequestScoped
class SampleBean extends InjectMeBean {
  private def enumToMap( enum:Enumeration ):java.util.Map[String,Enumeration#Value] =
        ((new ImmutableMap.Builder[String,Enumeration#Value]) /: enum.values) (
      (builder,member) => builder.put( member.toString, member )
    ).build

...
  @reflect.BeanProperty
  var patronType:PatronType.Value = PatronType.Student

  @reflect.BeanProperty
  val patronTypes:java.util.Map[String,Enumeration#Value] = enumToMap( PatronType )
}

I originally defined the patronTypes property as a mapping from String to PatronType.Value.

  @reflect.BeanProperty
  val patronTypes:java.util.Map[String,PatronType.Value] =
               ((new ImmutableMap.Builder[String,PatronType.Value]) /: enum.values) (
        (builder,member) => builder.put( member.toString, member )
      ).build

I introduced the enumToMap method to share that code block between several similar properties with different Enumeration types. Unfortunately - a subtype-specific enumToMap implementation has on output type that depends on an input parameter.

scala> def enumToMap( enum:Enumeration ):java.util.Map[String,enum.Value] =
     |         ((new ImmutableMap.Builder[String,enum.Value]) /: enum.values) (
     |       (builder,member) => builder.put( member.toString, member )
     |     ).build
<console>:6: error: illegal dependent method type
       def enumToMap( enum:Enumeration ):java.util.Map[String,enum.Value] =
                      ^    

I tried several variations on this theme, but finally settled on the enumToMap implementation that just leverages the Enumeration#Value base type. I googled around while working on this code, and stumbled across the fact that scala includes limited experimental support for dependent method types - that will be very cool if it evolves to production status.

Scala's instance-attached nested types have advantages, but they feel alien to an experienced java developer like me.

scala> class A {
     | var a = "A"
     | class B {
     | var b = "B"
     | }
     | var b = new B
     | }
defined class A

scala> val a1 = new A
a1: A = A@6489f0

scala> val a2 = new A
a2: A = A@15c44d6

scala> a1.b = a2.b
<console>:9: error: type mismatch;
 found   : a2.B
 required: a1.B
       a1.b = a2.b
                 ^