-
Notifications
You must be signed in to change notification settings - Fork 97
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
Translate enums with values #19
Comments
How are you going to generate switch statements using this construct? |
@uxmal Short answer - with this approach, we wouldn't. There are plenty of cases today where it is just infeasible to translate all the way down, and we tend to stick to a syntactic translation only. This results in compiler errors in the resulting code quite often that need to be manually fixed, and that's okay. In this case, I personally think it's more important to preserve the values of the "enum" and its behavior than to eschew them in favor of making However, your question got me thinking about an alternative approach. We could translate enums with values to be an abstract class with concrete implementations for each value. Example: public abstract class EnumTest
{
public static readonly EnumTest A = new EnumTest_A();
public static readonly EnumTest B = new EnumTest_B();
protected EnumTest(int value)
{
this.Value = value;
}
public int Value { get; }
public class EnumTest_A : EnumTest
{
public EnumTest_A()
: base(1)
{
}
}
public class EnumTest_B : EnumTest
{
public EnumTest_B()
: base(2)
{
}
}
} Then, switch could be altered to use pattern matching on the type: var value = DateTime.Now.Second % 2 == 0 ? EnumTest.A : EnumTest.B;
switch (value)
{
case EnumTest.EnumTest_A:
Console.WriteLine("A");
break;
case EnumTest.EnumTest_B:
Console.WriteLine("B");
break;
} Note that with the sealed class approach, you could do pattern matching on the value, if that works for your use case: var value = DateTime.Now.Second % 2 == 0 ? EnumTest.A : EnumTest.B;
switch (value)
{
case { Value: 1}:
Console.WriteLine("A");
break;
case { Value: 2}:
Console.WriteLine("B");
break;
} We don't do any kind of symbol resolution to know that this would need pattern matching, so either approach would have to be done manually by the user... but it's certainly an option. I'm thinking we can have three configurable approaches for how to treat enums with values:
And then it's up to the user of JavaToCSharp to decide how they want to translate it, until C# adds proper discriminated unions. If anyone has any other ideas without involving symbol resolution, let me know! |
Also my last example clearly could be rewritten as a standard enum with an int value... so pretend there's other fields there 😄 |
Fourth option, for those running C#9... we could take the approach from the link I posted about discriminated unions, and make them records inside an abstract class: abstract partial class Shape
{
public record Rectangle(float Width, float Length) : Shape;
public record Circle(float Radius) : Shape;
} |
... actually I'm not sure if that has the same semantics. Still thinking about this... |
Hi, just found this project (got tons of old Java utils for small projects and was looking to convert one that happened to use this). Since all Enum's extend java.lang.Enum that has an ordinal() final method, shouldn't that be considered the route to handling the switches if one wants to re-do translations often (or are the conversions more looking at idiomatic C# rather than good/easy conversion?), a shim of that one could of course. As for abstract classes you kinda would need support translating like that anyhow, the code i was looking to translate looks like this with enums implementing abstract methods.
|
@whizzter Thanks for the real-world example. I had never (or rarely) encountered abstract methods in enums but you're right, that strengthens the case for the abstract class approach. |
Well to be honest I'm not sure how much this is used in other places, It's was kinda specific but quite smooth solution to binding stuff for this interpreter. I guess this is the kind of places where you need to consider if Java compatibility or C# target code elegantness/idiomaticness is more important. (Nr 1 is more important if you want to continually translate some cross-language project , Nr 2 if you want to migrate). Might even be that having 2 variants depending on the source can be the right choice? Abstract being enforced for compatible conversions where required, but a leaner method chosen for non-tricky situations or explicitly for a simpler idiomatic migration-mode. |
This enum was converted to a C# enum with bit shifting and extension methods:
The original Java code:
For enums with more complicated private fields, I had to convert them into abstract classes:
The original Java code:
Just my 2 cents. |
I think we can translate enums with values to be sealed classes with
public static readonly
members.Example:
Output:
The text was updated successfully, but these errors were encountered: