Actually, it's not too hard to create a ReadOnlyString and ReadOnlyArray which have several methods overridden to produce errors. Overriding at: and basicAt: goes an awefully long way. Then, the Parser needs to be updated. I did this once, but it was in an image too divergent from the main Squeak image that it could really be useful. :|
(I at least *tried* to make Float's and Characters read-only, too, though I don't remember how far I got!)
-Lex
Hans-Martin Mosner hm.mosner@cityweb.de wrote:
Avi Schwartz wrote:
Hi,
I am new to Smalltalk and Squeak, so please bear with me...
Welcome to The Club :-)
I am trying to figure out why the result of
'abcdef' at: 1 put: $x
is $x and not 'xbcdef'.
That has been the Smalltalk behavior since the dark ages... I presume the intention is to make it semantically similar to assignment expressions, whose value is equal to the assigned value. To achieve your intention, you should evalutae 'abcdef' at: 1 put: $x; yourself which returns the receiver of the first message expression.
Now, to complicate matters even worse for me, according to the book 'Smalltalk, Objects, and Design' by Chamond Liu, the result I should expect is an exception since a string literal is immutable.
Squeak does not currently have really immutable objects (with the exception of SmallIntegers). This is also true for a number of other Smalltalks. To make your code portable to Smalltalks with immutable literals, you should write 'abcdef' copy at: 1 put: $x; yourself It would certainly be a great service to the Squeak community to implement immutable objects, but I think that this requires quite some in-depth knowledge of the VM and/or image to do, so this is certainly not a beginner's project.
Cheers and happy holidays, Hans-Martin
Actually, it's not too hard to create a ReadOnlyString and ReadOnlyArray which have several methods overridden to produce errors. Overriding at: and basicAt: goes an awefully long way. Then, the Parser needs to be updated. I did this once, but it was in an image too divergent from the main Squeak image that it could really be useful. :|
Is it necessary to change the parser?
I had been thinking instead about changing the behavior of class String so that Strings are immutable (by redefining at:put:, replaceFrom:to:with:startingAt:, byteAt:put: and what else?), and creating a separate class MutableString for those few places where string mutation is really used. I wonder how common this behavior is.
One tricky thing is that string mutation is sometimes used to create a string that will then be treated as immutable. See, for example, Symbol asString. This could (and probably should) be changed to use String withAll: aSymbol. Mutating a string is OK while it is being constructed (how else could it be constructed?, but taboo once it has been handed off to the world.)
Andrew
At 19:20 -0800 12/31/00, Andrew P. Black wrote:
Actually, it's not too hard to create a ReadOnlyString and ReadOnlyArray which have several methods overridden to produce errors. Overriding at: and basicAt: goes an awefully long way. Then, the Parser needs to be updated. I did this once, but it was in an image too divergent from the main Squeak image that it could really be useful. :|
Is it necessary to change the parser?
I had been thinking instead about changing the behavior of class String so that Strings are immutable (by redefining at:put:, replaceFrom:to:with:startingAt:, byteAt:put: and what else?), and creating a separate class MutableString for those few places where string mutation is really used. I wonder how common this behavior is.
One tricky thing is that string mutation is sometimes used to create a string that will then be treated as immutable. See, for example, Symbol asString. This could (and probably should) be changed to use String withAll: aSymbol. Mutating a string is OK while it is being constructed (how else could it be constructed?, but taboo once it has been handed off to the world.)
Andrew
Guys:
For whatever it's worth in this discussion, IBM Smalltalk implements read/only objects. Some objects, like literals, come r/o, but any object can be set r/o as desired. Object supports #isReadOnly and #markReadOnly:; the latter takes a boolean.
When an attempt is made to store into a r/o object the message #attemptedROMStore:intoSlot: is sent to the object, passing the object that was to be stored and its instance variable index; a default implementation in Object simply raises a primitive error.
For objects that have indexed instance variables, the VM checks for the error and fails primitives, such as #basicAt:put:, which in turn check the return code for a r/o store attempt and send #attemptedROMStore:intoSlot:. Fails: 'asdf' at: 1 put: $x
Objects with named instance variables, such as Points, seem to be sent #attemptedROMStore:intoSlot:. directly from the VM if they are r/o. Fails: ((2@3) markReadOnly: true; yourself) x: 3
#attemptedROMStore:intoSlot: can be overridden; if it answers true then the store is retried. Thus objects can be marked as r/o and stored into depending on runtime conditions. It is also possible to set self to r/w, do the store using the slot index, and set self back to r/o.
Note that setting an array to r/o does NOT set its contents to r/o.
The last time I played with this it was very slow; an implementation of active variables (where a store was always allowed but dependents were notified each time a store occurred) took 50 times longer to store (with no dependents) than simple r/w store. I didn't measure the time to get just the indication of an error; it may well be that the VM is fast and the overhead is in the Smalltalk code I wrote to implement active variables.
In the base image there are no users of #attemptedROMStore:intoSlot:, but since there is tons of code that can be loaded from libraries, something may use it.
Dave
squeak-dev@lists.squeakfoundation.org