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

ImmutableList<E> enumUniverse() #1022

Closed
gissuebot opened this issue Oct 31, 2014 · 19 comments
Closed

ImmutableList<E> enumUniverse() #1022

gissuebot opened this issue Oct 31, 2014 · 19 comments

Comments

@gissuebot
Copy link

Original issue created by wasserman.louis on 2012-06-02 at 07:08 PM


In the JDK, EnumSet and EnumMap use internal magic to get access to a shared array of the "universe" of constants for that enum.

I'd like to see something along the lines of

  ImmutableList<E> Enums.enumConstants(Class<E> clazz)

that provides safe, preferably globally cached access to the enum constants for a class, either by using reflection to cheat access to clazz.getEnumConstantsShared(), or by sun.misc.SharedSecrets like EnumSet itself does, or by doing its own caching somehow.

(I was attempting to write a DiscreteDomain for enum types, and copying the universe array grated slightly.)

@gissuebot
Copy link
Author

Original comment posted by neveue on 2012-06-03 at 01:45 AM


That would be nice. Reminds me of issue 777.

@gissuebot
Copy link
Author

Original comment posted by kevinb@google.com on 2012-06-04 at 03:28 PM


(No comment entered for this change.)


Labels: -Type-Enhancement, Type-Addition

@gissuebot
Copy link
Author

gissuebot commented Oct 31, 2014

Original comment posted by j...@nwsnet.de on 2012-06-05 at 03:23 PM


Sounds nice. Can't it return ImmutableSortedSet instead? The enum constants should be both ordered and unique (and immutable).

@gissuebot
Copy link
Author

Original comment posted by wasserman.louis on 2012-06-05 at 03:49 PM


It could, I guess? I feel like we've had mixed feelings about the Comparable instance of enums before, which doesn't always make contextual sense, and I feel like the get(int) operation is a relatively high priority. We already sort of have immutable enum sets, but they're really just thin wrappers around EnumSet.

The use case I specifically have in mind is, for example, reimplementing EnumMultiset as the ImmutableList<E> universe and an int[] instead of an EnumMap to wrapper objects.

@gissuebot
Copy link
Author

Original comment posted by kevinb@google.com on 2012-06-19 at 05:47 PM


Set seems correct over List, to me. SortedSet I don't care for, since we've observed that 90% of enums have no meaningful order, and the other 10% seem to have it but don't even bother to specify it.

Is this issue request much different from Sets.immutableEnumSet(EnumSet.allOf(MyEnum.class))?


Status: Acknowledged

@gissuebot
Copy link
Author

Original comment posted by wasserman.louis on 2012-06-19 at 11:55 PM


Well, for the use cases I had in mind, indexed random access was specifically necessary, meaning there had to be an accessible List. (Perhaps that's better implemented on a package-private basis, though, since I was basically thinking of it as a helper for enum-based collections.)

That's not equivalent to Sets.immutableEnumSet or the like.

@gissuebot
Copy link
Author

Original comment posted by wasserman.louis on 2012-06-22 at 12:45 PM


Alternative specific example: writing a DiscreteDomain for enum types, and implementing next(E). You need indexed access on the enum type to get the next value in the canonical ordering.

Basically -- indexed access is the one thing that you can't already get from EnumSet.

@gissuebot
Copy link
Author

Original comment posted by SeanPFloyd on 2012-06-22 at 02:50 PM


Regarding DiscreteDomain.next():

can't that be solved by this existing (admittedly ugly) code?

@Override
public E next(E value) {
    // bounds check omitted for laziness
    return value.getDeclaringClass().getEnumConstants()[value.ordinal()+1];
}

@gissuebot
Copy link
Author

Original comment posted by wasserman.louis on 2012-06-22 at 02:58 PM


Only at the expense of computing a fresh copy of the array each time. getEnumConstants() can't exactly let you modify the backing copy, so you're paying cost linear in the size of the entire enum every time.

@gissuebot
Copy link
Author

Original comment posted by SeanPFloyd on 2012-06-22 at 03:12 PM


Ah, I see. I forgot that non-empty arrays can't be made immutable.

@gissuebot
Copy link
Author

Original comment posted by kevinb@google.com on 2012-06-22 at 06:15 PM


So you store that array in a field, that's all.

This doesn't seem like a general-public use case, but a library-implementors' use case.

@gissuebot
Copy link
Author

Original comment posted by kevinb@google.com on 2012-06-22 at 06:16 PM


(No comment entered for this change.)


Status: Research

@gissuebot
Copy link
Author

Original comment posted by wasserman.louis on 2012-06-22 at 06:18 PM


Well, if you're extremely into performance, you can use some tricky hacks to reflectively access the class's internal shared copy of the array -- the array that getEnumConstants() is copied from.

I was hoping that we could factor out those details and provide an API with a safe interface to that array -- thus, an ImmutableList.

@gissuebot
Copy link
Author

Original comment posted by kevinb@google.com on 2012-06-22 at 06:55 PM


I still don't understand. If I want the enum universe as an ImmutableList, I can already get it with ImmutableList.copyOf(MyEnum.values()). Are you really trying to optimize that, or worry about caching that for the user (who can cache it herself)?

@gissuebot
Copy link
Author

Original comment posted by wasserman.louis on 2012-06-22 at 06:59 PM


Well. Technically, the Class object (you know, MyEnum.class) already does the caching itself internally. I want to provide the magic to safely access that cached value.

@gissuebot
Copy link
Author

Original comment posted by cpovirk@google.com on 2012-06-25 at 07:17 PM


Pulling in comments from http://codereview.appspot.com/6333058/ ...

"""
Essentially, the goal is to provide a safe, transparent, package-private way to
mirror the tricks used by EnumSet and EnumMap to get access to the shared array
of enum constants held in their Class object. On supported platforms -- that
is, wherever we can get the JavaLangAccess interface to the Java internals --
Enums.getUniverse runs in constant time, independent of the number of enum
values.

Ideally, this can be used to reimplement enum collection magic without going
through EnumSet or EnumMap. For example, EnumMultiset could be implemented with
the ImmutableList<E> and an int[], avoiding the per-element Count object
allocations.
"""

Of course, we could provide the alternative EnumMultiset already, but we'd need to call ImmutableList.copyOf(EnumSet.allOf(MyEnum.class)). That would almost certainly be slower for large enums, but it's not obvious to me that it would be slower, let alone significantly slower, for typical enums. If it is faster, would it pay off over the few dozen users EnumMultiset has? (As always, we can assume that it "should" have more callers than it does, but it's also possible that some of the existing users "should" use ImmutableMultiset.) If any of those users use GWT, will the code-size increase offset any gains?

The fact that EnumSet and EnumMap use this trick is encouraging, but I'm still uncertain about whether it's worth the effort, even with a CL ready.

@gissuebot
Copy link
Author

Original comment posted by wasserman.louis on 2012-06-27 at 01:43 PM


(Another specific application: a DiscreteDomain for enum types. The "next" function requires being able to look up the element with the next-higher ordinal, which can't be done with EnumSet alone.)

@gissuebot
Copy link
Author

Original comment posted by kevinb@google.com on 2012-06-28 at 10:22 PM


That was your original example. I still say that DiscreteDomain can just stash values() in a field and voila.

@gissuebot
Copy link
Author

Original comment posted by wasserman.louis on 2012-07-02 at 09:16 PM


Bleah, I'm really dumb.


Status: Duplicate
Merged Into: #777

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