[Python-Dev] mutability (was: lists v. tuples)
Fri, 14 Mar 2003 14:09:02 -0500
> 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
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