
Python's super considered harmful - prog
http://fuhm.net/super-harmful/
======
cturner
I think classical-inheritance subclassing is itself harmful. Subclassing
creates less flexible software than other approaches, and creates a need for
lots of boilerplate.

This issue - super in python - drives many new python programmers crazy.
However, I suspect most seasoned devs never think about it.

These days I never subclass or feel like I want to. Occasionally I'll use
'duck' typing where I would have subclassed in the past but I find that I
rarely even need that. The desire to use classes like this sets off an alarm
in my head that I'm making my code too complicated.

You do a lot of subclassing in Java. Java steers you there because it's so
onerous to use dictionaries and arrays/lists/tuples. The syntax for these
structures is simpler in python, and so they're more commonly-used.

Subclassing is particularly important for creating frameworks in java. You
build your world with packages, class hierarchies and 'bean' style objects.
Whereas in python you tend to abstract by module - sets of statics, functions
and lightweight structures.

I believe python would be stronger still had it had removed subclassing
altogether, and instead taken the prototype approach. In prototype languages
there's no such thing as a class. Everything is cloned off an original master
object. Functions and properties are tapped into the clone. Iolanguage has
many of these advantages but is far slower, lacks the reach of python's
standard library and (I think) also lacks python's awesome list-comprehension
syntax.

Someone with better articulation than me could generate blog traffic for
themselves by creating a pithy post about the difference in style between java
and python, and why subclassing is unpythonic. Then we could link to it when
these issues come up.

~~~
limmeau
I don't see much difference between a duck-typed language in which callables
with capitalized name are just expected to produce objects which obey a
certain duck type, and a prototype language.

The problem to which super is a (general and tricky) solution is the
consequences of _multiple_ class inheritance rather than class inheritance. A
single-inheritance super could be realized in a less tricky way.

~~~
cturner

        > I don't see much difference [..]
    

Agree, there's not much. But I have some scenarios in mind where I prefer the
prototype approach.

1) Inline classes

A pattern I sometimes use involves creating an object to maintain state before
a for loop. Example scenario: parsing characters as they come in over a
network line. Say the data has qutation blocks that create nesting situtaion.
You want to support both ' and " blocks.

It's a simple situation. You want an object that will store some kind of mode
for what scope you're in at the moment, and you'll be accumulating the
structure you're parsing. [1] You might want the object to have a render(self)
method as well, to dump the data once you've parsed it.

In io you can just say "Make me an object that does this". In python you
declare a class, and then instantiate an instance of it. It's needless to
create the class - there is absolutely only one time that I'm going to build
this thing. [2]

You could create a syntax that worked like python, but had a syntax that
addressed this without technically being a prototype language.

2) Adding functions to existing objects

In python there is ugliness involved in tapping a new function onto an
existing object. Python's a bit confusing here partly because of the way self
works. When I encounter this in python I usually do a lambda trick to make the
function a member of the object, and then I'll have some method on the object
that will refer to it. The equivalent in io is more straightforward.

    
    
        > A single-inheritance super could be realized in a less
        > tricky way.
    

True. I have and will never use multiple inheritance in python and would
prefer the simple syntax that would be made possible with single inheritance.

I remain interested in this broader issue of - is class-based inheritance a
good thing at all?

==

[1] In python you have to use a structure for this, because once you're in the
'for' loop, it won't let you rebind variables outside the scope of the for
loop, only modify them.

I haven't played with 'inline' yet.

[2] You could also use a dictionary, but I think that's a bit more verbose. An
object is just what I want in these situations.

~~~
btilly
For #1 you can just use a closure.

For #2, the method documented in
[http://stackoverflow.com/questions/972/adding-a-method-to-
an...](http://stackoverflow.com/questions/972/adding-a-method-to-an-existing-
object) doesn't seem so bad to me.

    
    
      object.methodname = new.instancemethod(function, object, class)
    

It may be deprecated. But it still works.

~~~
cturner

        > For #1 you can just use a closure.
    

I don't think that will work. See the discussion about rebinding in the post
or elsewhere in the thread.

~~~
btilly
It is unclear to me what you think doesn't work. A closure can easily store
state. As you yourself demonstrate in your rebinding example, you can store
and mutate scope if you use a mutable datastructure (like a list) to avoid
rebinding problems.

Perhaps if you gave an example of what you think doesn't work, I might
understand your point.

------
rhettinger
How Python's super() actually gets used:

[http://www.google.com/codesearch?as_q=super\\(&as_lang=py...](http://www.google.com/codesearch?as_q=super\\\(&as_lang=python)

~~~
ra
Indeed. super() is a hook / callback which permits a library to be used in
ways not envisaged by the original author.

~~~
masklinn
This definitely is not correct. Though there are many who argue that classes
should be designed for inheritance and that classes which are not should not
be inheritable (I'll leave that to your own judgement), when classes are
designed for inheritance you _do_ need a way to call your superclass.

And in Python's case, due to MI, you need a way to call your superclass _es_
in a consistent and sensible order even though these superclass _es_ are
unaware of one another (one might be "normally" inheritable while the other is
a mixin-type superclass for instance, or used to inject metaclass-based
behaviors). This is, as far as I know, a perfectly valid use case and one
which _requires_ a `super`-type utility (though Python's own `super` isn't
quite a flawless implementation of this).

------
shin_lao
I'm always irritated when I see such post.

My kitchen is full of knives, but I accidentally stab my wife only once or
twice per year. That's because I'm extra careful.

Same thing go with language constructs. I just don't throw features around and
see what happens.

~~~
sigzero
That's extra careful? I have been married 18 years and I have stabbed my wife
a total of ZERO times.

~~~
shin_lao
<http://en.wikipedia.org/wiki/Irony>

------
kolinko
"considered harmful" considered harmful:
<http://en.wikipedia.org/wiki/Considered_harmful>

------
cletus
Good post with solid examples.

At the risk of being down voted into oblivion (I know I would be on proggit by
the fundamentalist Pythonistas there): it seems to me that this just adds to
the list of Python issues that make the language far more complicated than it
really should be.

Examples that spring to mind:

\- The ongoing saga with the GIL (although I realize this has advantages in
simplifying C extension development) [1]

\- String formatting changing seemingly from 2.4 and every version thereafter
[2]

\- The 2.x/3.x split (yes I know there are reasons)

\- Version issues for scripting [3]

\- Syntax inconsistency. I know this one will be controversial but I'm
referring to things like the fact that del() is a operation

\- Other issues [4]

Isn't something like Ruby or Lua a lot cleaner in this regard? I ask this
question seriously.

[1]: <http://www.dabeaz.com/python/GIL.pdf>

[2]: <http://kuoi.com/~kamikaze/read.php?id=287>

[3]: <http://news.ycombinator.net/item?id=1712035>

[4]: [http://www.quora.com/What-are-the-main-weaknesses-of-
Python-...](http://www.quora.com/What-are-the-main-weaknesses-of-Python-as-a-
programming-language)

~~~
masklinn
> At the risk of being down voted into oblivion (I know I would be on proggit
> by the fundamentalist Pythonistas there)

You seem to be very well acquainted with proggit indeed as this kind of pre-
whining is quite common there. Though the little twist about it at the end is
a new (and quite despicable) addition to it.

> it seems to me that this just adds to the list of Python issues

Considering this page is at least two years old, it's older than e.g. most of
the GIL hubbub.

> The ongoing saga with the GIL (although I realize this has advantages in
> simplifying C extension development)

The GIL saga makes the whole language simpler (running directly opposite your
thesis that all these "points" make the language more complex), though it
_does_ make taking advantage of multiple cores harder (if you somehow have a
beef against multiple processes).

> String formatting changing seemingly from 2.4 and every version thereafter

You might want to read and test things before that kind of claims. When the
article you link says:

> In Python 2.5 and later, there's a new formatter

it means the old one is still there. It was not removed in Python 2.5 (or
later, `"It is %s!" % foo` still works perfectly in Python 3.1). The second
"point" of your article is hellishly disingenuous as it has _nothing_ to do
with formatting. It's also a pretty terrible article as it uses "long form"
formatting in the `format` calls (which are used to make bindings clearer,
whereas you can use C#-style positional formatting if your strings are short
and readable in and of themselves)… and then whines that the formatting calls
are too verbose.

And of course, coming from Perl the article you link to suggests… implicitly
pulling variables out of the context instead of explicitly sending them to
formatting.

> The 2.x/3.x split (yes I know there are reasons)

Indeed, and a number of these reasons center around making the language
simpler and more consistent (`print` as a function, reorganization of the
stdlib, ...).

> Version issues for scripting [2]

This has _nothing_ to do with Python as a language.

> Syntax inconsistency. I know this one will be controversial but I'm
> referring to things like the fact that del() is a operation

What are you talking about? What is `del()`? Are you talking about `del` as in
`del foo` and expressing your dislike of it being a statement? Considering the
original job of `del` (completely remove a binding from a scope), I'm not sure
what else it could have been (though I can't say I like it much, be it to
remove a binding from a scope or remove elements from structures). I'd also
enjoy your explanation of how it demonstrates inconsistency: which other
Python non-statement operation is able to destructively alter scopes? And is a
majority of the scope-altering operation non-statements? If it is not, would
not the non-statement scope-altering operations be inconsistent?

> Other issues [3]

Few of these are universally valid. In fact, I can find none that is apart
from whitespace making it harder (if not impossible) to generate code[0]. Some
of these complaints are plain nonsensical (Python being an "untyped
language"), most others are personal preferences which you may or may not
agree with (Python's scope confusion and crappy lambdas — or more precisely
overuse of statements as Haskell's lambdas have exactly the same limitation —
bug me a log, while TFAA's dislike of `eval` basically amounts to "I hate
languages where not everything is decided at compile time)

> Isn't something like Ruby or Lua a lot cleaner in this regard?

Ruby definitely is not, though the choices it made are most definitely
different. I don't know enough Lua to comment on it.

But if you want orthogonal and consistent languages, you probably should not
look at even remotely popular languages anyway: they're mostly hobbled
together. Even Haskell, which your [3] seems to hold as some kind of holy
grail, is a complex and not necessarily consistent language. Consistent
languages are generally very small (syntax-wise, as every syntactic construct
you add to the language exponentially increases your chances of breaking
syntactic consistency) and provide lots of power to users (e.g. the ability to
very easily define control-flow structures, increasing the risk of lowering
the "external" consistency of produced code). Examples of such languages are
Smalltalk, Forth, Lisp (especially, in my opinion, the Lisp-1 family). Though
really all of those should be pluralized as they pretty systematically ended
up forking from a common ancestor into a multitude of related-but-incompatible
(usually library-wise, sometimes syntax-wise or semantics-wise) languages.

[0] but then again, how often does that happen, and doesn't Python provide the
tools to generate a running system rather than have to statically generate
code which will then have to be compiled and run? I can't say I've often liked
_this kind_ code generation, which in my experience has more often lead to
pain and suffering than enjoyment, e.g. in GUI toolkits)

