Changing global variables in tkinter/pmw callback

Marcin 'Qrczak' Kowalczyk qrczak at knm.org.pl
Wed Apr 11 14:13:34 EDT 2001


Wed, 11 Apr 2001 14:10:35 +0200, Alex Martelli <aleaxit at yahoo.com> pisze:

> If you meant something different from what you just wrote
> (such as "if numbers were MUTABLE", rather than "immutable"
> as you said)

Oops, I meant mutable.

> All basically true, except I'm not too sure about deep copy
> equivalence to shallow, given the generality of your assertion
> about 'immutable objects'.

Ok, I meant the case where all subobjects are immutable.

In other words, since mutability at one level imples two kinds of
copying instead of one (by reference and by value), mutability at
all levels implies unbounded number of kinds of copying, to various
degrees at various places. The same applies to comparison.

There is no formally distinguished notion of deep copying. Does it
include class objects referred to by __class__ pseudoattributes?
Does it include free variables of function closures? What about weak
references? What if an object refers to sys.stdin?

So it may be be easier to avoid the "copy by value and mutate" style,
and use "make references to changed versions" style instead. This is
IMHO what functional programming is really about: it's not primarily
about functions, but about immutability.

Of course no style fits all uses, and even functional languages
provide physical mutability (values mutating in real time) and logical
mutability (imperative style).

> We might amend your asserted equivalence to cases where ONLY
> immutable objects are involved -- *NO* mutability allowed anywhere
> in the web of objects which may be referencing each other (hmmm,
> not sure you can _make_ a reference cycle with immutable objects
> *only* -- guess not, if you're not allowed to refer to an object
> until it's "fully-built").

That's why laziness is so coupled with functionalness. It's not only
that functional programming enables omnipresent laziness, but it
needs laziness to give back what immutability has taken away.

In particular it allows to cycle everything. This is IMHO what laziness
is really about: it's not primarily about deferring computation,
but about the ability to refer to all objects being constructed from
one another.

It's funny that in OCaml you can write a function which cycles a list
of a concrete length, but you can't normally do it for all lengths. It
can be done by calling a function written in C, or by playing tricks
with casting (Obj.magic which is like a pointer cast in C). This is
what immutability without laziness has lost.

OTOH Haskell and Clean allow as silly thing as making an object cycled
with itself, of arbitrary type.

> (the other, classic case being the typestrict-OO poser "if banana
> IS-A fruit, how comes bag-of-banana IS-NOT-A bag-of-fruit" --
> bag mutability [ability to insert an apple into it, for example]
> being the root cause).

This is exhibited in the recent OCaml release: list of bananas is a
subtype of list of fruits (because lists are immutable), but array
of bananas is not a subtype of array of fruits (because arrays are
mutable).

> I thought I was following you up until the middle of this
> paragraph.  What's the "boxing mechanism for individual
> objects" in Haskell?  I do understand (I think) how a mutable
> field in a one-field structure trivially lets you "box an
> individual object", a la
>     type 'a ref = ref of mutable 'a

And Haskell implementations (it's not standard but widely supported)
provide this as an abstract type. This is the primitive, and mutable
fields can be expressed by putting several such references together.

An advantage is that it's conceptually simpler and allows to refer
to the reference itself, no matter in which record it is placed.
A disadvantage is less efficient representation and somewhat less
convenient usage: the indirection is explicit.

There is also a difference in what equality means. In SML and Haskell
comparison of mutable references gives Python's "is" (in fact in
Haskell the type system makes it the only reasonable choice). In
OCaml comparison of records compares them field by field no matter
if they are mutable or not, which for references implies Python's
"==" defined as recursive "==" field by field.

Well, Haskell uses the other style for mutable arrays. They have
immutable shape but mutable contents. So they are equivalent to an
immutable array of mutable references, not to a mutable reference to
an immutable array.

> but doesn't Caml introduce further primitives for references
> (how would I define := otherwise...)?

type 'a ref = { mutable contents: 'a }
    (* The field is called contents. *)

let (:=) ref val = ref.contents <- val
    (* <- is a primitive which mutates a record field,
       but := is defined in the library. *)

The <- primitive emphasizes that there is always a container which
drives the assignment. There are syntactic forms for updating of a
record field, an array element and a string character, but mere
    a <- b
where "a" is an identifier is meaningless. In Python the dicionary of
locals is implicit, and that's why some people are confused with the
semantics of "=". It applies to the dictionary of locals or globals,
not to the object previously referred to by the given name as it
could seem. Perhaps it would help to say that x = 5 is equivalent to
    vars()['x'] = 5
(with an appropriate dictionary instead of vars(); I'm afraid I don't
remember complete rules and when vars() is not locals()), assuming
that they know that this is just a method call on the dictionary.

-- 
 __("<  Marcin Kowalczyk * qrczak at knm.org.pl http://qrczak.ids.net.pl/
 \__/
  ^^                      SYGNATURA ZASTĘPCZA
QRCZAK



More information about the Python-list mailing list