Enum Limitations

1,793 views
Skip to first unread message

Man Hoang

unread,
Sep 16, 2015, 11:27:50 AM9/16/15
to Dart Misc
As far as I can see, there are two big limitations of enum at the moment.

1. No easy way to know if an object is an enum (of and kind)

    var isEnum = (value ! null) && reflectClass(value.runtimeType).isEnum;

    // In C#, it's so easy
    // var isEnum = value is Enum;


2. No built-in support for parsing an integer or a string into an enum value. This is how I implement my own parsing method.

    /// Converts [input], which is an integer or a string, into an enum value of
    /// type [enumType].
    /// Returns `null` if fails.
    parseEnum(input, Type enumType) {
      try {
        var values = reflectClass(enumType).getField(#values).reflectee;
        if (input is int) {
          return values[input];
        }
        for (var value in values) {
          if (value.toString().split('.')[1] == input) {
            return value;
          }
        }
      } catch (e) {
      }
      return null;
    }

So, will the Dart team resolve these limitations in the next version of the language?


Joel Trottier-Hébert

unread,
Sep 16, 2015, 11:39:19 AM9/16/15
to Dart Misc
+1

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.

Sean Eagan

unread,
Sep 16, 2015, 12:10:18 PM9/16/15
to General Dart Discussion
On Wed, Sep 16, 2015 at 10:27 AM, Man Hoang <joll...@gmail.com> wrote:
As far as I can see, there are two big limitations of enum at the moment.

1. No easy way to know if an object is an enum (of and kind)

    var isEnum = (value ! null) && reflectClass(value.runtimeType).isEnum;

    // In C#, it's so easy
    // var isEnum = value is Enum;


As with your limitation 2, it is currently supported only via mirrors:


Günter Zöchbauer

unread,
Sep 16, 2015, 12:17:47 PM9/16/15
to Dart Misc
Some comment recently indicates that they are considering extending enum capabilities eventually.

I would add 
- custom values for items.
- mirror-less access to the names

Using a normal class as enum (http://stackoverflow.com/a/15854550/217408) isn't too cumbersome.
I usually just use a class because I can customize it to my likings.

Lasse R.H. Nielsen

unread,
Sep 16, 2015, 12:20:25 PM9/16/15
to mi...@dartlang.org
On Wed, Sep 16, 2015 at 5:27 PM, Man Hoang <joll...@gmail.com> wrote:
As far as I can see, there are two big limitations of enum at the moment.

1. No easy way to know if an object is an enum (of and kind)

    var isEnum = (value ! null) && reflectClass(value.runtimeType).isEnum;

    // In C#, it's so easy
    // var isEnum = value is Enum;


Just for clarification: In which cases do you need to know that a value is an instance of a class created using "enum"?
The interface is minuscule (.index) and the index isn't that useful if you don't know the type, and since the methods on those are static, there isn't a lot to use it for. 
 
2. No built-in support for parsing an integer or a string into an enum value. This is how I implement my own parsing method.

    /// Converts [input], which is an integer or a string, into an enum value of
    /// type [enumType].
    /// Returns `null` if fails.
    parseEnum(input, Type enumType) {
      try {
        var values = reflectClass(enumType).getField(#values).reflectee;
        if (input is int) {
          return values[input];
        }
        for (var value in values) {
          if (value.toString().split('.')[1] == input) {
            return value;
          }
        }
      } catch (e) {
      }
      return null;
    }


As with so many other things, if you know the type statically, you can go through the EnumType.values list.
If you don't know the type statically, then it's effectively reflection.
Using a Type value to represent something is ... rarely useful. If you had an "EnumParser" class that you could instantiate with the values list, then that would be a much better representation of the enum than its Type obejct.

An approach that could probably work, without clobbering the enum's namespace, is to have an Enum superclass with static helper methods. Then you could do "is Enum" and "Enum.getValues(someEnumValue)", and internally it would just be one more (private, slightly magical) getter on each enum class.

 
So, will the Dart team resolve these limitations in the next version of the language?

I haven't heard of anything related to this. Can't speak for anybody else :)

/L
--
Lasse R.H. Nielsen - l...@google.com  
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 København K - Denmark - CVR nr. 28 86 69 84

Don Olmstead

unread,
Sep 16, 2015, 2:51:15 PM9/16/15
to mi...@dartlang.org
I've just had two annoyances with enums. First one is you can't annotate a value https://github.com/dart-lang/sdk/issues/23441

The other annoyance and this kinda goes back to the flags thing which honestly I'd prefer if Dart followed C# there as you can just annotate that its a flag and the magic happens, is that you can't do something like

class Flags<T extends Enum>

Other than that don't change a thing ;)

--

Man Hoang

unread,
Sep 17, 2015, 12:23:28 AM9/17/15
to Dart Misc


On Wednesday, September 16, 2015 at 11:20:25 PM UTC+7, Lasse Reichstein Holst Nielsen wrote:


On Wed, Sep 16, 2015 at 5:27 PM, Man Hoang <joll...@gmail.com> wrote:
As far as I can see, there are two big limitations of enum at the moment.

1. No easy way to know if an object is an enum (of and kind)

    var isEnum = (value ! null) && reflectClass(value.runtimeType).isEnum;

    // In C#, it's so easy
    // var isEnum = value is Enum;


Just for clarification: In which cases do you need to know that a value is an instance of a class created using "enum"?
The interface is minuscule (.index) and the index isn't that useful if you don't know the type, and since the methods on those are static, there isn't a lot to use it for. 
 
 I need to know this so I can correctly encode the value during JSON serialization. This can be easily achieved by making sure that every enum extends a special class called Enum (or whatever the name).

if (value is Enum) return value.index;
// or
if (value is Enum) return value.toString().split('.')[1];

Regarding the toString method, I think it would be better if an enum has an instance method or a getter that returns only the name of the enum field.
This is because, in most cases, only the field name is used in JSON serialization.

enum Color { blue, green, red }

Color.green.toString() == 'Color.green';

// Consider adding this method.
Color.green.toSimpleString() == 'green';

// Or consider adding this getter.
Color.green.name == 'green';


2. No built-in support for parsing an integer or a string into an enum value. This is how I implement my own parsing method.

    /// Converts [input], which is an integer or a string, into an enum value of
    /// type [enumType].
    /// Returns `null` if fails.
    parseEnum(input, Type enumType) {
      try {
        var values = reflectClass(enumType).getField(#values).reflectee;
        if (input is int) {
          return values[input];
        }
        for (var value in values) {
          if (value.toString().split('.')[1] == input) {
            return value;
          }
        }
      } catch (e) {
      }
      return null;
    }


This is required when decoding a JSON string.

Monty Rasmussen

unread,
Sep 17, 2015, 12:49:37 AM9/17/15
to Dart Misc
Yes, because of the way enums have been implemented in Dart, I pretty much just never use them. Too often, I need to serialize and persist data, and these int-based, ordinal enums are too hard to deal with. It's just about the only feature I truly dislike in Dart.

KwangYul Seo

unread,
Sep 18, 2015, 11:44:49 AM9/18/15
to mi...@dartlang.org
I would like to add one more

* Make enum types implement Comparable.

Currently, we can't use enum values as keys in sorted map like SplayTreeMap because enums do not implement Comparable.




David Morgan ☯

unread,
Sep 25, 2015, 8:50:53 AM9/25/15
to Dart Misc
Please have a look at


for cases when you want to do class-like things with enums, such as implementing Comparable. It also gives you conversion to/from string via "name" and "valueOf". Suggestions for other functionality to add are welcome, please file them as issues.

EnumClass is intended to be the "we'd like Dart enums to be as powerful as Java ones" dropin library until language support improves. So, if you need support for something now, you may want to file an issue for EnumClass, it's likely to arrive a lot faster than a change to the Dart language :)

Cheers

Morgan

David Morgan ☯

unread,
Sep 25, 2015, 8:57:33 AM9/25/15
to Dart Misc
Until language support improves,


should do what you want. It has "name" for ->string and "valueOf" for conversion back from string.

And, all of them extend "EnumClass" :)

tatumizer-v0.2

unread,
Sep 25, 2015, 9:08:07 PM9/25/15
to Dart Misc
Yeah, "const" is a pita. If you need a proof, look no further than this example.
We need a code generator and a lot of boilerplate and complexity just for constness sake.

If language removed the requirement of constness in annotations and elsewhere, we would be perfectly fine with "final" vars:
class TestEnum extends EnumClass {
 
static final
    yes
= new TestEnum._("yes"),
   
no = new TestEnum._("no"),
    maybe
= new TestEnum._("maybe");
 
 
TestEnum._(String name) : super(name);
}


That's all. There's very minimal amount of redundancy here; considering that enums are quite rare, we could live with that IMO.

If you need the list of values, call Enums.values(TestEnum);
for "valueOf",  call Enums.valueOf(TestEnum,"maybe");

BTW, it's not obvious that you need enums values to be "const", even with current language design. (I can't immediately find a good use case that requires constness).


John Messerly

unread,
Sep 25, 2015, 9:12:25 PM9/25/15
to General Dart Discussion
On Fri, Sep 25, 2015 at 6:08 PM, tatumizer-v0.2 <tatu...@gmail.com> wrote:

BTW, it's not obvious that you need enums values to be "const", even with current language design. (I can't immediately find a good use case that requires constness).

They need to be const to be consumed by other constants, like metadata annotations.

(Whether or not `const` should exist at all is separate question :) )

Bob Nystrom

unread,
Sep 28, 2015, 12:12:45 PM9/28/15
to General Dart Discussion

On Fri, Sep 25, 2015 at 6:08 PM, tatumizer-v0.2 <tatu...@gmail.com> wrote:
BTW, it's not obvious that you need enums values to be "const", even with current language design. (I can't immediately find a good use case that requires constness).

The language specifies that a static warning must be reported if a switch() on an enum type does not have a case for every value (or a default case). That means at static analysis time, we need to know the full list of enum values, and we need to be able to evaluate the expressions in the cases.

(Of course, if we wanted to allow non-const enums, this warning could be removed and then this problem is no more.)

Cheers!

- bob

tatumizer-v0.2

unread,
Sep 28, 2015, 8:24:56 PM9/28/15
to Dart Misc
> The language specifies that a static warning must be reported if a switch() on an enum type does not have a case for every value (or a default case).
Oh, right, I forgot about this feature. Maybe because it's forgettable. It's based on static type of selector, it should be enum for this magic to work. If it's just "var" - nothing happens, even when "propagated type" is enum.
I played a bit with short examples, and noticed something unusual. If static type is enum, switch doesn't allow for possibility of null value of selector. E.g.
enum MyEnum {
  foo,bar
}
void main() {
   MyEnum x=null;
   switch (x) {
     case MyEnum.foo:
     case MyEnum.bar:
     case null:  // error: Case expressions must have the same types, 'null' is not a 'MyEnum'
                       // null is not MyEnum? why?
   }
}
However, if selector is int, nulls are allowed:
void main() {
   int x=null;
   switch (x) {
     case null:   // no problem!
   }
}

Strange... 




Gen

unread,
Sep 29, 2015, 4:06:59 AM9/29/15
to mi...@dartlang.org
I have tested things in Webstorm and my results are different from yours:
- I have no warning when I do not cover all enum values in a "switch" statement.
- When I try "case null" for an "int" variable in Webstorm then I get this error:
error: line 10 pos 8: expected case expression of type int
        case null: print("int null");

I find it rather strange that one can assign "null" to a variable of type X but
one can not match "null" as expression of type X for a "switch" statement.

PS
After some time I got the error (?, red color) in Webstorm as well:
"Missing case clause for 'bar'

Lasse R.H. Nielsen

unread,
Sep 29, 2015, 5:22:04 AM9/29/15
to mi...@dartlang.org
On Tue, Sep 29, 2015 at 10:06 AM, Gen <gp78...@gmail.com> wrote:
I have tested things in Webstorm and my results are different from yours:
- I have no warning when I do not cover all enum values in a "switch" statement.
- When I try "case null" for an "int" variable in Webstorm then I get this error:
error: line 10 pos 8: expected case expression of type int
        case null: print("int null");

I find it rather strange that one can assign "null" to a variable of type X but
one can not match "null" as expression of type X for a "switch" statement.

The spec for switch is a little "special" on this point.

It requires all the switch constants to have the same type.
Not be assignable to the same type, or having a common supertype, but to have the *exact* same type:

> It is a compile-time error if the values of the expressions e_k are not either: 
>  • instances of the same class C, for all k ∈ 1..n, or
>  • instances of a class that implements int, for all k ∈ 1..n, or
>  • instances of a class that implements String, for all k ∈ 1..n.

It's not even a warning, it's a compile-time error if the values are not all instances of the same class (or string or int, which is confusing because we go to great lengths to avoid exposing that there are internal subclasses of into or String, so the user would assume that all integers or strings are already the same class).

It's also a compile time error if the class overrides Object's operator== (except for a slew of exceptions for internal types that override operator== but really feel like they shouldn't).

Basically, it's a mess.

We should at least remove the "same class" requirement since it prevents you from using your own enum-like constants if you use a subclass for some instances. The "not overriding operator==" probably has to stay so we can use "identical" for the comparisons with good conscience.

kc

unread,
Sep 29, 2015, 8:42:40 AM9/29/15
to Dart Misc
On Friday, September 25, 2015 at 1:57:33 PM UTC+1, David Morgan ☯ wrote:
Until language support improves,



Re language support. Your work on enums, immutability/value objects is very interesting. 

Syntax/semantic innovation is being considered for Dart 2.0. 

The React style diff-a-tree-of-value-objects does seem to be pretty central to both Sky/Flutter and Angular 2.0. Support baked-in to the lang and runtime would be good.

K.

Alex Tatumizer

unread,
Sep 29, 2015, 11:29:36 AM9/29/15
to mi...@dartlang.org
I used dartpad for my etudes, but I can't figure out which version of dart compiler is there. All I know is that dartpad accepts the following program, no questions asked:
void main() {
  int x=0;
  switch (x) {
    case null:
  }
}

Devon Carew

unread,
Sep 29, 2015, 1:48:29 PM9/29/15
to General Dart Discussion
On Tue, Sep 29, 2015 at 8:29 AM, Alex Tatumizer <tatu...@gmail.com> wrote:
I used dartpad for my etudes, but I can't figure out which version of dart compiler is there.

It's not documented, but to find out the version of the sdk that dartpad is built on, click on the 'DartPad' text in the upper left. Right now it's using 1.12.1.

All I know is that dartpad accepts the following program, no questions asked:
void main() {
  int x=0;
  switch (x) {
    case null:
  }
}

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.



--
Devon Carew
Software Engineer
Google, Inc.

tatumizer-v0.2

unread,
Sep 29, 2015, 4:00:47 PM9/29/15
to Dart Misc
Aha! Here's what happens.
This is valid:

void main() {
  int x=0;
  switch (x) {
    case null:
  }
}
But this is not:

void main() {
  int x=0;
  switch (x) {
    case 0:
    case null: // error: Case expressions must have the same types, '0' is not a 'Null'
  }
}

Dart just requires that all actual "cases" to be of the same type. So "null" *alone* is treated as OK case (because there's nothing it can conflict with).
Compare with java spec (maybe written by Gilad?)
Quote:
The prohibition against using null as a case constant prevents code being written that can never be executed. If the switch statement's Expression is of a reference type, that is, String or a boxed primitive type or an enum type, then an exception will be thrown will occur if the Expression evaluates to null at run time. In the judgment of the designers of the Java programming language, this is a better outcome than silently skipping the entire switch statement or choosing to execute the statements (if any) after the default label (if any).
End Quote

In dart, exception is NOT thrown if Expression evaluates to null. I think it undermines the logic behind special treatment of enum in a context of switch statement.
The following is a valid dart program, it compiles and runs (in 1.12.1)
enum MyEnum {
  foo

}
void main() {
  MyEnum x=null;
  switch (x) {
    case MyEnum.foo:
  }
  print("OK"); // no error thrown for x=null - really prints OK
}

Requirement of "full set of enum values in switch" kind of makes sense (IMO) only if the cases really exhaust the possibilities for Expression. If we leave a loophole for x=null, then our list of variants is not complete. Java cleverly avoids this pitfall by throwing NPE upfront when Expression==null
Won't it be a good idea for dart to do the same?



Lasse R.H. Nielsen

unread,
Sep 30, 2015, 6:04:48 AM9/30/15
to mi...@dartlang.org
On Tue, Sep 29, 2015 at 10:00 PM, tatumizer-v0.2 <tatu...@gmail.com> wrote:
Aha! Here's what happens.
This is valid:
void main() {
  int x=0;
  switch (x) {
    case null:
  }
}
But this is not:
void main() {
  int x=0;
  switch (x) {
    case 0:
    case null: // error: Case expressions must have the same types, '0' is not a 'Null'
  }
}

Dart just requires that all actual "cases" to be of the same type. So "null" *alone* is treated as OK case (because there's nothing it can conflict with).
Compare with java spec (maybe written by Gilad?)
Quote:
The prohibition against using null as a case constant prevents code being written that can never be executed. If the switch statement's Expression is of a reference type, that is, String or a boxed primitive type or an enum type, then an exception will be thrown will occur if the Expression evaluates to null at run time. In the judgment of the designers of the Java programming language, this is a better outcome than silently skipping the entire switch statement or choosing to execute the statements (if any) after the default label (if any).
End Quote

In dart, exception is NOT thrown if Expression evaluates to null. I think it undermines the logic behind special treatment of enum in a context of switch statement.

I can see the point, but I'm not sure Dart and Java should be the same.
In Java, if the (static) type of a switch expression is Foo, then you know that the result is either Foo or null.
In Dart, the result may be any value, even in checked mode.

The special handling of enums in a switch is to ensure that all enum values are accounted for.
In Java, allowing null would mean that to be complete, you need to handle null as well.
In Dart, you are never complete if you don't have a default case, and it's not fixed by just disallowing null.

Dart is different from Java in that `null` is an object. Disallowing null is special-casing that one object, and even if we wanted to, we can't do it based on the static type like Java does because static types should not affect runtime (and can't, the VM doesn't implement static analysis at all).

Well, we can actually do it, because we have ensured that all the case expressions have the same class, so we can use that as a guide. 
 
The following is a valid dart program, it compiles and runs (in 1.12.1)
enum MyEnum {
  foo
}
void main() {
  MyEnum x=null;
  switch (x) {
    case MyEnum.foo:
  }
  print("OK"); // no error thrown for x=null - really prints OK
}

So is this:

enum MyEnum {foo} 
abstract class C {
  MyEnum get x;
}
class D implements C {
  get x => 42;
}
void main() {
   C c = new D();  
   switch (c.x) {  // static type of c.x: MyEnum, actual value: 42, no type errors in checked mode.
     case MyEnum.foo:
   }
   print("OK");  // no error thrown for x=42. Would you expect one?
}
 

Requirement of "full set of enum values in switch" kind of makes sense (IMO) only if the cases really exhaust the possibilities for Expression.

It doesn't, and while it's possible, it's not a small change.
It makes switches on enum classes (and maybe int and string as well, as in Java) special in that they *throw* on a non-matching value, instead of going to the default.
 
If we leave a loophole for x=null, then our list of variants is not complete.

We leave a loophole for *all* value. There is no single exception like in Java, we have to disallow all non-MyEnum values, which is possible (it's detectable that the "class of the case expressions" is an enum class, and default to throwing if the switch expression doesn't evaluate to an instance of that class), but that would be a much more intrusive special casing than just giving a warning if not all enum values are handled, and I don't think the result is worth the complexity.

Java cleverly avoids this pitfall by throwing NPE upfront when Expression==null
Won't it be a good idea for dart to do the same?

I don't think so. It's not enough, and I think doing enough to ensure switch completeness is too much.

But then, I subscribe to the idea that switch statements are symptoms of a bad OO design to begin with. You should use method dispatch instead - and enums should be able to have methods for exactly that reason. Or tables, if your values are really froma a small set of simple value. 
Simple enums like what we have is just begging for switching by value, they are actively encouraging bad design.

/L

Gen

unread,
Sep 30, 2015, 10:44:30 AM9/30/15
to Dart Misc
But then, I subscribe to the idea that switch statements are symptoms of a bad OO design to begin with. You should use method dispatch instead - and enums should be able to have methods for exactly that reason. Or tables, if your values are really froma a small set of simple value.
Simple enums like what we have is just begging for switching by value, they are actively encouraging bad design.

AFAIU, a "switch" statement is an optimized version of "if" and "else if" statements. These statements deal with values or objects.
I do not understand how method dispatch and enums with methods would affect the "switch" statement.
 

Alex Tatumizer

unread,
Sep 30, 2015, 1:38:27 PM9/30/15
to mi...@dartlang.org
@Lasse:
Sure, where java checks Expression != null, dart (in theory) should check "Expression is of the same runtime type as all "case" variants. And maybe it's too much. But then, specialcasing enum in switch (which is what dart does now) is too much, too.

I'd like to clarify one point though: it's about the complexity of implementing this check (no matter whether the feature is worthwhile or not - just in theory). It might be complicated because VM doesn't know the common type of "case" variants? But how it can generate optimal code without this knowledge? E.g., suppose I have a switch with 42 variants (say, 0..41) - then, good compiler will generate a jump table, instead of if -else is -...etc. You can generate jump table only if you know the type is int and check that the range is "dense". There are other optimization techniques for "switch" - they all require the knowledge of type anyway.

But if compiler knows the expected type, generating the above check is no more complicated than java's expression != null.

@Gen:

> I do not understand how method dispatch and enums with methods would affect the "switch" statemen

When you have enums like in those in java, where enum values can be objects, you just define extra method in the enum class, and call it instead of writing switch. That's much cleaner. "switch" is quite rarely needed, mostly in very low-level functions like scanner or something. That's another reason I think too much fuss about types in switch is unwarranted: the feature is too rare and reserved mostly for low-level scenarios. (it has to be optimized really well by compiler, not blindly generating if -else if ...).


Gen

unread,
Sep 30, 2015, 2:20:16 PM9/30/15
to mi...@dartlang.org
Can you give an example how a method could replace a "switch" statement ?
Maybe you want to replace this:
switch (enum):
   case enum.A : object.someMethod();break;
by this:
enum.someMethod();

Obviously what enum.someMethod() does depends on the enum and not on the method that would like to call object.someMethod() and not enum.someMethod().
I do not see how one can replace "if" or "switch" by a method dispatch.
IMHO, enums are most often only useful in combination with "if" and "switch" statements.

Alex Tatumizer

unread,
Sep 30, 2015, 3:06:29 PM9/30/15
to mi...@dartlang.org
@Gen: normally, this doesn't happen. If you know any real use case, we can look into it. (I never encountered such situation before, but it doesn't mean it doesn't exist. I so far used switches only in a low-level context, and even that is rare).

tatumizer-v0.2

unread,
Sep 30, 2015, 3:46:52 PM9/30/15
to Dart Misc
Oh, I think I know what you mean.
Java provides special syntax for defining extra methods for each enum individually.
In dart, you can model it like this:
class TestEnum extends EnumClass {
 
static final

    yes
= new TestEnum._("yes", ()=>"Mr. Yes"),
   
no = new TestEnum._("no", ()=>"I don't even know who I am"),
    maybe
= new TestEnum._("maybe", ()=>"call me 'maybe'");
  Function _whoAreYou;
 
TestEnum._(String name, this._whoAreYou) : super(name);
  String whoAreYou()=>_whoAreYou();
}


Or you can subclass TestEnum, having 3 different subclasses for yes, no and maybe.
Then, instead of switching, just call myEnum.whoAreYou();
In dart, this all is quite concise, not sure it would warrant any special syntax.


Lasse R.H. Nielsen

unread,
Oct 1, 2015, 1:59:55 AM10/1/15
to mi...@dartlang.org
On Wed, Sep 30, 2015 at 8:20 PM, Gen <gp78...@gmail.com> wrote:
Can you give an example how a method could replace a "switch" statement ?

A switch, at its core, detects one of a number of cases and executes code depending on which case it is.

In Dart, switch cases can only be compile-time constant objects of the same type, so the matched values will have a common supertype. It's a multi-way branch with trivial branching logic (so there is no hidden computation in the branching, it's all in the case code)..

That means that the "code depending on the case" can be put into a method on the constant object instead.
Example:

    floom(Biff biff) { 
      switch (biff) {
        case Biff.boff: something(); break;
        case Biff.fluff: somethingElse(); break;
      }
    }

could be rewrittn as:
       
  floom(Biff biff) { biff.floom(); }

where Biff.boff.floom is  floom() { something(); }  and Bif.fluff.floom is  floom() { somethingElse(); } . 
That uses method dispatch to select which code to run, like a switch does, but puts it on the objects themselves instead of in some unrelated function elsewhere.

This has some advantages and some disadvantages, but it is usually easier (to some degree) to maintain something written using dynamic dispatch than something using switch statements. 
It keeps the "object related operation" on the object, which is good for locality.

It does require you to have control over the Biff class in order to add the floom method.
You can't do that for integers or strings, or just classes that you're not writing yourself, which is why switching on integers may make sense (but only if you are not using the integers to represent objects - in that case you should use the object itself). A scanner is the typical example where you want to switch on an plain input code point.

If the switch is basically on the type of an object, that object should do it for you. If the operation is not something you can predict ahead of time, you can use double-dispatch (visitor pattern) instead.
 
Maybe you want to replace this:
switch (enum):
   case enum.A : object.someMethod();break;
by this:
enum.someMethod();

Obviously what enum.someMethod() does depends on the enum and not on method that would like to call object.someMethod() and not enum.someMethod().

I do not see how one can replace "if" or "switch" by a method dispatch.

There is a longer discussion here: http://c2.com/cgi/wiki?SwitchStatementsSmell

My problem is that Java enums allow you to use dispatch instead of switch by allowing you to add methods to the enum objects, and even individual methods to each object.
Dart enums only support switching, which is kindof sad.

/L
-- 

David "Morgan" Morgan

unread,
Oct 1, 2015, 4:04:16 AM10/1/15
to mi...@dartlang.org

My problem is that Java enums allow you to use dispatch instead of switch by allowing you to add methods to the enum objects, and even individual methods to each object.
Dart enums only support switching, which is kindof sad.

It is. And here's that link again ;)


It might not be super pretty, but it's the best we have. My team uses it extensively. Actually an older, google-internal implementation, but we'll switch to this one in time.

Gen

unread,
Oct 1, 2015, 4:47:01 AM10/1/15
to Dart Misc
@tatumizer-v0.2 @Lasse Reichstein Holst Nielsen

Thanks for the explanations and I agree with you except that a "switch" could be replaced by a method dispatch.
 
IMO, these ideas are essential:


That uses method dispatch to select which code to run, like a switch does, but puts it on the objects themselves instead of in some unrelated function elsewhere.
That is what I had written and that is the whole point of using "if" and "switch" instead of an abstract method dispatch: Call elsewhere some other function depending on a certain case.
With "if" and "switch" and "for", the caller or interpreter can know the case and decide what is done in that case.

 
You can't do that for integers or strings, or just classes that you're not writing yourself, which is why switching on integers may make sense (but only if you are not using the integers to represent objects - in that case you should use the object itself). A scanner is the typical example where you want to switch on an plain input code point.
Integers, strings, enumerations, "symbols" and even collections are "readable" values that one can use in combination with "if" and "switch" and "for" statements.

Of course an enumeration is technically an object which could have useful convenience and dispatch methods.
But the purpose of "if" and "switch" is to statically link a certain case to a certain consequence within a method.
Whereas object orientation and dynamic method dispatch is useful to keep things abstract and dynamic within a method.
But somewhere abstraction must end and that is where "if" and "switch" or other pattern matching mechanisms are used.
Reply all
Reply to author
Forward
0 new messages