Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enumeration.values is not referentially transparent #4334

Closed
scabug opened this issue Mar 12, 2011 · 4 comments
Closed

Enumeration.values is not referentially transparent #4334

scabug opened this issue Mar 12, 2011 · 4 comments

Comments

@scabug
Copy link

scabug commented Mar 12, 2011

=== What steps will reproduce the problem (please be specific and use wikiformatting)? ===
In the interpreter, after loading this code:

object MyEnum extends Enumeration {
    type MyEnum = Value
    val A, B = Value
}

val values1 = MyEnum.values
val values2 = MyEnum.values
values1 == values2

gives the following output

scala> :load ../bug2.scala
Loading ../bug2.scala...
defined module MyEnum
values1: MyEnum.ValueSet = MyEnum.ValueSet(A, B)
values2: MyEnum.ValueSet = MyEnum.ValueSet(A, B, Value)
res18: Boolean = false

scala> MyEnum.values
res19: MyEnum.ValueSet = MyEnum.ValueSet(A, B, Value)

scala> MyEnum.values
res20: MyEnum.ValueSet = MyEnum.ValueSet(A, B, Value)

=== What is the expected behavior? ===
MyEnum.values should be referentially transparent:
MyEnum.values == MyEnum.values.

=== What do you see instead? ===
MyEnum.values gets an additional member named Value after the first use.
=== Additional information ===
While I can understand that the implementation of Enumeration is quite complex, I'm worried that it still doesn't work. Additionally, the documentation should probably explain that it performs evil magic and should be used with care, i.e. by following the given pattern quite closely. A specification of "quite closely" would be most appreciated.

=== What versions of the following are you using? ===

  • Scala: 2.8.0, 2.8.1
  • Java:
# java -version
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02, mixed mode)
  • Operating system: Ubuntu linux 9.10
@scabug
Copy link
Author

scabug commented Mar 12, 2011

Imported From: https://issues.scala-lang.org/browse/SI-4334?orig=1
Reporter: @Blaisorblade
See #5211

@scabug
Copy link
Author

scabug commented Mar 12, 2011

@Blaisorblade said:
Part of the problem might stem from the fact that the method

  protected final def Value: Value = Value(nextId)     

(declared [https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_8_1_final/src//library/scala/Enumeration.scala#L131 here])
is not filtered out by populateNameMap:

    val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty && classOf[Value].isAssignableFrom(m.getReturnType))

each of those methods is afterward invoked by populateNameMap; the Value method will then be invoked, it will construct an instance of Val, and the Val constructor will reset vsetDefined altering the return value of values (even if its definition seems immutable, it is not).
To complete the picture, populateNameMap is only called indirectly through Val.toString -> Enumeration.nameOf.

Problems:

  1. The Val constructor should not reset vsetDefined, it should rather throw an exception if vsetDefined was true, i.e. values had been invoked.

  2. populateNameMap should filter out Value, and a big fat warning should be added against adding new method with the same signature without fixing populateNameMap. Alternatively, populateNameMap could use getDeclaredMethods on the class of the actual enumeration, which filters out inherited methods.

  3. Of course, this does not solve the fragility problem: if the Enumeration instance declares a method like randomElem(): Value, it will mistaken for an enumeration entry. As already asked, this "evil magic" should be documented.

Should I provide a patch for 1) and 2)?

@scabug
Copy link
Author

scabug commented Mar 12, 2011

@harrah said:
The immediate issue is a duplicate of #3687. I understand the general concern about Enumeration, but this should be discussed on the mailing lists. This subject has been discussed before, so you are most likely to succeed by understanding those discussions and giving concrete proposals. (I am not the final authority here- these are suggestions.)

@scabug
Copy link
Author

scabug commented Mar 13, 2011

@Blaisorblade said:
Sorry, my bad for this dup, and thank you very much for the helpful answer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant