|
From: Alexandre F. <ale...@gm...> - 2008-01-18 23:19:03
|
On 1/18/08, Neil Madden <ne...@cs...> wrote:
>
> Nit picking, but values, strictly speaking, are always immutable.
Yes, until we try to push the envelope :-)
> It's variables that are passed by reference in most languages, or
> some kind of first-class reference cell or "object". This is an
> important point, because presumably it doesn't make sense to make the
> Tcl_Obj representation of "2" mutable. I mean, if "2" gets changed to
> "3", what has happened? What *is* the explanation of:
>
> set a [mutable 2]
> convert $a 3 ;# assuming "convert" is rough analogue of set
Neil, why wave that red flag ? While, again, I am no thrilled by the
necessity of introducing mutable scalars, the above mutation doesn't
threaten constants any more than the equivalent C:
a=(int *)malloc(sizeof(int));*a=2;
*a=3;
> But in the new world, what
> exactly is this thing that contains 2 and then contains 3? We clearly
> (hopefully) haven't changed the number 2 itself, and the variable "a"
> hasn't been touched, so what is this extra thing and what are its
> properties?
This extra thing is an free-floating integer value. In Eiffel speak,
we call this an instance of a reference class, as opposed to
"expanded" classes whose instances can only be copied. What is
frustrating is that Tcl_Obj is implemented just like a reference class
(pointers to heap-allocated objects), but keep the semantics of an
expanded class.
> Which we of course have now in many forms, e.g.:
>
> set m [frame .f]
> set n $m
> $m configure -text "Foo"
So what ? My point is that mutability is useful for containers, namely
lists and dicts, which are first-class, GCed values. Should we abandon
the concept because of the pre-existence of opaque, non-GCed handles
like widget names ?
> Yes, it does. Given that Tcl already quite nicely separates values
> from mutable variables, why introduce another layer?
Two reasons:
(1) Variables don't reach into substructures: there's no variable
"name" equivalent to "the adress of" [lindex [dict get [lindex [dict
get $d foo] 3] bar] 4].
(2) That layer is a very local perturbation of COW semantics on
specific object types and primitives. It won't bite you by surprise
(no mutable is created unless you call [mutable]), and won't affect
the performance of the rest.
> lappend, lset, etc operate on variables, not values. So converting
> them to also operate on "mutable" values would seem to be quite a
> large and surprising change in their behaviour.
A "change" ? No, an extension of their domain. Today, mutable values
are outside the picture, so there's no compatibility issue. As for the
aesthetic surprise, well yes, the best way of surprising nobody, is
not to change anything.
But what if I yielded on the "reuse primitives" front, and instead
came up with a bunch of new ones like [mlappend] [mlreplace] [mdict
set] ? Wouldn't I get even worse criticism on the basis of ugly
proliferation ?
> > Now, we need primitives to change the mutability state. This is
> > done with
> >
> > set l [list 1 2 3] ;# $l is immutable
> > set m [mutable $l] ;# $l is untouched, still immutable
>
> So m is now a mutable variable containing a mutable value?
> This seems like a lot of duplication.
Well, variables are boxing gloves, mutable values are delicate claws.
But you need the gloves to hold the claws.
> Will mutable values support traces like variables?
No, no need for that.
> > foreach d $mutable_list_of_mutable_dicts {
> > transitive_closure d
> > }
>
> For dicts, doesn't [dict with] and [dict update] solve many of these
> same problems? Designing a similar facility for lists could be a
> useful addition.
No. Think of nesting the above on three levels. COW then forces much
plumbing/unplumbing to avoid any duplication. Hence my proposal to
give a delicate too to disable COW locally when you know what you're
doing.
> IMO, the correct way to approach any perceived deficit in this area
> would be to examine why variables are not suitable for the job, and
> what precisely would need to change to make them suitable.
OK. A possibility would be an extension of Tcl_SetVar2 allowing a kind
of $v(PATH) notation, where the PATH is a sequence of list indexes and
dict keys:
set x [list 1 2 [dict create a 3 b 4 c [list 5 6 7]]]
# the ((())) notation is of course problematic, to be determined later
incr x((( { l 2 d c l 2 } )))
But, granted, I have no ready-to-use syntax to replace the ((( and ))) above...
-Alex
|