[Python-ideas] values in vs. values out
Jason Orendorff
jason.orendorff at gmail.com
Thu Jan 13 21:11:00 CET 2011
On Thu, Jan 13, 2011 at 9:21 AM, Luc Goossens <luc.goossens at cern.ch> wrote:
> Sorry maybe this was not clear from my mail but I am not so much interested
> in possible work-arounds but in why this asymmetry exists in the first
> place.
> I mean is there a reason as to why it is the way it is, or is it just that
> nobody ever asked for anything else.
There are two kinds of asymmetry here. One is semantic and one is syntactic.
1. Semantically, function calls are fundamentally asymmetric in
Python. A call takes as its input a tuple of arguments and a
dictionary of keyword arguments, but its output is either a single
return value or a single raised exception.
2. Syntactically, the syntax for composing a value (tuple expressions,
list/set/dict displays, constructor calls) differs from the syntax for
decomposing a value into its parts (unpacking assignment).
The ML family of programming languages eliminate both asymmetries
about as completely as I can imagine. ML functions take one argument
and return one value; either can be a tuple. The same pattern-matching
syntax is used to cope with parameters and return values. To a very
great degree the syntax for composing a tuple, record, or list is the
same as the syntax for decomposing it. So what you're asking is at
least demonstrably possible, at least for other languages.
So why does Python have these asymmetries?
1. The semantic asymmetry (functions taking multiple parameters but
returning a single value) is a subtle thing. Even in Scheme, where
conceptual purity and treating continuations as procedures are core
design principles of the entire language, this asymmetry is baked into
(lambda) and the behavior of function calls. And even in ML there is
*some* asymmetry; a function can die with an error rather than return
anything. (You can "error out" but not "error in".)
In Python's design, I imagine Guido found this particular asymmetry
made the language fit the brain better. It's more like C. The greater
symmetry in languages like ML may have felt like be too much--and one
more unfamiliar thing for new users to trip over.
In any case it would be impractical to change this in Python. It's
baked into the language, the implementation, and the C API.
2. The syntactic asymmetry is made up of lots of little asymmetries,
and I think it's enlightening to take a few of them case by case.
(a) You can write
[a, b] = [1, 2]
but not
{a, b} = {1, 2}
or
{"A": a, "B": b} = {"A": 1, "B": 2}
Sets have no deterministic order, so the second possibility is
misleading. The third is not implemented, I imagine, purely
for usability reasons: it would do more harm than good.
(b) You can write
x = complex(1, 2)
but not
complex(a, b) = x
In ML-like languages, you can identify constructors at compile
time, so it's clear on the left-hand side of something like this
what variables are being defined. In Python it's not so
obvious what this is supposed to do.
(c) Unlike ML, you can write
(a, b) = [1, 2]
or generally
a, b = any_iterable
It is useful for unpacking to depend on the iterable protocol
rather than the exact type of the right-hand side. This is a
nicety that ML-like languages don't bother with, afaik.
(d) You can write
def f(x, y, a) : ...
f(**dct)
but not
(x, y, a) = **dct
and conversely you can write
lst[1] = x
but not
def f(lst[1]): ...
f(x)
In both cases, I find the accepted syntax sane, and the
symmetric-but-currently-not-accepted syntax baffling.
Note that in the case of lst[1] = x, we are mutating an
existing object, something ML does not bother to make
easy.
All four of these cases seem to boil down to what's useful vs. what's
confusing. You could go on for some time in that vein.
Hope this helps.
-j
More information about the Python-ideas
mailing list