Enumeration idioms: Values from different enumerations

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Ben Finney

    Enumeration idioms: Values from different enumerations

    [quoting private email with permission]

    Antoon Pardon wrote:[color=blue]
    > I just downloaded your enum module for python [from the Cheeseshop]
    > and played a bit with it. IMO some of the behaviour makes it less
    > usefull.[/color]

    Feedback is appreciated. I'm hoping to provide a "one obvious way" to
    do enumerations in Python.
    [color=blue][color=green][color=darkred]
    > >>> from enum import Enum
    > >>> day = Enum('mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun')
    > >>> col = Enum('red', 'green', 'blue')
    > >>> day.wed == col.blue[/color][/color]
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in ?
    > File "enum.py", line 100, in __cmp__
    > raise EnumValueCompar eError(self, other)
    > enum.EnumValueC ompareError: Not values from the same enumeration:
    > (EnumValue(<enu m.Enum object at 0x4020c30c>, 2, 'wed'),
    > EnumValue(<enum .Enum object at 0x4021a14c>, 2, 'blue'))[color=green][color=darkred]
    > >>> type(day.mon) == type(col.red)[/color][/color]
    > True[color=green][color=darkred]
    > >>> type(day.mon) is type(col.red)[/color][/color]
    > True[color=green][color=darkred]
    > >>> lst= [day.mon, col.red]
    > >>> day.fri in lst[/color][/color][/color]
    [color=blue]
    > As can be seen from the above, you raise an exception when one wants
    > to compare Enums from different enumarations, but it seems a bit
    > strange that different enumerations belong to the same type.[/color]

    This does seem a point that could be confusing. Would it be better if
    every Enum instance had its own unique subclass of EnumValue, that was
    used to instantiate values for that enumeration?
    [color=blue]
    > I also think it would be more usefull if enums from different
    > enumerations just tested unequal.[/color]

    My rationale for this is: The only purpose of an enumeration is to
    have a set of arbitrary unique values within that enumeration. The
    values make no sense in the context of a different enumeration, so I
    see three different comparison results:
    [color=blue][color=green][color=darkred]
    >>> Weekday.mon == Weekday.mon[/color][/color][/color]
    True[color=blue][color=green][color=darkred]
    >>> Weekday.fri == Weekday.mon[/color][/color][/color]
    False[color=blue][color=green][color=darkred]
    >>> Colour.blue == Weekday.mon[/color][/color][/color]
    [...]
    enum.EnumValueC ompareError: Not values from the same enumeration

    However, I'm aware that this is not how other Python types behave:
    [color=blue][color=green][color=darkred]
    >>> 23 == 23[/color][/color][/color]
    True[color=blue][color=green][color=darkred]
    >>> 42 == 23[/color][/color][/color]
    False[color=blue][color=green][color=darkred]
    >>> "spam" == 23[/color][/color][/color]
    False

    Is there a semantic difference between these cases? Is that difference
    enough to want different behaviour?

    Is there some behaviour other than "evaluate to False" or "raise an
    exception", that could indicate "not comparable"?
    [color=blue]
    > Because as it is you can't put elements from different enumerations
    > in a list and check with the in operator if a specific enum value is
    > in the list.
    >
    > It could also cause problems for dictionaries, since keys in
    > dictionaries can be tested against a key giving in a subscription.[/color]

    These are valid concerns. I can't see how to reconcile these against
    the desire for values from different enums to fail comparison.

    Am I alone in my tri-state view of enumeration value comparisons? Can
    anyone else defend why values from different enumerations should not
    compare?

    --
    \ "I was the kid next door's imaginary friend." -- Emo Philips |
    `\ |
    _o__) |
    Ben Finney
  • Peter Hansen

    #2
    Re: Enumeration idioms: Values from different enumerations

    Ben Finney wrote:[color=blue]
    > These are valid concerns. I can't see how to reconcile these against
    > the desire for values from different enums to fail comparison.
    >
    > Am I alone in my tri-state view of enumeration value comparisons? Can
    > anyone else defend why values from different enumerations should not
    > compare?[/color]

    While I'm largely a disinterested bystander, it occurs to me that if you
    look at the reasons behind wanting enumerations in the first place, you
    might find a good reason to defend this view.

    For example, if enumerations are intended to reduce the likelihood of
    certain types of errors (where the use of typical XXXX=3 "constants"
    might be more prone to errors), then perhaps this suggests that passing
    errors silently is bad. That is, trying to compare enumerations that
    should not be compared *is* an error (raising an exception) *because*
    the whole point of enumerations is to avoid errors in such cases.

    Or perhaps I'm off the mark as to why people want enumerations. Is it
    just a cosmetic consideration? (Yes, I've used and appreciated them
    extensively in C and might even pick up Enum for my Python code... I'm
    just sort of playing devil's advocate here.)

    -Peter

    Comment

    • Mike Meyer

      #3
      Re: Enumeration idioms: Values from different enumerations

      Peter Hansen <peter@engcorp. com> writes:[color=blue]
      > For example, if enumerations are intended to reduce the likelihood of
      > certain types of errors (where the use of typical XXXX=3 "constants"
      > might be more prone to errors), then perhaps this suggests that
      > passing errors silently is bad. That is, trying to compare
      > enumerations that should not be compared *is* an error (raising an
      > exception) *because* the whole point of enumerations is to avoid
      > errors in such cases.[/color]

      Except it might not be an error. For instance, if I've got a list of
      enum objects taken from various types (say I've got one set of enums
      for days of the week, another for months of the year, and so on, and
      which I use depends on whether the user wants to select days of the
      week, months of the year, etc), it makes perfect sense to want to know
      if a specific enum value is in the list, and the obvious way to check
      it is with "my_value in enum_list". That won't work if you raise an
      exception - it takes a relatively convoluted bit of code to make this
      test.

      Python generally uses '==' to mean "is the same value". To do that, a
      simple true/false return is enough. In raising an exception, you're
      making '==' carry an extra meaning (I'm not sure *what* that is,
      though). Do any python builtins behave that way? How about anything in
      the python standard library?

      <mike
      --
      Mike Meyer <mwm@mired.or g> http://www.mired.org/home/mwm/
      Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.

      Comment

      • Antoon Pardon

        #4
        Re: Enumeration idioms: Values from different enumerations

        Op 2005-12-16, Ben Finney schreef <ben+hates-spam@benfinney. id.au>:[color=blue]
        > [quoting private email with permission]
        >
        > Antoon Pardon wrote:[color=green]
        >> I just downloaded your enum module for python [from the Cheeseshop]
        >> and played a bit with it. IMO some of the behaviour makes it less
        >> usefull.[/color]
        >
        > Feedback is appreciated. I'm hoping to provide a "one obvious way" to
        > do enumerations in Python.
        >[color=green][color=darkred]
        >> >>> from enum import Enum
        >> >>> day = Enum('mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun')
        >> >>> col = Enum('red', 'green', 'blue')
        >> >>> day.wed == col.blue[/color]
        >> Traceback (most recent call last):
        >> File "<stdin>", line 1, in ?
        >> File "enum.py", line 100, in __cmp__
        >> raise EnumValueCompar eError(self, other)
        >> enum.EnumValueC ompareError: Not values from the same enumeration:
        >> (EnumValue(<enu m.Enum object at 0x4020c30c>, 2, 'wed'),
        >> EnumValue(<enum .Enum object at 0x4021a14c>, 2, 'blue'))[color=darkred]
        >> >>> type(day.mon) == type(col.red)[/color]
        >> True[color=darkred]
        >> >>> type(day.mon) is type(col.red)[/color]
        >> True[color=darkred]
        >> >>> lst= [day.mon, col.red]
        >> >>> day.fri in lst[/color][/color]
        >[color=green]
        >> As can be seen from the above, you raise an exception when one wants
        >> to compare Enums from different enumarations, but it seems a bit
        >> strange that different enumerations belong to the same type.[/color]
        >
        > This does seem a point that could be confusing. Would it be better if
        > every Enum instance had its own unique subclass of EnumValue, that was
        > used to instantiate values for that enumeration?[/color]

        If you decide on keeping the current behaviour when comparing
        values of different enumerations, I would definitely answer
        yes.
        [color=blue][color=green]
        >> I also think it would be more usefull if enums from different
        >> enumerations just tested unequal.[/color]
        >
        > My rationale for this is: The only purpose of an enumeration is to
        > have a set of arbitrary unique values within that enumeration. The
        > values make no sense in the context of a different enumeration, so I
        > see three different comparison results:
        >[color=green][color=darkred]
        > >>> Weekday.mon == Weekday.mon[/color][/color]
        > True[color=green][color=darkred]
        > >>> Weekday.fri == Weekday.mon[/color][/color]
        > False[color=green][color=darkred]
        > >>> Colour.blue == Weekday.mon[/color][/color]
        > [...]
        > enum.EnumValueC ompareError: Not values from the same enumeration
        >
        > However, I'm aware that this is not how other Python types behave:
        >[color=green][color=darkred]
        > >>> 23 == 23[/color][/color]
        > True[color=green][color=darkred]
        > >>> 42 == 23[/color][/color]
        > False[color=green][color=darkred]
        > >>> "spam" == 23[/color][/color]
        > False
        >
        > Is there a semantic difference between these cases? Is that difference
        > enough to want different behaviour?
        >
        > Is there some behaviour other than "evaluate to False" or "raise an
        > exception", that could indicate "not comparable"?[/color]

        This is a difficult question, because AFAIU python doesn't have clear
        guidelines for this. I also have the impression that comparisons are
        used for two different reasons.

        The first is compare things in a mathematical kind of way in which
        how things are compared is important.

        The second is more an ordering mechanisme. Whether a string is greater
        than an int or vice versa, is not imporant what is important is that
        this order is consistent and can be used in binary searches, trees
        and other structures to organise data.

        Now python has only one collection of compare operators which can
        cause conflicts. For instance, one could impose an order on sets
        to use for such structure but that goes against the normal order
        on sets which is based on subsets.

        The only advise I have here is look at PEP 3000 that states:

        Comparisons other than == and != between disparate types will raise
        an exception unless explicitly supported by the type.

        Which seem to imply that == and != should not raise an exception
        but >, >=, <, <= should.

        --
        Antoon Pardon

        Comment

        • Ben Finney

          #5
          Re: Enumeration idioms: Values from different enumerations

          Mike Meyer <mwm@mired.or g> writes:[color=blue]
          > Peter Hansen <peter@engcorp. com> writes:[color=green]
          >> That is, [perhaps] trying to compare enumerations that should not
          >> be compared *is* an error (raising an exception) *because* the
          >> whole point of enumerations is to avoid errors in such cases.[/color]
          >
          > Except it might not be an error. For instance, if I've got a list of
          > enum objects taken from various types (say I've got one set of enums
          > for days of the week, another for months of the year, and so on, and
          > which I use depends on whether the user wants to select days of the
          > week, months of the year, etc), it makes perfect sense to want to know
          > if a specific enum value is in the list, and the obvious way to check
          > it is with "my_value in enum_list". That won't work if you raise an
          > exception - it takes a relatively convoluted bit of code to make this
          > test.[/color]

          The 'enum' package in Cheeseshop doesn't do that. Enumerations are
          sequences (of unique arbitrary values), that can be iterated and tested
          for membership.

          What's being discussed here is what happens when comparing the *values*
          from the enumeration.
          [color=blue]
          > Python generally uses '==' to mean "is the same value". To do that,
          > a simple true/false return is enough. In raising an exception,
          > you're making '==' carry an extra meaning (I'm not sure *what* that
          > is, though).[/color]

          The problem with "is the same value" as an explanation for '==' is
          that it doesn't help in cases such as::
          [color=blue][color=green][color=darkred]
          >>> ShirtSize = Enum('small', 'medium', 'large')
          >>> AppleSize = Enum('small', 'large')[/color][/color][/color]

          What should be the result of this comparison::
          [color=blue][color=green][color=darkred]
          >>> ShirtSize.small == AppleSize.small[/color][/color][/color]

          Are they "the same value"? They're both "small" (and they both coerce
          to the same string value, and in this case the same integer value).

          If not, is 'False' the right way to indicate that?

          Or is it an error to even try comparing them?
          [color=blue]
          > Do any python builtins behave that way? How about anything in the
          > python standard library?[/color]

          No to both; I believe this may be a defining property of
          enumerations. Am I wrong?

          --
          \ "Man cannot be uplifted; he must be seduced into virtue." -- |
          `\ Donald Robert Perry Marquis |
          _o__) |
          Ben Finney

          Comment

          • Antoon Pardon

            #6
            Re: Enumeration idioms: Values from different enumerations

            Op 2005-12-16, Ben Finney schreef <bignose@polar. local>:[color=blue]
            > Mike Meyer <mwm@mired.or g> writes:[color=green]
            >> Peter Hansen <peter@engcorp. com> writes:[color=darkred]
            >>> That is, [perhaps] trying to compare enumerations that should not
            >>> be compared *is* an error (raising an exception) *because* the
            >>> whole point of enumerations is to avoid errors in such cases.[/color]
            >>
            >> Except it might not be an error. For instance, if I've got a list of
            >> enum objects taken from various types (say I've got one set of enums
            >> for days of the week, another for months of the year, and so on, and
            >> which I use depends on whether the user wants to select days of the
            >> week, months of the year, etc), it makes perfect sense to want to know
            >> if a specific enum value is in the list, and the obvious way to check
            >> it is with "my_value in enum_list". That won't work if you raise an
            >> exception - it takes a relatively convoluted bit of code to make this
            >> test.[/color]
            >
            > The 'enum' package in Cheeseshop doesn't do that. Enumerations are
            > sequences (of unique arbitrary values), that can be iterated and tested
            > for membership.[/color]

            Sure but we do have this:
            [color=blue][color=green][color=darkred]
            >>> from enum import Enum
            >>> day = Enum('mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun')
            >>> col = Enum('red', 'green', 'blue')
            >>> lst= [day.mon, col.red]
            >>> col.blue in lst[/color][/color][/color]
            Traceback (most recent call last):
            File "<stdin>", line 1, in ?
            File "enum.py", line 100, in __cmp__
            raise EnumValueCompar eError(self, other)
            enum.EnumValueC ompareError: Not values from the same enumeration:
            (EnumValue(<enu m.Enum object at 0x402181ac>, 2, 'blue'),
            EnumValue(<enum .Enum object at 0x4020c36c>, 0, 'mon'))
            [color=blue]
            > What's being discussed here is what happens when comparing the *values*
            > from the enumeration.
            >[color=green]
            >> Python generally uses '==' to mean "is the same value". To do that,
            >> a simple true/false return is enough. In raising an exception,
            >> you're making '==' carry an extra meaning (I'm not sure *what* that
            >> is, though).[/color]
            >
            > The problem with "is the same value" as an explanation for '==' is
            > that it doesn't help in cases such as::
            >[color=green][color=darkred]
            > >>> ShirtSize = Enum('small', 'medium', 'large')
            > >>> AppleSize = Enum('small', 'large')[/color][/color]
            >
            > What should be the result of this comparison::
            >[color=green][color=darkred]
            > >>> ShirtSize.small == AppleSize.small[/color][/color]
            >
            > Are they "the same value"? They're both "small" (and they both coerce
            > to the same string value, and in this case the same integer value).
            >
            > If not, is 'False' the right way to indicate that?[/color]

            I would agree 'False' is the right answer here.

            --
            Antoon Pardon

            Comment

            • Ben Sizer

              #7
              Re: Enumeration idioms: Values from different enumerations

              Ben Finney wrote:[color=blue]
              > The problem with "is the same value" as an explanation for '==' is
              > that it doesn't help in cases such as::
              >[color=green][color=darkred]
              > >>> ShirtSize = Enum('small', 'medium', 'large')
              > >>> AppleSize = Enum('small', 'large')[/color][/color]
              >
              > What should be the result of this comparison::
              >[color=green][color=darkred]
              > >>> ShirtSize.small == AppleSize.small[/color][/color]
              >
              > Are they "the same value"? They're both "small" (and they both coerce
              > to the same string value, and in this case the same integer value).[/color]

              Is it possible to make it have the following sort of behaviour? :
              [color=blue][color=green][color=darkred]
              >>> ShirtSize.small == AppleSize.small[/color][/color][/color]
              True[color=blue][color=green][color=darkred]
              >>> ShirtSize.small is AppleSize.small[/color][/color][/color]
              False

              It works for comparing a boolean (True) vs. an integer (1), so it has
              some sort of precedent. (Especially if you make the tenuous assumption
              that True,False are language-supported 'enums' for 0 and 1.)

              --
              Ben Sizer

              Comment

              • Antoon Pardon

                #8
                Re: Enumeration idioms: Values from different enumerations

                Op 2005-12-16, Ben Sizer schreef <kylotan@gmail. com>:[color=blue]
                > Ben Finney wrote:[color=green]
                >> The problem with "is the same value" as an explanation for '==' is
                >> that it doesn't help in cases such as::
                >>[color=darkred]
                >> >>> ShirtSize = Enum('small', 'medium', 'large')
                >> >>> AppleSize = Enum('small', 'large')[/color]
                >>
                >> What should be the result of this comparison::
                >>[color=darkred]
                >> >>> ShirtSize.small == AppleSize.small[/color]
                >>
                >> Are they "the same value"? They're both "small" (and they both coerce
                >> to the same string value, and in this case the same integer value).[/color]
                >
                > Is it possible to make it have the following sort of behaviour? :
                >[color=green][color=darkred]
                >>>> ShirtSize.small == AppleSize.small[/color][/color]
                > True[color=green][color=darkred]
                >>>> ShirtSize.small is AppleSize.small[/color][/color]
                > False
                >
                > It works for comparing a boolean (True) vs. an integer (1), so it has
                > some sort of precedent. (Especially if you make the tenuous assumption
                > that True,False are language-supported 'enums' for 0 and 1.)[/color]

                I'm against it. I don't like the following returning True:

                ShirtSize.small in [ShirtSize.Mediu m, AppleSize.small]


                I also think it may cause problems with other comparisons.

                Supose the following:

                col = Enum('red', 'green', 'blue')
                paint = Enum('violet' , 'blue', 'red')

                Then we get the following situation:

                col.red == paint.red and col.blue == paint.blue

                but

                col.red < col.blue and paint.blue < paint.red

                --
                Antoon Pardon

                Comment

                • Ben Finney

                  #9
                  Re: Enumeration idioms: Values from different enumerations

                  Antoon Pardon <apardon@forel. vub.ac.be> writes:[color=blue]
                  > Ben Finney wrote:[color=green]
                  >> The 'enum' package in Cheeseshop [defines enumerations as]
                  >> sequences (of unique arbitrary values), that can be iterated and
                  >> tested for membership.[/color]
                  >
                  > Sure but we do have this:
                  >[color=green][color=darkred]
                  >>>> from enum import Enum
                  >>>> day = Enum('mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun')
                  >>>> col = Enum('red', 'green', 'blue')
                  >>>> lst= [day.mon, col.red]
                  >>>> col.blue in lst[/color][/color]
                  > [...]
                  > enum.EnumValueC ompareError: Not values from the same enumeration:[/color]

                  Yes, that looks like a case in favour of allowing at least equal-value
                  and not-equal-value comparisons.
                  [color=blue][color=green]
                  >> The problem with "is the same value" as an explanation for '==' is
                  >> that it doesn't help in cases such as::
                  >>[color=darkred]
                  >> >>> ShirtSize = Enum('small', 'medium', 'large')
                  >> >>> AppleSize = Enum('small', 'large')[/color]
                  >>
                  >> What should be the result of this comparison::
                  >>[color=darkred]
                  >> >>> ShirtSize.small == AppleSize.small[/color]
                  >>
                  >> Are they "the same value"? They're both "small" (and they both coerce
                  >> to the same string value, and in this case the same integer value).
                  >>
                  >> If not, is 'False' the right way to indicate that?[/color]
                  >
                  > I would agree 'False' is the right answer here.[/color]

                  Antoon Pardon wrote:[color=blue]
                  > Ben Finney wrote:[color=green]
                  > > Would it be better if every Enum instance had its own unique
                  > > subclass of EnumValue, that was used to instantiate values for
                  > > that enumeration?[/color]
                  >
                  > If you decide on keeping the current behaviour when comparing
                  > values of different enumerations, I would definitely answer
                  > yes.[/color]

                  If values from different enums were to be compared for equality (and
                  not raise an exception), would it still be good to have those values
                  be of different types?
                  [color=blue]
                  > This is a difficult question, because AFAIU python doesn't have
                  > clear guidelines for [comparisons between differing types]. I also
                  > have the impression that comparisons are used for two different
                  > reasons.[/color]
                  [color=blue]
                  > The first is compare things in a mathematical kind of way in which
                  > how things are compared is important.[/color]
                  [color=blue]
                  > The second is more an ordering mechanisme. Whether a string is
                  > greater than an int or vice versa, is not imporant what is important
                  > is that this order is consistent and can be used in binary searches,
                  > trees and other structures to organise data.[/color]
                  [color=blue]
                  > Now python has only one collection of compare operators which can
                  > cause conflicts. For instance, one could impose an order on sets to
                  > use for such structure but that goes against the normal order on
                  > sets which is based on subsets.[/color]
                  [color=blue]
                  > The only advise I have here is look at PEP 3000 that states:[/color]
                  [color=blue]
                  > Comparisons other than == and != between disparate types will raise
                  > an exception unless explicitly supported by the type.[/color]
                  [color=blue]
                  > Which seem to imply that == and != should not raise an exception but[color=green]
                  > >, >=, <, <= should.[/color][/color]

                  This seems like a good guide for a policy on enumerations.

                  How about this proposal:

                  Enumerations (instances of Enum) contain a fixed sequence of unique,
                  arbitrary values. The values within an enumeration are instances of a
                  type (subclass of EnumValue), unique to that enumeration.

                  Values from an enumeration can be compared for equality (__eq__,
                  __ne__) with any other value, and will only return True for the same
                  value from the same enumeration, otherwise False. Other comparison
                  operations can be performed only with values from the same
                  enumeration, otherwise an exception (EnumValueCompa reError, subclass
                  of ValueError) is raised.

                  This might result in the following simplistic implementation: :

                  class EnumValue(objec t):
                  # ...

                  def __eq__(self, other):
                  result = False
                  if self is other:
                  result = True
                  return result

                  def __cmp__(self, other):
                  if isinstance(othe r, EnumValue):
                  if is_same_enumera tion(self, other):
                  result = cmp(self.index, other.index)
                  else:
                  raise EnumValueCompar eError(self, other)
                  return result

                  This gives meaning to the "equal value" comparisons, but ensures that
                  other comparisons are errors.

                  Comments so far?

                  --
                  \ "I like to fill my bathtub up with water, then turn the shower |
                  `\ on and pretend I'm in a submarine that's been hit." -- Steven |
                  _o__) Wright |
                  Ben Finney

                  Comment

                  • Paul Rubin

                    #10
                    Re: Enumeration idioms: Values from different enumerations

                    Ben Finney <bignose+hate s-spam@benfinney. id.au> writes:[color=blue]
                    > This gives meaning to the "equal value" comparisons, but ensures that
                    > other comparisons are errors.
                    >
                    > Comments so far?[/color]

                    What does copy.copy of an enumeration value do? What happens if you
                    have a list with some enumeration values inside, and you make a
                    deepcopy of it? What happens if you pickle an enum, then unpickle the
                    pickle and compare what comes out to the other enum?

                    All in all, comparing by object identity doesn't sound too good.
                    Maybe you want to have the enum contain its own name internally, and
                    do a string comparison.

                    Comment

                    • Antoon Pardon

                      #11
                      Re: Enumeration idioms: Values from different enumerations

                      > Antoon Pardon wrote:[color=blue][color=green]
                      >> Ben Finney wrote:[color=darkred]
                      >> > Would it be better if every Enum instance had its own unique
                      >> > subclass of EnumValue, that was used to instantiate values for
                      >> > that enumeration?[/color]
                      >>
                      >> If you decide on keeping the current behaviour when comparing
                      >> values of different enumerations, I would definitely answer
                      >> yes.[/color]
                      >
                      > If values from different enums were to be compared for equality (and
                      > not raise an exception), would it still be good to have those values
                      > be of different types?[/color]

                      Yes, because people who would need a quick and dirty ordering
                      could then use the type of the object as a first key.
                      [color=blue][color=green]
                      >> The only advise I have here is look at PEP 3000 that states:[/color]
                      >[color=green]
                      >> Comparisons other than == and != between disparate types will raise
                      >> an exception unless explicitly supported by the type.[/color]
                      >[color=green]
                      >> Which seem to imply that == and != should not raise an exception but[color=darkred]
                      >> >, >=, <, <= should.[/color][/color]
                      >
                      > This seems like a good guide for a policy on enumerations.
                      >
                      > How about this proposal:
                      >
                      > Enumerations (instances of Enum) contain a fixed sequence of unique,
                      > arbitrary values. The values within an enumeration are instances of a
                      > type (subclass of EnumValue), unique to that enumeration.
                      >
                      > Values from an enumeration can be compared for equality (__eq__,
                      > __ne__) with any other value, and will only return True for the same
                      > value from the same enumeration, otherwise False. Other comparison
                      > operations can be performed only with values from the same
                      > enumeration, otherwise an exception (EnumValueCompa reError, subclass
                      > of ValueError) is raised.[/color]

                      Looks good to me.
                      [color=blue]
                      > This might result in the following simplistic implementation: :
                      >
                      > class EnumValue(objec t):
                      > # ...
                      >
                      > def __eq__(self, other):
                      > result = False
                      > if self is other:
                      > result = True
                      > return result
                      >
                      > def __cmp__(self, other):
                      > if isinstance(othe r, EnumValue):
                      > if is_same_enumera tion(self, other):
                      > result = cmp(self.index, other.index)
                      > else:
                      > raise EnumValueCompar eError(self, other)
                      > return result
                      >
                      > This gives meaning to the "equal value" comparisons, but ensures that
                      > other comparisons are errors.
                      >
                      > Comments so far?[/color]

                      Isn't there an else missing? I have the impression that if you compare
                      two enums from a different enumeration __cmp__ will raise UnboundLocalErr or.

                      --
                      Antoon Pardon

                      Comment

                      • Ben Sizer

                        #12
                        Re: Enumeration idioms: Values from different enumerations


                        Antoon Pardon wrote:[color=blue]
                        > Op 2005-12-16, Ben Sizer schreef <kylotan@gmail. com>:[color=green]
                        > > Is it possible to make it have the following sort of behaviour? :
                        > >[color=darkred]
                        > >>>> ShirtSize.small == AppleSize.small[/color]
                        > > True[color=darkred]
                        > >>>> ShirtSize.small is AppleSize.small[/color]
                        > > False
                        > >
                        > > It works for comparing a boolean (True) vs. an integer (1), so it has
                        > > some sort of precedent. (Especially if you make the tenuous assumption
                        > > that True,False are language-supported 'enums' for 0 and 1.)[/color]
                        >
                        > I'm against it. I don't like the following returning True:
                        >
                        > ShirtSize.small in [ShirtSize.Mediu m, AppleSize.small][/color]

                        I agree to an extent. I can see that being unwanted behaviour, although
                        not really a big one, and no worse than in C++. I think that when you
                        have a list of alternatives like that, they're either hard-coded by
                        selectively picking from the enumeration's initialisation list, or by
                        being generated according to some other criteria. Either way, it would
                        be hard to end up with the wrong type of value into that list, I think.
                        [color=blue]
                        > I also think it may cause problems with other comparisons.
                        >
                        > Supose the following:
                        >
                        > col = Enum('red', 'green', 'blue')
                        > paint = Enum('violet' , 'blue', 'red')
                        >
                        > Then we get the following situation:
                        >
                        > col.red == paint.red and col.blue == paint.blue
                        >
                        > but
                        >
                        > col.red < col.blue and paint.blue < paint.red[/color]

                        I don't think that's a problem - does any other language make any
                        guarantees on ordering across multiple enumerations? Transitivity
                        within any single enumeration plus transivity of equivalence across
                        multiple enumerations, should be enough for most needs, no?

                        --
                        Ben Sizer

                        Comment

                        • skip@pobox.com

                          #13
                          Re: Enumeration idioms: Values from different enumerations


                          Without downloading and installing your code, can you tell me what the
                          result of these comparisons would be?

                          col = Enum('red', 'green', 'blue')
                          day = Enum('mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun')
                          col.blue == "blue"
                          day.tue == 23

                          If they return False I would expect

                          col.blue == day.tue

                          to return False as well, not raise an exception.

                          Skip

                          Comment

                          • skip@pobox.com

                            #14
                            Re: Enumeration idioms: Values from different enumerations

                            [color=blue][color=green][color=darkred]
                            >>>> ShirtSize = Enum('small', 'medium', 'large')
                            >>>> AppleSize = Enum('small', 'large')[/color][/color][/color]

                            Ben> What should be the result of this comparison::
                            [color=blue][color=green][color=darkred]
                            >>>> ShirtSize.small == AppleSize.small[/color][/color][/color]

                            False. They are values from different objects. Just make __eq__ map to
                            "is". I think you'll be fine.

                            Ben> Or is it an error to even try comparing them?

                            As someone else pointed out containment tests become difficult with your
                            current formulation.
                            [color=blue][color=green]
                            >> Do any python builtins behave that way? How about anything in the
                            >> python standard library?[/color][/color]

                            Ben> No to both; I believe this may be a defining property of
                            Ben> enumerations. Am I wrong?

                            I think so. <0.5 wink>. I think you should be able to compare any two
                            objects. I think the complex types give you a little wiggle room on the
                            size comparisons (<, <=, >, >=), but I think == and != really ought to work.

                            Skip

                            Comment

                            • Mike Meyer

                              #15
                              Re: Enumeration idioms: Values from different enumerations

                              Ben Finney <bignose@polar. local> writes:[color=blue]
                              > Mike Meyer <mwm@mired.or g> writes:[color=green]
                              >> Peter Hansen <peter@engcorp. com> writes:[color=darkred]
                              >>> That is, [perhaps] trying to compare enumerations that should not
                              >>> be compared *is* an error (raising an exception) *because* the
                              >>> whole point of enumerations is to avoid errors in such cases.[/color]
                              >> Except it might not be an error. For instance, if I've got a list of
                              >> enum objects taken from various types (say I've got one set of enums
                              >> for days of the week, another for months of the year, and so on, and
                              >> which I use depends on whether the user wants to select days of the
                              >> week, months of the year, etc), it makes perfect sense to want to know
                              >> if a specific enum value is in the list, and the obvious way to check
                              >> it is with "my_value in enum_list". That won't work if you raise an
                              >> exception - it takes a relatively convoluted bit of code to make this
                              >> test.[/color]
                              > What's being discussed here is what happens when comparing the *values*
                              > from the enumeration.[/color]

                              That's what I thought I was discussing, but apparently I wasn't clear
                              enough. Let me try again.

                              I think it's perfectly reasonable to store enum values from different
                              enums in a list, and check for a specific value being in that list. If
                              comparing two enum values can raise an exception, then doinng this
                              become problematic, as you may get an exception. According to what you
                              say below, this isn't true for any builtin type or any type in the
                              standard library.
                              [color=blue][color=green]
                              >> Python generally uses '==' to mean "is the same value". To do that,
                              >> a simple true/false return is enough. In raising an exception,
                              >> you're making '==' carry an extra meaning (I'm not sure *what* that
                              >> is, though).[/color]
                              > The problem with "is the same value" as an explanation for '==' is
                              > that it doesn't help in cases such as::[color=green][color=darkred]
                              > >>> ShirtSize = Enum('small', 'medium', 'large')
                              > >>> AppleSize = Enum('small', 'large')[/color][/color][/color]

                              Actually, it provides a very explicit guideline for these cases. The
                              guidelines is by no means obvious, as witness languages like LISP,
                              which have multiple equality operators.
                              [color=blue]
                              > What should be the result of this comparison::[color=green][color=darkred]
                              > >>> ShirtSize.small == AppleSize.small[/color][/color]
                              > Are they "the same value"? They're both "small" (and they both coerce
                              > to the same string value, and in this case the same integer value).[/color]

                              That depends on the semantics you want to place on the values of
                              enums. Reasonable arguments can be made for anything from "they're
                              exactly like small integers" to "the values are an implementation
                              detail, and you shouldn't worry about them." That they coerce to the
                              same string is irreleevant, at least in python, which doesn't coerce
                              strings to
                              [color=blue][color=green]
                              >> Do any python builtins behave that way? How about anything in the
                              >> python standard library?[/color]
                              > No to both; I believe this may be a defining property of
                              > enumerations. Am I wrong?[/color]

                              There are enum implementations that don't treat comparing enum values
                              from different enums as an error, so I'd say you're wrong. In Python's
                              case, comparing two objects for identity never raises an exception for
                              any type that comes with the language, so I'd say that that was a
                              defining property of python.

                              <mike
                              --
                              Mike Meyer <mwm@mired.or g> http://www.mired.org/home/mwm/
                              Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.

                              Comment

                              Working...