Skip to content

Add static parse method for Enums #1560

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

Closed
esDotDev opened this issue Apr 5, 2021 · 8 comments
Closed

Add static parse method for Enums #1560

esDotDev opened this issue Apr 5, 2021 · 8 comments
Labels
feature Proposed language feature that solves one or more problems

Comments

@esDotDev
Copy link

esDotDev commented Apr 5, 2021

Currently it's repetitive and verbose when trying to accomplish simple tasks with Enum.

For example, I might have

enum MenuType {
  home,
  search,
  trending,
  settings,
}

And I want to parse that into a query string so I have a link like "#/?menuType=search".

If we look at Kotlin, C# or Swift, they both support this in a straight forward way:

Swift:

MenuType(rawValue: "search")
MenuType.search.rawValue // search

Kotlin:

MenuType.valueOf("search")
MenuType.search.toString() // search

C#

Enum.TryParse("Search", out MenuType enum);
nameof(MenuType.Search) // search

To do this in a highly readable way in dart we need to write boilerplate code for each Enum (and usually import a plugin).

extension MyEnumExt on MyEnum {
  String get name => describeEnum(this);
}

Parsing it the other way is something like:

MenuType fromString(String value, List<MenuType> values, MenuType default) {
  try {
      return values.singleWhere((enumItem) => enumItem.name  == value);
  } on StateError catch (_) {
      return default;
  }
}

Ideally, this would be built into the language and just be as simple as:

MenuType.parse("search") ?? MenuType.home;
MenuType.search.name

Adding .name addresses the toString use case (#1511) but fromString / parse is still cumbersome.

@esDotDev esDotDev added the feature Proposed language feature that solves one or more problems label Apr 5, 2021
@esDotDev esDotDev changed the title Add toString and fromString methods for Enums Add fromString or tryParse method for Enums Apr 6, 2021
@esDotDev esDotDev changed the title Add fromString or tryParse method for Enums Add tryParse method for Enums Apr 6, 2021
@esDotDev esDotDev changed the title Add tryParse method for Enums Add static parse method for Enums Apr 6, 2021
@esDotDev
Copy link
Author

esDotDev commented Apr 6, 2021

Even with the helper plugin we have to write this:

enum SearchCategory {
  All,
  Popular,
}

extension on SearchCategory {
  String get value => describeEnum(this);
}

SearchCategory searchCategoryFromString(String value) {
  return EnumToString.fromString(SearchCategory.values, value) ?? SearchCategory.All;
}

When we ideally could just write something like:

enum SearchCategory {
  @default All,
  Popular,
}

The concrete downside to this are:

  • Increased learning curve for new developers. Every single developer needs to memorize this boilerplate code at some pt. This feels like minutia to some degree. Would be nice if we could all just erase these workarounds from our mind / not teach them in the first place.
  • searchCategoryFromString does not support refactoring well, the enum class can easily get renamed without the fromString getting updated
  • More verbose code examples everywhere enums are serialized, we can't discuss something simple like how to use an enum in the query string, or read/write them to a file, without getting sidetracked into extension methods and external plugins.
  • It contributes to the feeling that enums are a 2nd class citizen / afterthought in dart (just speaking for myself here). Another contributing factor is lack of static methods / extensions on Enums (Static extension methods #723) and the inability to do value-based enums (Allow enum classes to have members #158)

@iamarnas
Copy link

iamarnas commented Apr 6, 2021

@esDotDev Hi,
I personally everywhere use Map they are so useful and flexible :)

enum UserStatus { online, offline }

var userStatus = <UserStatus, String>{
  UserStatus.online: "Online",
  UserStatus.offline: "Offline",
};

String userStatusToString(UserStatus status) {
  return userStatus[status];
  // Another method.
  // return userStatus.values.elementAt(status.index);
}

UserStatus userStatusFromString(String status) {
  bool containsKey(UserStatus key) => userStatus[key].contains(status);
  return userStatus.keys.firstWhere((containsKey));
}

// Status to String.
print(userStatusToString(UserStatus.online));  // -> Online
// Status from String.
print(userStatusFromString("Online")); // -> UserStatus.online

@esDotDev
Copy link
Author

esDotDev commented Apr 6, 2021

Ah nice approach. But still lots of boilerplate, and still not great for refactoring. If you change the name of UserStatus 2 methods and one variable are out of date.

If we had proper value enums, you could write that like this with absolutely no boilerplate and full refactoring support:

enum UserStatus { online = "Online", offline = "Offline"}
...
print(UserStatus.online.value);  // -> Online
print(UserStatus.parse(UserStatus.online.value)); // -> UserStatus.online

Or even:

enum UserStatus { online = 0, offline = 1}
...
print(UserStatus.online.value);  // -> 0
print(UserStatus.parse(UserStatus.online.value)); // -> UserStatus.online

But that is a bit off-topic maybe.

@cadaniel
Copy link

cadaniel commented Apr 6, 2021

I don't think a to/from string explictly are needed, but maybe enum values like Kotlin supports.

https://kotlinlang.org/docs/enum-classes.html#implementing-interfaces-in-enum-classes

They can represent arbitrary types of data without needing to be string specific.

@esDotDev
Copy link
Author

esDotDev commented Apr 6, 2021

Right, that would be great, something like:

SearchCategory.parse("all")
SearchCategory.all.value // all

It would still be nice to have implicit support for string based values, so we don't need to write:

enum SearchCategory {
  all = "all",
  popular = "popular",
}

@cadaniel
Copy link

cadaniel commented Apr 6, 2021

Right, that would be great, something like:

SearchCategory.parse("all")
SearchCategory.all.value // all

It would still be nice to have implicit support for string based values, so we don't need to write:

enum SearchCategory {
  all = "all",
  popular = "popular",
}

I see what you mean, and yes brining that feature over would be nice as well.

@srawlins
Copy link
Member

srawlins commented Apr 8, 2021

Duplicate of dart-lang/sdk#33244

@srawlins srawlins marked this as a duplicate of dart-lang/sdk#33244 Apr 8, 2021
@esDotDev esDotDev closed this as completed Apr 8, 2021
@esDotDev
Copy link
Author

esDotDev commented Apr 8, 2021

Closing since there is an existing issue for the same functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems
Projects
None yet
Development

No branches or pull requests

4 participants