Lawful != Mutable (was Can Python function return multiple data?)

Rustom Mody rustompmody at gmail.com
Sun Jun 7 11:49:52 EDT 2015


On Saturday, June 6, 2015 at 11:13:52 AM UTC+5:30, Chris Angelico wrote:
> On Sat, Jun 6, 2015 at 3:28 PM, Rustom Mody  wrote:
> > You just repeated what Chris said, replacing 'immutable' with 'same'
> > There was a list: [1,2,3]
> > At some point that list is found to be(come) [1,2,3,4]
> > They dont look same to me.
> 
> "I'm going shopping, can you get me the shopping list please?"
> *goes and fetches a piece of paper from the kitchen*
> "Wait, this isn't the right list! This one has more things on it!"
> 
> The question of whether or not the thing fetched is indeed the
> shopping list is independent of the items on it. The list has an
> identity and it has a value (the items needed). If I hand you an empty
> list on the basis that the shopping list you placed there last week
> was empty, I've destroyed the value of the posted shopping list -
> people have added things to it during the week, and they expect those
> things to be on the list that gets referenced to make purchases.


Well that is a more useful metaphor than much of what I see being said here.
[Most of what I see being summarizable into:
This is the way python is
Python is Holy Writ
THOU SHALT NOT QUESTION
]

So thanks Chris for a non-pythonic metaphor.

May we look a little into it?

Is your shopping list really a list? If I have:

1. Bread
2. Eggs
3. Rice

Presumably that's the 'same' list as

1. Eggs
2. Bread
3. Rice

IOW if we have to make a python data-structure for it, the (python) list
["eggs", "bread", "rice"]
is overspecific. Whereas the set
set(["eggs", "bread", "rice"])
works better for the simple reason that python will conform with our informal
expectation of the two differently listed shopping lists being 
equal with the set data structure and not the list data structure.  ie
["eggs", "bread", "rice"] == ["bread", "eggs", "rice"] fails
whereas
set(["eggs", "bread", "rice"]) == set(["bread", "eggs", "rice"]) works

Is it only coincidentally related to the math law: 
{1,2,3} = {2,1,3}  ?

Now say we change the example slightly, from shopping list to
shopping itenary:
1. Grocer
2. Hardware
3. Clothes

and due to geography of the stores the above order is the best one.
[Yeah I am assuming the Travelling Buysman problem is a solved problem]


So I model that as
itinerary = ["grocer", "hardware", "clothes"]

O! I forgot... Need to cut my hair

itinerary[:2] + ["barber"] + itinerary[-1:]
['grocer', 'hardware', 'barber', 'clothes']
>>> 

Nice... Just one doubt
Do I need to parenthesize that expression??

I try
>>> itinerary[:2] + (["barber"] + itinerary[-1:])
['grocer', 'hardware', 'barber', 'clothes']
>>> (itinerary[:2] + ["barber"]) + itinerary[-1:]
['grocer', 'hardware', 'barber', 'clothes']
>>> 

Seems to be the same.
Nice...

But is it always so?
Or did it just happen by coincidence?

IOW: Does list-+ satisfy an associative LAW of the form:

(∀ a,b,c:list • (a + b) + c = a + (b + c) ) ??


Now try it with mutation.

Some (wiseguy) told me that mutating data structures can be more efficient
than 'functional' ones.

Sounds good... Just not sure how/when associativity works/breaks.

Say we want to stuff a 4 between the 2 and the 3 in [1,2,3]
[Its a bit tiresome to keep typing 'grocer' etc]

>>> it = [1,2,3]
>>> it[:2]
[1, 2]
>>> it[:2].append(4)
>>> it
[1, 2, 3]

Ho Hum.
Try again

>>> it = [1,2,3]
>>> it = it[:2].append(4)
>>> it = it.append(it[-1])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'append'


Got to 'un-None' the #$@%%^ thing

>>> def app(a,b):
...   a.extend(b)
...   return a
... 

>>> a,b,c=[1,2],[3,4],[5,6]
>>> app(app(a,b),c)
[1, 2, 3, 4, 5, 6]
>>> a,b,c=[1,2],[3,4],[5,6]
>>> app(a,app(b,c))
[1, 2, 3, 4, 5, 6]

Looks right so far.
A few more checks...

>>> a,b=[1,2],[3,4]
>>> app(app(a,a),b)  # (a + a) + b
[1, 2, 1, 2, 3, 4]
>>> a,b=[1,2],[3,4]  # ok
>>> app(a,app(a,b))  # a + (a + b)
[1, 2, 3, 4, 1, 2, 3, 4]  # Whooops!


No I am not claiming that my pretence at noob struggles is very convincing.
Hopefully works enough to show that mutatory programming may be a lot of 'fun'
However imperative ≡ mutating  ≢ not-lawful

In Summary:

Correct programs are in accordance with math/logic laws
Incorrect programs are written by people ignorant of laws
Immutability is the bedrock of lawfulness -- If Newton had assumed
that between the time Kepler made his calculations and Newton recast them
into general form, the gravitional constant 'G' was changing, we would not
have physics or science as we know it
Properties like (python's version of) immutability just make stating of lawful
behavior unduly hard by asserting gibberish such as
[1,2,3] is [1,2,3,4].

[Just to be clear, I find python's notion of immutability sloppy but hard
to avoid whereas python's use of the 'is' operator for pointer-equality
a much bigger linguistic blunder. The two errors are closely related]

Piquant footnote: The big proponent of 'lawful¹' programming is
Lambert Meertens, who happens to be the grandfather² of python.

¹ http://www.kestrel.edu/home/people/meertens/publications/papers/Algorithmics.pdf
² http://en.wikipedia.org/wiki/ABC_%28programming_language%29



More information about the Python-list mailing list