Why self?

Alex Martelli aleax at aleax.it
Tue Jul 9 03:05:03 EDT 2002


Robb Shecter wrote:

> Brian Quinlan wrote:
>>...  Actually, private instance
>> variables are uncommon in general.
> 
> Sounds like a difference in design philosophies.  In my code, private
> everything is the norm, with a very thin/small public API.

Wise artisans learn a tool's strengths and use those strengths rather
than fighting against the tool.  Your "design philosophy", *actively*
_hiding_ information, may be OK with other languages (one could do a
lot of debate about that -- see later for a start), but it's definitely
not the most productive way to use Python (or several other tools
with similar underlying philosophies).

What I see as the fallacy of "information hiding" as an active purview
(having pursued it diligently for lo those many years) is that it
reflects and responds to an assumed underlying "pecking order" which,
upon reflection, is not a best fit for most projects.  To wit: the
designers of libraries and frameworks do an excellent job defining
exactly what functionality the client-code programmers need; those
client-code programmers, on the other hand, are rater clueless blokes
who'll trample all over the carefully designed library / framework
architecture unless strictly held in check for their own good.

Just doesn't work that way -- not in organizations that aren't already
dysfunctional, not in projects that are decently managed.  I'm not
very interested in choosing tools and design philosophies to enhance
the thin chances of projects using rigid "waterfall" methodologies,
_without_ decent levels of code-inspection, in some dysfunctional
organization where "application programmers" are thought of as an
unruly, lower-caste breed unable to follow a few sensible principles
without the equivalent of electric cattle prods to motivate them.

I recommend Highsmith's new survey of "Agile Software Development
Ecosystems" for a background on what I have in mind as the applicable
ranges of usable methodologies -- then, one may reflect on how such
social structures should best be reflected in tools and design.

The boundaries of any subsystem should be clean, with emphasis on
simplicity and clarity of working code rather than architectural
elaboration.  Architectural sophistication should enter when it is
strongly demanded by _reality_, rather than as an anticipatory 
move on the part of a presumed-to-be-all-seeing "Designer" (with
a mandatory uppercase D).  Design is in good part the task of
unearthing the simplicity that too often lies buried and hidden
under elaborate, complicated layers -- over-generalization and
over-specialization being both able to hide that simplicity.  Too
many libraries and frameworks meant to be _reusable_ are barely
even _usable_ -- and language tools that allow a designer to
_enforce_ (rather than _suggest_) usage rigidity don't help at all.

public/private is one such tool, and there are others -- such as
methods that are not overridable (Java's "final") or not virtual
(C++), _data_ that is not overridable (Python is exceptionally good
at letting you override data as well as code -- it makes the
Template Method design pattern into an even stronger powerhouse
than in other OO languages, as it now mixes so naturally with
data-driven, interpretive-like structures!), hard-coded names
and types.

C++'s templates do away with much of that, in favour of verbal
specifications of "what is this thing supposed to do" and even
the O()-performance constraints on "this thing" -- C++'s standard
library (and the still-under-development STL which inspired it)
is a great monument to the power of generic programming.  Python
(apart from wrapping it all in much more elegant syntax) takes
this to new height (at a performance cost, of course) by doing
it at runtime and thus even more flexibly.


I guess it can be argued that in order to _learn_ to ride a
bicycle it's best to have training wheel and just one gear
ratio.  Although, I've seen, in some of the regions where
bicycles are most widespread (Bologna is on the outskirts of
one such largish region), kids learning to ride on real, full
fledged bicycles rather than "kid stuff" ones, and being none
the worse for that.  I wonder if Amsterdam (which is surely
another major region of intense bicycle use, and Python's
birthplace) has a similar philosophy, and whether this may
have influenced Python itself (Guido has surely used _locks_
on bicycles as a metaphor to explain Python's _advisory_ concept
of "private" -- but that's a slightly different issue).

Be that as it may, production-level coding, like effective
cycling, benefits from flexibility (many gear ratios, for
example, so you can choose the best one at each time) and
simplicity (the everyday miracle of a bicycle's inherent
dynamic equilibrium) rather than from training wheels (supposed 
to stop you from losing your balance).


>> Python forces you to be explicit. That way we will know what you are
>> doing, right or wrong.
> 
> Mmmm - I dunno; I think this same argument could be used in the Java
> world for some of the things the language forces you to do, like
> explicit casting and declarations:
> 
> String name = (String) aVector.element(0)
> 
> Python doesn't have any problems with implicitness here...

If you want to force a _string_ representation of aVector's first
element to be bound to variable name, you'll code:
        name = str(aVector[0])
which is roughly on a par with the Java construct -- you use the
indexing operator [] rather than calling an '.element' method,
and function call syntax str(...) rather than cast syntax, but
that's all pretty much syntax sugar.

Python doesn't force you to lose flexibility by specifying types
when you'r rather keep polymorphism -- that's a totally different
issue.  You CAN force types (e.g. by calling str), you don't
HAVE to (you can just get a reference, if that is what you want).

The use of implicit scoping in Java (and similar languages) is
not polymorphic.  Therefore, no flexibility is lost by making the
scope clearer, the way Python does.  Simplicity and clarity gain,
without flexibility loss -- an obvious, large win.

The way some people are going ballistic about using self.whatever
(rather than typical C++'s m_whatever, &c) can be seen as either
tragic or ridiculous -- I'll choose the latter viewpoint, most
particularly given the temporal coincidence with yet another
round of the recurring saga of the joiner.join haters... a good 
indication that the time draws near for me to drop out of c.l.py
again -- I can't really afford the time even for serious, useful,
constructive discourse here, when I should be writing and editing
and coding, much less for yet another round of such so-often
fought flamewars.  It's not as if there's any actual risk of
beautiful Python being destroyed by such ridiculous ideas becoming
real, after all -- it's survived hundreds such tempests-in-teapots,
it will survive a couple more.


Alex




More information about the Python-list mailing list