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

How could I pass something like Enum.Type as function parameter in dart lang? #53771

Closed
HaloWang opened this issue Oct 17, 2023 · 5 comments
Closed

Comments

@HaloWang
Copy link

What I want in short:

enum Foo {
  a,
}

enum Bar {
  b
}

/// define
void anyFunction(enumType: Enum.Type, enumStringValue:String) {
  if (enumType == Foo) {
    final value = Foo.values.byName(enumStringValue);
    print("greet, I got a Foo.a");
    return;
  }

  if (enumType == Bar) {
    final value = Bar.values.byName(enumStringValue);
    print("greet, I got a Bar.b");
    return;
  }
}

/// calling
anyFunction(Foo, "a"); // greet, I got a Foo.a
anyFunction(Bar, "b"); // greet, I got a Bar.b
anyFunction(Foo, "b"); // throw

I'm trying to sync enum between different flutter engines but I found it is hard for me to create an Enum by string. I must write different method for different enum which is a little "ugly".

By the way, could I pass something like Class.Type?

@ykmnkmi
Copy link
Contributor

ykmnkmi commented Oct 17, 2023

enum Foo { a }

enum Bar { b }

/// define
void anyFunction<T extends Enum>(List<T> values, String enumStringValue) {
  var value = values.byName(enumStringValue);
  print('greet, I got a $value');
}

/// calling

void main() {
  anyFunction(Foo.values, 'a'); // greet, I got a Foo.a
  anyFunction(Bar.values, 'b'); // greet, I got a Bar.b
  anyFunction(Foo.values, 'b'); // throw
}

@HaloWang
Copy link
Author

HaloWang commented Oct 17, 2023

enum Foo { a }

enum Bar { b }

/// define
void anyFunction<T extends Enum>(List<T> values, String enumStringValue) {
  var value = values.byName(enumStringValue);
  print('greet, I got a $value');
}

/// calling

void main() {
  anyFunction(Foo.values, 'a'); // greet, I got a Foo.a
  anyFunction(Bar.values, 'b'); // greet, I got a Bar.b
  anyFunction(Foo.values, 'b'); // throw
}

Thank you for your inspiration!

@eernstg
Copy link
Member

eernstg commented Oct 17, 2023

@ykmnkmi's solution is quite nice, because it avoids relying on objects of type Type.

It is normally not recommended to use objects of type Type for several reasons. In particular, a Type can be used to recognize a type, but it does not allow us to recognize subtypes, and object-oriented code should normally allow any object with a given static type T to have a run-time type which is a subtype of T.

Nevertheless, in this particular case we're dealing with enumerated types, and they are special in that they never have any subtypes (other than bottom types like Never, but they will never be the type of an actual object).

So let's try to use Type objects anyway:

enum Foo { a }
enum Bar { b }

const enumValues = <Type, List<Enum>>{
  Foo: Foo.values,
  Bar: Bar.values,
};

T anyFunction<T extends Enum>(String enumStringValue) =>
  enumValues[T]!.byName(enumStringValue) as T;

void main() {
  Foo foo = anyFunction("a"); // OK.
  Bar bar = anyFunction("b"); // OK.
  Foo badFoo = anyFunction("b"); // Throws.
}

The crucial trade-off is that you need to have a "registry" (here we're using enumValues) where you can find all the enum values that you'd ever want to look up based on their name. If it's OK for you to have such a registry (and you can populate it dynamically if you can't create it as a constant value), then the resulting anyFunction can use a type argument to determine the desired enum type, and that type argument can again be provided by type inference. That's the reason why we can look up Foo.a simply by calling anyFunction("a").

I'll close this issue because it doesn't report on anything that doesn't work as intended.

@eernstg eernstg closed this as completed Oct 17, 2023
@ykmnkmi
Copy link
Contributor

ykmnkmi commented Oct 18, 2023

Static interfaces would make this much simpler in Dart.

@eernstg
Copy link
Member

eernstg commented Oct 18, 2023

Static interfaces: Probably similar to some proposals in dart-lang/language#356.

That would indeed give us a mapping like enumValues as a language feature, rather than having us write it and maintain it ourselves.

However, we should keep in mind that some applications are large, and size matters. It is an undecidable property of a program (in Dart and in many other languages) exactly which values any given type parameter will have at run time, and this means that we might ask the language to store a huge map like enumValues because there are a large number of enum values altogether in the program, and we can't determine at compile time which ones will be looked up using this mechanism. If we write enumValues manually then we can just include the values we think we need, which might be a much smaller set, and then it will be a regular bug if we forget some of them. As usual, the trade-offs aren't trivial. ;-)

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

No branches or pull requests

3 participants