Elements 2513 and 2521: Setting enum value from String

This is another thing that changed from Elements 2409 to 2513 and 2521, and currently breaks my code.

I need to assign a value to some enum, given the string representation of enum value. So far, I solved the problem by defining

{$IFDEF JAVA}
type
  EnumType<T> = public T;
{$ELSE} // for .NET
type
  EnumType<T> = public extension class(T)
  where T is record;
  public
    class method ValueOf(aStr: String): T;
    begin
      exit T(&Enum.Parse(typeOf(T), aStr));
    end;
  end;
{$ENDIF}

This allowed me to make the assignments such as

SomeEnumType e := EnumType<SomeEnumType>.ValueOf("SomeStringValue");

I admit the solution is somewhat tricky, but it worked very well for any enum type, without the need to tamper with typeOf(), strange methods with many arguments, IFDEFS or similar. But now it does not compile any more and I cannot think of a similarly simple solution. Any ideas or suggestions? Is there any existing solution that I keep overlooking in the documentation? If not, I suggest a new feature: platform-independent mapping from string to enum value.

No ideas, no suggestions, no solutions?

Ok, let me then explicitly formulate

Feature request for Elements:

Platform-independent conversion from string to enum value, for any enum type.

What exactly fails? the Java or the .NET version, and whats the error?

Good idea yes.

Thanks, logged as bugs://84492

JAVA fails at the call

SomeEnumType e := EnumType<SomeEnumType>.ValueOf("SomeStringValue");

with

Error (E43) No static member "ValueOf" on type "EnumType<not nullable nullable SomeEnumType>"

Again: this this did work in Elements 2409.

Ah yes. What happened is that enums were inconsistent between Java ands the other platforms, because they mapped to reference types in Java, but where simple numeric value types every where else — and we made that consistent across platforms. As a side effect you might be losing access to Java-specifc APIs on the enum type, yes :(.

You can still force an enum own there Java platform to be based on the Java enum class, by specifying an ancestor for the enum (just as you can do X = public enum on Int64, you can do Y = public enum of java.lang.Enum. That will give you back the Java APIs (but at the cost of less platform compatibility.

Hopefully once we implement the above feature request that will make ti easier to have consistent enums and access to their string representation, across platforms.

I use the following code to do the conversion on Island/Windows, don’t know if it is the good way but just FYI
method AsEnum(const aStr: not nullable String): Tuple of (Boolean, nullable T);
begin
result := (false, nil);
if not typeOf(T).IsEnum then exit;
for each el in typeOf(T).Constants do begin
if el.Name.Equals(aStr) then exit (true, T(el.Value));
end;

Is there anything new with this issue (that is, platform-independent conversion of string to any enum type, bugs://84492)?

I still couldn’t find a satisfactory solution in newer versions of Elements and I am stuck with Elements 2409 because of that. Unfortunately, @wuping’s solution does not work on .NET and java.

so as a quick “this works today” fix. You can use “enum of Enum” on Java to make it work on Java again.
ie:

type 
  Myenum = (a,b,c) of java.lang.Enum;

This makes it revert to to the old behavior. I have to do some thinking on how to best solve this properly.

1 Like

as I said in June :wink:

Carlo and Marc, thank you for taking this issue in consideration.

Yes, I am aware of the enum of java.lang.Enum quick fix, but then, are you aware of the consequences it has for a cross-platform .NET/java class library? Each and every enum would have to be declared as:

type 
{$IFDEF JAVA}
  Myenum = public enum (a,b,c) of java.lang.Enum;
{$ELSE}
  Myenum = public enum (a,b,c);
{$ENDIF}

(or such, I didn’t check the syntax).

This is ugly, inconvenient and inappropriate for a high-level language that has a built-in support of enums.

Also, I would like to point out the lack and inconnsitency of enumeration functionality, the issue already raised in Can you enumerate an enum?

for el in Myenum do ... does not work on any of .NET or java;

for el: Myenum := low(Myenum) to high(Myenum) do ... works on .NET but fails to compile on java;

for el: Integer := low(Myenum) to high(Myenum) do ... compiles in java, but returns integers rather than strings.

IMO, a more consistent behavior should be provided for a cross-platform context.

I agree, and it’s on my list, but this is a very tricky issue to solve properly.

One further hac.workaroud rtf make this easier might be:

type 
{$IFDEF JAVA}
  EnumBase = public java.lang.Enum;
{$ELSE}
  EnumBase = Int32;
{$ENDIF}
  Myenum = public enum (a,b,c) of EnumBase;

this way, you only need an ifdef in one place, for the base type. still ugly, I agree, but better.

Great idea, thank you. This may even work and one $IFDEF instead of many would be perfectly acceptable.

However, changing enums from ... of Integer to ... of java.lang.Enum seems to create problems elsewhere, please see my next post.

1 Like