views:

450

answers:

2

I'm using Scala 2.8 and defining an Enumeration like this:

object Stooges extends Enumeration {
  type Stooge = Value
  val Larry, Curly, Moe = Value
}

And I want to add a method to this Enumeration that cycles to the "next" stooge. I can define such a method outside Stooges and this works in a test program just fine:

def nextStooge(v:Stooges.Stooge):Stooges.Stooge =
  Stooges((v.id+1) % Stooges.values.size)

What I'd really like is to add this method to Stooges and I have tried doing such a thing (using both Stooges.Stooge and Stooges.Value). Those both compile. But running a program like this:

import Stooges._
object App extends Application {
  println(Stooges.nextStooge(Larry))
}

yields:

Exception in thread "main" java.lang.ExceptionInInitializerError
        at demo.App.main(Stooges.scala)
Caused by: java.lang.IllegalArgumentException: wrong number of arguments
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:592)
        at scala.Enumeration$$anonfun$scala$Enumeration$$nameOf$2.apply(Enumeration.scala:176)
        at scala.Enumeration$$anonfun$scala$Enumeration$$nameOf$2.apply(Enumeration.scala:171)
        at scala.collection.TraversableLike$WithFilter$$anonfun$foreach$1.apply(TraversableLike.scala:1200)
        at scala.collection.IndexedSeqLike$class.foreach(IndexedSeqLike.scala:85)
        at scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:20)
        at scala.collection.TraversableLike$WithFilter.foreach(TraversableLike.scala:1199)
        at scala.Enumeration.scala$Enumeration$$nameOf(Enumeration.scala:171)
        at scala.Enumeration$Val.toString(Enumeration.scala:237)
        at java.lang.String.valueOf(String.java:2615)
        at java.io.PrintStream.print(PrintStream.java:616)
        at java.io.PrintStream.println(PrintStream.java:753)
        at scala.Console$.println(Console.scala:198)
        at scala.Predef$.println(Predef.scala:152)
        at demo.App$.<init>(Stooges.scala:14)
        at demo.App$.<clinit>(Stooges.scala)

Is this a bug or just a bad idea?

+3  A: 

This works for me:

scala> object Stooges extends Enumeration {
     |   type Stooge = Value
     |   val Larry = Value("Larry")
     |   val Curly = Value("Curly")
     |   val Moe = Value("Moe")
     |
     |   def nextStooge(v:Stooges.Stooge) = Stooges((v.id+1) % Stooges.maxId)
     | }
defined module Stooges

scala>

scala> import Stooges._
import Stooges._

scala> nextStooge(Larry)
res0: Stooges.Value = Curly

scala> nextStooge(Curly)
res1: Stooges.Value = Moe

scala> nextStooge(Moe)
res2: Stooges.Value = Larry

It would be definetively nicer to be able to say Larry.nextStooge instead of nextStooge(Larry). I suppose you have to implement that with a custom sealed class.

Thomas Jung
Indeed, not needing to pass the arg to nextStooge (and just calling it next()) was my original goal. Interesting that this works when specifying each val separately and naming it. I'll play some more.
Alex Miller
+2  A: 

This is a bug. That initalization is doing something awfully strange. I'm going to open a ticket (done, #2827), if none exists.

Daniel
Many thanks....
Alex Miller