Courious problem with literal array returned by method

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Courious problem with literal array returned by method

Günther Schmidt
Hi,

I've come accross a courious problem:

TestClass >> arr

        ^#(1 2 3 4)

returns a literal array.


let's say

to1 := TestClass new.

arr1 := to1 arr.

arr1 at:1 put: 30.

to1 arr inspect. "The 30 was injected".

TestClass new arr inspect "also has 30 in position 1".


Is this behaviour correct?


Günther


Reply | Threaded
Open this post in threaded view
|

Re: Courious problem with literal array returned by method

Chris Uppal-3
Günther,

> I've come accross a courious problem:
[...]
> Is this behaviour correct?

Yes; although it may be surprising.

An "array literal" is not an expression that evaluates to a new array each time
it is executed; it is an expression that evaluates to the /same/ array (i.e.
the same specific object) each time it is evaluated.

The way it works is that the compiler creates the array object at compile time,
and embeds a reference to it into the CompiledMethod.  You can see the array
object if you inspect the method itself.

The same embedding-an-object-reference-in-a-method mechanism is used for string
literals, and for the "compile-time" expressions like
    ##('A String' size).

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Courious problem with literal array returned by method

Günther Schmidt
Chris Uppal schrieb:

> Günther,
>
>
>>I've come accross a courious problem:
>
> [...]
>
>>Is this behaviour correct?
>
>
> Yes; although it may be surprising.
>
> An "array literal" is not an expression that evaluates to a new array each time
> it is executed; it is an expression that evaluates to the /same/ array (i.e.
> the same specific object) each time it is evaluated.
>
> The way it works is that the compiler creates the array object at compile time,
> and embeds a reference to it into the CompiledMethod.  You can see the array
> object if you inspect the method itself.
>
> The same embedding-an-object-reference-in-a-method mechanism is used for string
> literals, and for the "compile-time" expressions like
>     ##('A String' size).
>
>     -- chris
>
>

Chris,

I guess I can learn to live with that, now that I'm aware of it ;-).

How would you go about avoiding the problem of the array being altered, would you pass a copy?

Günther


Reply | Threaded
Open this post in threaded view
|

Re: Courious problem with literal array returned by method

Chris Uppal-3
Günther,

> How would you go about avoiding the problem of the array being altered,
> would you pass a copy?

Well, it's not something that has ever caused me any problems, so it's
difficult to say how I'd cure it ;-)

I think that whenever you pass a Collection from one method to another (either
as a parameter or as the returned value), you have to be aware of which (if
either) of the methods is allowed modify that collection.  There's nothing
special about methods that answer literal arrays, exactly the same problems
could occur if the method answered a collection that it held in one of its
instance variables.

I'm not at all formal about this, but in general I think I use the convention
that methods are not allowed to make assumptions about the collections that are
passed between them.  So I usually make a copy of any collection that I intend
to keep hold of (since the supplier may change it later) or that I want to make
changes to (since the supplier may not want any changes to be made to "its"
collection).   There are obviously many exceptions to this.  In some cases I'm
just lazy and modify or keep the original collection because I "know" that it's
safe.  In other cases it can be good idea to pass explicitly modifiable
collections around (e.g. passing a collection to another method that will add
items to it).  In still other cases, I get cautious and make copies of
collections that are unnecessary (according to my conventions), just to be on
the safe side.

So, I suppose, I wouldn't answer a copy of the literal array from the
TestClass>>arr method (since that method is "entitled" to assume that no-one
will modify it), but I would make a copy of the value answered by
    to1 arr
before making any changes to it.

Other conventions are possible, but all it comes down it is that you always
have to understand who (if anyone) is allowed modify the collections.
Conventions help with this, but there will always be lots of exceptions.  (The
same is true for modifying any object's state, of course, but collections are
special because the operations that change them are so generic.)

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Courious problem with literal array returned by method

Eliot Miranda
In reply to this post by Günther Schmidt
Günther Schmidt wrote:

> Hi,
>
> I've come accross a courious problem:
>
> TestClass >> arr
>
>     ^#(1 2 3 4)
>
> returns a literal array.
>
>
> let's say
>
> to1 := TestClass new.
>
> arr1 := to1 arr.
>
> arr1 at:1 put: 30.
>
> to1 arr inspect. "The 30 was injected".
>
> TestClass new arr inspect "also has 30 in position 1".
>
>
> Is this behaviour correct?

No; its deeply confusing and error-prone, and when you look at the
source of the method it doesn't show that the array has changed.  But
its the case that many Smalltalk dialects have provided this behaviour
since Smalltalk-80 had it in the first place.

But VAST introduced immutability in the VM a few years ago and VW
followed suit in about '02.  I thought someone was saying that Dolphin 5
had implemented immutability; must be mistaken.

One can implement it above the VM by introducing e.g. ImmutableArray,
ImmutableString et al, and have the compiler generate these.

--
_______________,,,^..^,,,____________________________
Eliot Miranda              Smalltalk - Scene not herd


Reply | Threaded
Open this post in threaded view
|

Re: Courious problem with literal array returned by method

Chris Uppal-3
Eliot Miranda wrote:

> One can implement it above the VM by introducing e.g. ImmutableArray,
> ImmutableString et al, and have the compiler generate these.

[Off-topic, and not Dolphin specific -- or even Smalltalk specific]
One nice possibility, if one were willing to make string literals be of another
class than String, would be to make the database software refuse to accept
anything /except/ string literals as valid SQL.  Not a perfect defence against
programmers allowing SQL-injection attacks, but a good start, and one that
would have almost zero impact on programmers who were "doing it right" in the
first place.

[Getting back on topic... ish]
Regardless of whether the behaviour of array/string literals is "confusing" or
"correct" (or even both), I find the ability to embed references to real
objects in compiled methods to be immensely useful (albeit, admittedly, only in
odd circumstances).  One more example of how Smalltalk's concrete execution
model is superior to the "declarative heresy".

    -- chris