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 |
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 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 |
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 |
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 |
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 |
Free forum by Nabble | Edit this page |