<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
  </head>
  <body text="#330033" bgcolor="#FFFFFF">
    <div class="moz-cite-prefix">On 5/13/2013 7:36 PM, Ethan Furman
      wrote:<br>
    </div>
    <blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">On
      05/10/2013 10:15 PM, Glenn Linderman wrote:
      <br>
      <blockquote type="cite">
        <br>
        So it is quite possible to marry the two, as Ethan helped me
        figure out using an earlier NamedInt class:
        <br>
        <br>
        class NIE( IntET, Enum ):
        <br>
             x = ('NIE.x', 1)
        <br>
             y = ('NIE.y', 2)
        <br>
             z = ('NIE.z', 4)
        <br>
        <br>
        and then expressions involving members of NIE (and even
        associated integers) will be tracked... see demo1.py.
        <br>
        <br>
        But the last few lines of demo1 demonstrate that NIE doesn't
        like, somehow, remember that its values, deep down under
        <br>
        the covers, are really int.  And doesn't even like them when
        they are wrapped into IntET objects.  This may or may not
        <br>
        be a bug in the current Enum implementation.
        <br>
      </blockquote>
      <br>
      [demo1.py excerpt]
      <br>
          print( repr( NIE1( 1 ) + NIE1(2)))
      <br>
          print( repr( NIE1( IntET('NIE1.x', 1 )) + NIE1(2)))
      <br>
      <br>
      <br>
      <blockquote type="cite">So the questions are:
        <br>
        1) Is there a bug in ref435 Enum that makes demo1 report errors
        instead of those lines working?
        <br>
      </blockquote>
      <br>
      Nope.
      <br>
    </blockquote>
    <br>
    Well, if it isn't a bug, it will be interesting to read the
    documentation that explains the behavior, when the documentation is
    written:<br>
    <br>
    The "obvious" documentation would be that Enum names values of any
    type, particularly the first type in the multiple-inheritance list. 
    The values assigned to the enumeration members are used as
    parameters to the constructor of that first type, but the value of
    the enumeration member itself is an item of the type, created by the
    constructor.<br>
    <br>
    The __call__ syntax  [ EnumDerivation( value ) ] looks up
    enumeration members by value.<br>
    <br>
    The obvious documentation would stop there.  But if demo1 doesn't
    demonstrate a bug, it would have to continue, saying something like:<br>
    <br>
    However, if you have a complex type, you can't look up by value, but
    rather have to resupply the constructor parameters used to create
    the item. This means that for simple types<br>
    <br>
    EnumDerivation( EnumerationMember.value ) is EnumerationMember<br>
    <br>
    but that doesn't hold for complex types.  I think it should.<br>
    <br>
    <br>
    <blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">
      <blockquote type="cite">2) Is something like demo2 interesting to
        anyone but me? Of course, I think it would be great for
        reporting flag values
        <br>
        using names rather than a number representing combined bit
        fields.
        <br>
      </blockquote>
      <br>
      No idea.  ;)
      <br>
      <br>
      <blockquote type="cite">3) I don't see a way to subclass the
        ref435 EnumMeta except by replacing the whole __new__ method...
        does this mechanism
        <br>
        warrant a slight refactoring of EnumMeta to make this mechanism
        easier to subclass with less code redundancy?
        <br>
      </blockquote>
      <br>
      I've broken it down to make subclassing easier.
      <br>
    </blockquote>
    <br>
    Thanks... I'll take a look, eventually, but I'll be offline until
    next week.<br>
    <br>
    <blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">
      <blockquote type="cite">4) Or is it simple enough and useful
        enough to somehow make it a feature of EnumMeta, enabled by a
        keyword parameter?
        <br>
      </blockquote>
      <br>
      Probably not.
      <br>
      <br>
      <blockquote type="cite">5) All this is based on "IntET"... which
        likely suffices for API flags parameters... but when I got to
        __truediv__ and
        <br>
        __rtruediv__, which don't return int, then I started wondering
        how to write a vanilla ET class that inherits from
        <br>
        "number" instead of "int" or "float"? One could, of course, make
        cooperating classes FloatET and DecimalET .... is this
        <br>
        a language limitation, or is there more documentation I haven't
        read? :)   (I did read footnote [1] of
        <br>
        <a class="moz-txt-link-rfc2396E" href="http://docs.python.org/3/reference/datamodel.html#emulating-numeric-types"><http://docs.python.org/3/reference/datamodel.html#emulating-numeric-types></a>,
        and trembled.)
        <br>
      </blockquote>
      <br>
      Sounds like a fun project (for some value of fun ;)
      <br>
    </blockquote>
    <br>
    Not sure I'll get there, for a few years... such might be useful in
    certain debugging scenarios, but not sure it is useful enough to
    implement, given the footnote, except, perhaps, to truly become an
    expert in the Python object model.<br>
    <br>
    <blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">Okay,
      sorry for the long delay.
      <br>
      <br>
      What it comes down to is if you want to marry two complex types
      together, you may have to be the counselor as well. ;)
      <br>
    </blockquote>
    <br>
    :)  I assume by "counselor" you mean the code for __new__ and
    __init__ below, which, when I get a chance to understand them, will
    probably explain some of your earlier remarks about it maybe being
    easier to implement in such a manner.  Of course, I don't
    particularly want to marry the types, just have XxxEnum work for
    IntET as well as it does for int... I was bumping into name
    conflicts between Nick's implementation and yours, that weren't
    immediately obvious to me, because I haven't done multiple
    inheritance much — Enum is dragging me into that and metaclasses,
    though, which is a good thing for me, likely.<br>
    <br>
    The one piece of "marriage" that is interesting is to avoid
    specifying the name twice, and it seems your code<br>
    <br>
    <blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">Here's
      your code, revamped.  I did make a slight change in the meta --  I
      moved the name assignment above the __init__ call so it's
      available in __init__.
      <br>
    </blockquote>
    <br>
    That's handy, thanks.<br>
    <br>
    <blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">
      <br>
      --8<--------------------------------------------------------
      <br>
      from ref435 import Enum
      <br>
      from flags import IntET
      <br>
      <br>
      class NIE1( IntET, Enum ):
      <br>
          x =  1
      <br>
          y =  2
      <br>
          z =  4
      <br>
          def __new__(cls, value):
      <br>
              member = IntET.__new__(cls, 'temp', value)
      <br>
              member._value = value
      <br>
              return member
      <br>
          def __init__(self, value):
      <br>
              self._etname = self._name
      <br>
      <br>
      print( repr( NIE1.x.value ))
      <br>
      print( repr( NIE1.x + NIE1.y ))
      <br>
      print( repr( NIE1.x + ~ NIE1.y))
      <br>
      print( repr( NIE1.x + ~ 2 ))
      <br>
      print( repr( NIE1.z * 3 ))
      <br>
      <br>
      <br>
      print( repr( NIE1( 1 ) + NIE1(2)))
      <br>
      print( repr( NIE1( IntET('NIE1.x', 1 )) + NIE1(2)))
      <br>
      --8<--------------------------------------------------------
      <br>
      <br>
      and my results:
      <br>
      <br>
      1
      <br>
      IntET('(x + y)', 3)
      <br>
      IntET('(x + ~y)', -2)
      <br>
      IntET('(x + -3)', -2)
      <br>
      IntET('(z * 3)', 12)
      <br>
      IntET('(x + y)', 3)
      <br>
      IntET('(x + y)', 3)
      <br>
    </blockquote>
    <br>
    I'd expect  NIE1.x.value  to be  IntET('x', 1)  but I'll have to
    look more carefully at what you've done, when I have some time next
    week. You may have made some "simplifying assumptions", and things
    _should_ be as simple as possible, but no simpler... especially not
    if it leads to unexpected results.<br>
    <br>
    <blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">Oh,
      and if you really wanted the 'NEI' in the _etname, change the name
      assignment:
      <br>
      <br>
          self._etname = 'NIE.' + self._name<br>
    </blockquote>
    <br>
    Sure.  I did, because one problem that might arise is the
    combination of NIE-style enums from different enumerations... not
    prohibited for IntEnum or NIE, because it gets converted to the base
    type (int or IntET, respectively).  But if someone accidentally
    combines an enumeration member from NIE1 and an enumeration member
    from NIE2, and it has the same member name, the expression could
    "look right" without the class name included.  So you see, including
    the class name was not just a whim, but the result of analyzing
    potential error cases.<br>
    <br>
    <blockquote type="cite">Forget to mention the good part -- in the
      custom __new__ you are able to set the value to whatever you want
      (not a big deal in this case, but if you had several parameters
      going in you could still make _value be a single, simple int).
    </blockquote>
    <br>
    This will take more thought than I have time for tonight, also. 
    Right now, I think I want the value for NIE.x to be IntET('NIE.x', 1
    ).  And your code isn't achieving that at present, but maybe I just
    need to tweak __new__ and then can... and maybe it cures the
    discrepancy in expectations mentioned earlier too...<br>
    <br>
    On the other hand, when I think about it more, maybe I'll see what
    you are suggesting as a better path, for some reason.  But I think
    it is the case at present, that what you think I want, is different
    than what I think I want :)<br>
  </body>
</html>