Andrew Cooke | Contents | Latest | RSS | Twitter | Previous | Next

C[omp]ute

Welcome to my blog, which was once a mailing list of the same name and is still generated by mail. Please reply via the "comment" links.

Always interested in offers/projects/new ideas. Eclectic experience in fields like: numerical computing; Python web; Java enterprise; functional languages; GPGPU; SQL databases; etc. Based in Santiago, Chile; telecommute worldwide. CV; email.

Personal Projects

Lepl parser for Python.

Colorless Green.

Photography around Santiago.

SVG experiment.

Professional Portfolio

Calibration of seismometers.

Data access via web services.

Cache rewrite.

Extending OpenSSH.

C-ORM: docs, API.

Last 100 entries

[Link, Politics, USA] The Future Of American Democracy; Mass Hysteria; [Review, Books, Links] Kazuo Ishiguro - Never Let Me Go; [Link, Books] David Mitchell's Favourite Japanese Fiction; [Link, Bike] Rear Suspension Geometry; [Link, Cycling, Art] Strava Artwork; [Link, Computing] Useful gcc flags; [Link] Voynich Manuscript Decoded; [Bike] Notes on Servicing Suspension Forks; [Links, Computing] Snap, Flatpack, Appimage; [Link, Computing] Oracle is leaving Java (to die); [Link, Politics] Cubans + Ultrasonics; [Book, Link] Laurent Binet; VirtualBox; [Book, Link] No One's Ways; [Link] The Biggest Problem For Cyclists Is Bad Driving; [Computing] Doxygen, Sphinx, Breathe; [Admin] Brokw Recent Permalinks; [Bike, Chile] Buying Bearings in Santiago; [Computing, Opensuse] Upgrading to 42.3; [Link, Physics] First Support for a Physics Theory of Life; [Link, Bike] Peruvian Frame Maker; [Link] Awesome Game Theory Tit-For-Tat Thing; [Food, Review] La Fabbrica - Good Italian Food In Santiago; [Link, Programming] MySQL UTF8 Broken; [Link, Books] Latin American Authors; [Link, Computing] Optimizatin Puzzle; [Link, Books, Politics] Orwell Prize; [Link] What the Hell Is Happening With Qatar?; [Link] Deep Learning + Virtual Tensor Machines; [Link] Scaled Composites: Largest Wingspan Ever; [Link] SCP Foundation; [Bike] Lessons From 2 Leading 2 Trailing; [Link] Veg Restaurants in Santiago; [Link] List of Contemporary Latin American Authors; [Bike] FTHR; [Link] Whoa - NSA Reduces Collection (of US Residents); [Link] Red Bull's Breitbart; [Link] Linux Threads; [Link] Punycode; [Link] Bull / Girl Statues on Wall Street; [Link] Beautiful Chair Video; Update: Lower Pressures; [Link] Neat Python Exceptions; [Link] Fix for Windows 10 to Avoid Ads; [Link] Attacks on ZRTP; [Link] UK Jazz Invasion; [Review] Cuba; [Link] Aricle on Gender Reversal of US Presidential Debate; {OpenSuse] Fix for Network Offline in Updater Applet; [Link] Parkinson's Related to Gut Flora; Farellones Bike Park; [Meta] Tags; Update: Second Ride; Schwalbe Thunder Burt 2.1 v Continental X-King 2.4; Mountain Biking in Santiago; Books on Ethics; Security Fail from Command Driven Interface; Everything Old is New Again; Interesting Take on Trump's Lies; Chutney v6; References on Entropy; Amusing "Alexa.." broadcast; The Shame of Chile's Education System; Playing mp4 gifs in Firefox on Opensuses Leap 42.2; Concurrency at Microsoft; Globalisation: Uk -> Chile; OpenSuse 42.2 and Synaptics Touch-Pads; Even; Cherry Jam; Lebanese Writer Amin Maalouf; C++ - it's the language of the future; Learning From Trump; Chinese Writer Hu Fayun; And; Apricot Jam; Also; Excellent Article on USA Politics; Oh Metafilter; Prejudice Against The Rurals; Also, Zizek; Trump; Why Trump Won; Doxygen + Latex on CentOS 6; SMASH - Solve 5 Biggest Problems in Physics; Good article on racism, brexit, and social divides; Grandaddy are back!; Consciousness From Max Entropy; Democrats; Harvard Will Fix Black Poverty; Modelling Bicycle Wheels; Amusing Polling Outlier; If Labour keeps telling working class people...; Populism and Choice; Books on Defeat; Enrique Ferrari - Argentine Author; Transcript of German Scientists on Learning of Hiroshima; Calvert Journal; Owen Jones on Twitter; Possible Japanese Authors; Complex American Literature

© 2006-2017 Andrew Cooke (site) / post authors (content).

Python Enums on Crack, Part II

From: andrew cooke <andrew@...>

Date: Tue, 4 Jun 2013 08:50:28 -0400

Just under a month ago I wrote a disappointed rant[1] about the new Enum for
Python 3.

Since then I spent time extending the existing code[2] (to produce bnum[3]),
before changing direction and writing my own, alternative Enum from
scratch[4].  I've also swapped a few emails with various kind people.

While all that doesn't make me an expert, I do now have a better understanding
of the design and some of the choices it embodies.  So I thought I'd revisit
the points I made earlier and try explain why things work that way, where I
can, and what space for change still remains.


Implicit Values
---------------

In the original article I said that my first example -

  class Colour(Enum):
      red
      green

- was illegal syntax.  I was wrong.

When Python parses the class definition it looks for values in the dict of the
class that it is building.  Python 3's metaclass protocol allows us to provide
that dict, so we can use a subclass that assigns default values to unknown
names (and provide values from 'red' and 'green' instead of triggering an
error).

I use this trick in simple-enum[4], and the above is a valid declaration when
using that package.  But it's not a risk-free solution: there's the
possibility of very confusing errors / bugs.

The problem is that elsewhere in the code we may refer to a name in the global
scope.  The class dict will, incorrectly, provide a default value for that
name too.  And while you can reduce the effect[5], I am not (yet) convinced
that you can remove the risk entirely.


Implicit Values 2 (Strange Syntaxes)
------------------------------------

But all is not lost.  The PEP 0435 test code includes support for:

  class Colour(Enum):
      red = ...
      green = ...

which, although uglier, avoids the issues with "magic values".  This is not in
the default implementation, but it can be added by providing an alternate
metaclass).


Duplicate Values
----------------

Python 3's metaclass support includes keyword arguments.  Here's an example
from simple-enum:

  class WithAliases(Enum, implicit=False, allow_aliases=True):
      one = 1
      another_one = 1

Please ignore the 'implicit=False' (it does what you'd expect; it's needed
because of the shadowing issue I discussed earlier) - I am showing this
example because the 'allow_aliases' flag seems like a good solution to whether
or not duplicate values should be flagged: duplicates are errors by default,
but can be enabled if required.

Unfortunately I don't see anything likle this in the PEP 0345 code.  There's
no such flag (no metaclass keyword args are used at all) and no related tests.
But it is fairly easy to add - I included it in bnum[3].


Inheritance
-----------

The PEP Enum code is complicated by the need to support inheritance -
something that is used mainly (in the tests) to allow Enums to "be" integers.

In case the above is not clear, this is valid with PEP 0435:

  # PEP 0435
  class Number(int, Enum):
      one = 1
      two = 2

  > Number.one + Number.two
  3
  > isinstance(Number.one, Number)
  True
  > isinstance(Number.one, int)
  True

In contrast, the simple-enum implementation is, well, simpler, treating all
enumerations as named tuples (with name and value components), so equivalent
code would read:

  # simple-enum
  > Number.one.value + Number.two.value
  3

Now, after that long introduction, the question is: why does PEP 0435 have
this emphasis?  I chose the simple (but more verbose) solution because it
seemed easier to understand, simplified the implementation, and allowed me to
present enumerations in terms of both dicts and tuples (something I haven't
explained here, since I'm focussing on PEP 0435, but see [4] if you're
curious).

Nick Coghlan explained this to me, and it shone a completely new light on the
design: the PEP is designed to be backwards compatible with existing Python
library code.

For example, the socket module is full of constants like TIPC_ADDR_NAME and
AF_BLUETOOTH.  Existing code *expects* them to evaluate to whatever their
current value is.  Changing all that existing code to TIPC_ADDR_NAME.value is
impossible.  So the PEP Enum *must* "be" an int (or a str, or whatever the
original design chose) if these constants are going to be replaced by Enums.

Hence the inheritance.


Alternate Implcit Values
------------------------

I mentioned this in my rant, and support it in simple-enum with metaclass
keyword arguments (eg. 'values=from_zero'), but implicit values currently play
a very small part in the PEP 0435 Enum (they are available only through the
"functional API").


Language Changes
----------------

While the "names in a class" syntax is possible, it's something of a hack (see
above).  Since support for such a syntax might also help named tuples it's
interesting to ask whether the language could be extended in some way to
support this.  I don't have a concrete suggestion, but it seems like an
interesting avenue to explore.

A simpler change, which I stumbled across while considering alternatives, is
to extend matching to infinite sequences.  This would allow a syntax like:

  class SequenceBased(Enum):
      one, two, three, ... = count()


Summary
-------

Much of the design of the PEP 0435 Enum is driven by the requirement that it
be applied retroactively to existing classes (without changing existing code).
Honestly, to me, that seems a bit "too clever", but I understand the
temptation.

The "clean" syntax (names in a class) is possible in Python, but concerns
about opaque errors / bugs from name shadowing have excluded it from the PEP.
Alternative syntaxes (like 'name = ...') exist in the tests, but are not
enabled by default.

Duplicate values could be enabled by a named argument to the metaclass.  I
don't understand why this issue is missing from the code (even in the tests,
which otherwise do a good job of exploring alternative ideas).


[1] rant - http://www.acooke.org/cute/Pythonssad0.html
[2] PEP 0435 code - https://bitbucket.org/stoneleaf/ref435
[3] mod of [2] - https://github.com/andrewcooke/bnum
[4] new start - https://github.com/andrewcooke/simple-enum
[5] magic values - https://github.com/andrewcooke/simple-enum#the-danger-of-magic

The back-wards compatibility fallacy

From: Poul-Henning Kamp <phk@...>

Date: Tue, 04 Jun 2013 14:56:22 +0000

"Much of the design of the PEP 0435 Enum is driven by the
	requirement that it be applied retroactively to existing
	classes (without changing existing code).  Honestly, to me,
	that seems a bit "too clever", but I understand the
	temptation."

There is a finite amount of existing python code, it may be a lot of
python code, but it is a finite amount.

There is a unbounded amount of python code yet to be written and
in all likelyhood, much more python code will be written in the
future, than has been written in the past.

It is therefore a very short-sighted tradeoff and a grave mistake
to handicap such an important language tool as enums, just to cater
to the smaller of these two codebases.

If in doubt about this arguments validity, recall how
backwards-compat-at-all-cost-standardization has totally stopped
the evolution of the C language.

-- 
Poul-Henning Kamp       | UNIX since Zilog Zeus 3.20
phk@...         | TCP/IP since RFC 956
FreeBSD committer       | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.

Comment on this post