Tuples -- who needs 'em

Martijn Faassen m.faassen at vet.uu.nl
Mon Apr 10 18:05:16 EDT 2000


Bob Alexander <bobalex at home.com> wrote:
> "Martijn Faassen" <m.faassen at vet.uu.nl> wrote:

> Thanks for your well-considered comments, but we still have our differences
> :-)

I didn't expect otherwise. :)

>> the idea of immutable
>> objects is that assigning them is exactly the same behavior as copying
>> them. That's something an easy thing to think about; for instance with
>> strings and numbers. The idea here is that tuples allow you to think that
>> way about lists.

> Well, immutable objects render the copy vs. reference semantics moot, since
> you can't change them anyway. With true copy semantics, the receiver of the
> copy can change the object without affecting the originator's object.

That's exactly what I meant. Since the difference is moot when you have
immutability, you lose all the subtleties involved with reference
semantics versus value semantics if you use immutable objects. Which
can make things easier to think about.

> But I
> agree that you can safely pass around references to immutable objects
> without fear of their being modified -- I guess that's the point of
> immutable.

Right.

>> Okay, but it's generally practiced in idiom. Language constructions can
>> exist that partially support idiom, but not enforce it, right? Here the
>> idea is to bind various immutable things together to something that's
>> still immutable. The immutability of non-tuples isn't there to
>> catch 'mutation' errors (as that there is no way to actually mutate them
>> at all). It's there for the nice semantics. Tuples supply the syntax and
>> semantics to do this with multiple immutable things. Your problem arises
>> because there's something very similar to a tuple, a, list, which does
>> support mutation syntax. Would you have the same trouble with immutable
>> strings if there were mutable strings in the language? And why not?

> You might ask, "why doesn't Python have both mutable strings and
> immutable?".

In fact, you can easily construct mutable strings from for instance
Arrays of characters in Python, but mutable strings are not clearly
present, that's true.

> Some languages (like Java) do. One answer: having both flavors
> doesn't buy us much, even though there might be an occasional use for a
> mutable string. I'm glad we don't have both flavors of string. Similarly, I
> don't think we need both mutable and immutable sequences. But in the case of
> sequences, it's the immutable flavor that doesn't buy us much.

> By the way, for those who contend that tuples are a good way to pass around
> groups of heterogeneous elements, I contend that they have some drawbacks.
> Take the example of "point" that was previously used in this thread. Create
> a point p = (11, 22). How do I refer to the elements? As p[0] and y[1]. Hmm,
> which is x and which is y?

No, you unpack it:

x, y = p

and then you refer to the elements.

> Wouldn't it be better if I could reference the
> elements by name, x.x and x.y? Some languages have record types where you
> can declare "record Point(x, y)", create an object as Point(11, 22), and
> refer to the elements as p.x and p.y.

In Python this is called 'class':

class Point:
    pass

mypoint = Point()
mypoint.x = 1
mypoint.y = 2

If you want convenience, write an __init__ function for Point. :)

> A language supporting this is Icon,
> and records are roughly as efficient as Python's tuples even though the
> elements have names.

I've seen the idea of named tuple addressing thrown around before on
the list; I think Paul Prescod came up with it a while back. It's
an interesting idea, might have some merits, but probably has hassles
too, and it's not certain it's worth those. Look up the thread in deja news
if you want a more detailed discussion.

> Even in JavaScript you can construct something like a
> tuple (but not immutable) with named elements using the same syntax as
> Python dictionary "literals" {x: 11, y: 22}.

What's wrong with using classes? 

> Although I clearly prefer
> Python as a language over JavaScript, that is a nice feature. Of course, you
> can effect the same behavior in Python, but not so conveniently.

Classes may be a trifle more verbose, but I don't really think my example
above was *that* verbose; even if you use an '__init__' method. And if 
they're too heavy weight, tuple unpacking is your friend. :)

> I think
> that tuple-type objects with named elements are superior to numbered
> elements for groups of heterogeneous elements, and that immutability is not
> often necessary and even sometimes an inconvenience.

It should rarely be necessary that you need to access tuple elements by
numbers; it's supposed to be a collection of heterogeneous objects (in
my understanding of idiom), and accessing by number usually doesn't make
any sense. Just unpack them.

[snip]
>> I do think the Python language supports the homogeniety idea. Just because
>> Python supports heterogeneous lists doesn't mean you should be using them
>> all over the place.

> But, why not? How is it damaging?

It's damaging if you go and access those heterogeneous objects by numerical
indexes. It isn't very readable. Why not use a tuple in such a
case and unpack it? Or if you have multiple similar heterogeneous lists,
use a list of tuples. Or of course you can always switch to classes.

> When I first discovered a language that
> did not require homogeniety (is that a word?) in lists, I though of it as an
> advantage, not a drawback. (That was Snobol4, a *long* time ago!) I still
> feel that way.

It's very powerful in OO as you can exploit polymorphism. The way the
.sort() method of lists uses the __cmp__() method is a good example.
I'm not sure what use it is to have a list of say, an integer, 3 strings,
an integer, and a floating point number, etc, etc, unless you're going
to treat this list somehow as a list of structs of objects. Which means
you should've been using tuples or classes in the first place, right?
Could you give me an example of where this is handy?

Of *course* the dynamic typing is an advantage, but still in by far the
most lists you're treating all items as *similar* objects. You assume
they all support the same interface; perhaps you do some checks like
hasattr() or type comparisons, but if that gets out of hand it usually
means your code isn't designed the right way, right?

> Some of my following responses reflect the fact that I haven't bought into
> the if-a-sequence-is-a-list-it-must-be-homogeneous concept.

[snip]

>> > There have been cases where I used tuples, to find out
>> > later that I wanted mutability, so went back and changed.
>>
>> Hm, I rarely if ever seem to run into this. If I need mutability of
>> a set of heterogenous objects I tend to use a class. There may be a
>> switch from tuples to classes, but not often from tuples to lists, I
>> think.

> Well, since I don't have an aversion to heterogeneous lists, it's kind of
> the same thing  :-) Yes, the proper choice is class, but a small list (or
> tuple) is much more convenient (for the coder, BTW, not the reader :-). And,
> after all, Python is a "rapid development" language where convenience is
> highly valued. Just don't forget which element number is which! Or if you
> change the order later, don't forget to change all the references.

I don't really understand how this is more convenient. I need to juggle
element numbers in my head, remember offsets, difficult. Unless you mean
you unpack the tuples. For small enough tuples you can usually remember
what's in them, but I do always need to look up the time tuple when
I use the time module. That might've been nicer as a class. :)

>> Perhaps you shouldn't think 'tuples or lists', but 'tuples or classes',
>> then?

> If tuple is a super-convenient-quickie substitution for class, then, to me,
> list is just a mutable version of the same concept. (And neither of those is
> as expressive as using a class.)

Okay. I can see that usage, but I don't see how much convenience you buy
here; it's not hard to write:

class Foo:
   pass

foo_object = Foo()

instead of:

foo_list = []

Of course the latter is shorter, but you pay heavily when you do 'attribute
access':

foo_object.x, foo_object.y = 10, 11 
foo_object.y = 22
foo_object.z = 14
print foo_object.x, foo_object.y

foo_list = [10, 11]
foo_list[1] = 22
foo_list.append(14)
print foo_list[0], foo_list[1]

The latter is a lot less readable. And less writable, as soon as you start
changing individual elements of the lists.

> You're suggestion is change tuple-to-class,
> in my example I changed tuple-to-list. Either way is a different means to
> the same end (yours is more correct, but more laborious). One might start
> out using tuple not realizing that he/she would later want mutability for
> that particular use. Then he/she has to change existing code. In a language
> focused on rapid development, that is not good. I guess the moral is: if
> you're not 100% sure, use list :-)

My moral would be: if you run into the limitations of tuples, switch to
classes. :) I think that starts saving you hassle almost immediately.
Python is great because classes are *not* laborious!

> And if there were only one tuple/list datatype, we'd never have to decide
> about it during programming, or go back and change it when we don't
> anticipate correctly, or explain the difference to Python newbies, or have
> FAQ items about it, or have discussions such as this :-)

Instead we'd have people straining lists where they should've used 
classes, more weird reference semantics bugs (I passed [x, y] to this
function and then changed it and now nothing works, whaa), and Tim
Peters switching to Haskell because it has tuples. :)

Regards,

Martijn
-- 
History of the 20th Century: WW1, WW2, WW3?
No, WWW -- Could we be going in the right direction?



More information about the Python-list mailing list