[Python-Dev] mutability (was: lists v. tuples)

Zooko zooko@zooko.com
Fri, 14 Mar 2003 14:09:02 -0500

 GvR wrote:
> This has its downside too though.  A function designed to take an
> immutable class instance cannot rely on the class instance to remain
> unchanged, because the caller could pass it an instance of the
> corresponding mutable subclass!  (For example, the function might use
> the argument as a dict key.)  In some sense this inheritance pattern
> breaks the "Liskov substibutability" principle: if B is a base class
> of C, whenever a B instance is expected, a C instance may be used.


Presumably the designers of the NextStep libraries thought to themselves that 
they couldn't do it the other way (have NSArray subclass NSMutableArray) because 
NSArray couldn't provide a real implementation of a mutation method like 
"NSArray addObject".

If you include the immutability guarantee as well as the methods in the 
"contract" offered by an interface, then its clear that neither can be a 
Liskov-substitution-principle-preserving subtype of the other.

The E Language paid careful attention to this issue because a surprise about 
mutability could easily be a security hole.  Their solution is quite Pythonic, 
inasmuch as type-checking is dynamic, structural (an object matches a type if it 
offers the interface regardless of whether it is explicitly declared to be a 
subtype), and soft (an object can implement only part of a type).

These are the three noble features of Python's type system.  (I occasionally 
hear about efforts to cripple Python's type system in order to make it as 
ungainly as Java's, but fortunately they always seem to fade away...)

So in E, it's the same: if you are expecting a mutable list (a "FlexList") and 
you get an immutable one, you'll get an exception at run-time if you try a 
mutation operation like mylist.append("spam").

Like Python, E's strings do the right thing if you invoke immutable list 
("ConstList") methods on them.

The syntax for constructing maps and lists and indexing them is similar to 
Python's.  That syntax always constructs immutable structures, a mutable version 
of which is generated with the method "mylist.diverge()".  To get an immutable 
version of a mutable structure, you write "mylist.snapshot()".




         ^-- newly and incompletely restored