I would like to join those who oppose this valiant proposal. The main problem for me is that it complicates the beautifully simple and uniform syntax of Smalltalk: As an example, a: b does not have a receiver. I consider the simple syntax one of the great things about Smalltalk both for learning and for code readability.
If anything were to be done with variables, I would suggest making them first-class objects. As they are, they are different from everything else and break the uniformity of the language. Assignments could then be handled for example as
var assign: x
thus removing the need for the assignment statement while maintaining the syntax. A lot of other things could also be done more easily such as (pseudocode)
(Array with: selectedVariables) do: [:var| var assign: Strinbg new]
instead of
a := ''. b := ''. c := ''. etc.
Ivan
Thanks for taking the time in looking over my (admittedly pretty rough) idea.
From: "Jarvis, Robert P." Jarvisb@timken.com
I don't like the idea of implicit targets. One of the great
beauties of
Smalltalk is its simple and very regular grammar. In my opinion adding implicit targets would make the grammar more complex and less regular without a corresponding gain in clarity or expressiveness.
Yes, I also don't want to mess the syntax up. However, for 'reading' accesses, there is no (visible) change in syntax, it's just that what used to be variable references are now interpreted as message sends. That seems like a simplification to me.
The only 'addition' is that for assigning values, instead of writing:
a := b.
you would write
a: b.
Considering that the colon syntax is also already in use, and that := gets removed, that also seems to be a simplification of the visible syntax, overall (a slight complication and a medium simplification). As a matter of fact, the compiler could treat a:= as equivalent to a: I have to admit that I haven't considered what this will do to the compiler, though.
I just don't see a great advantage here. It seems more like a hint to the compiler
than an
aid to the human.
Well, the aid is that there is now only message sends, assignments have been eliminated from the language or at least hidden from view. The practical benefit I have in mind is that the decision wether access to an instance variables is direct or via accessors is made in one place instead of everywhere the variable is accessed. Currently, if I have direct instance variable access, I write.
myInstanceVar doSomething.
If I have accessors, I write
self myInstanceVar doSomething.
*everywhere* I use myInstanceVar. The same goes for write-access:
myInstanceVar := newValue
versus
self myInstanceVar:newValue.
The problem is that changes to the access policy are very expensive because every method *accessing* the instance-var/accessor has to be changed. Therefore, your (absolutely correct, IMHO) proposition that all instance var access be done with accessors first and directly only when absolutely necessary means that a lot of code has to potentially be modified in the latter case. With lots of coders being prone to premature optimiziation, they will opt for direct access instead, especially since it is also less typing.
With my proposal, code can always be written as if it is using accessors, making it non-brittle, but at the same time it enjoys all the benefits cited for direct variable access (privacy, speed, less typing, etc.) So, I just write
myInstanceVar doSomething. and myInstanceVar:newValue.
and this very same code will use accessors if available or direct access if not.
Also, if := is eliminated how is a reference assigned to a temporary variable?
Trickery. Just like with instance variables, the compiler detects that there is a local variable of that name and emits the direct access code instead. I know this sounds a little insane (turn the access into a message send and then auto-reduce it back to an access), but there is some method to the madness :-)
Regards,
Marcel
Ivan Tomek,
Jodrey School of Computer Science Acadia University Wolfville, Nova Scotia, Canada, B0P 1X0
fax: (902) 585-1067 voice: (902) 585-1467
Hey, it's monday, I haven't woken up properly yet!
It must take you a couple of days because its Tuesday where I am (and all of the world by now) <gg>
8-)
This is getting a bit involved, but I have another idea. First, two principles:
1) We should keep the receiver in message patterns. (I'm against abbreviated message-sends.)
2) We want to get rid of assignment. (It's always a hack, except if you make it a function as in LISP, or do away with it, as in functional languages.)
Solution: If we had the notion of "implicit accessors," we could write,
| var | self var: 42. Transcript show: self var printString; cr.
The code that implements doesNotUnderstand (or, even better, handles the exception MessageNotUnderstood) could then look in the local scope to see if there's a variable named "var" and handle the assignment and reference as "implicit accessing" -- this way it appears that we have accessors even for local temp. vars.
(This is very similar to several other schemes that use doesNotUnderstand for "generic behavior" or property list objects.)
If we did it this way, we could do away with all accessors (except for the speed hit we'd take passing though doesNotUnderstand on IV accesses).
stp
Stephen Pope wrote:
This is getting a bit involved, but I have another idea. First, two principles:
- We should keep the receiver in message patterns. (I'm against
abbreviated message-sends.)
- We want to get rid of assignment. (It's always a hack, except if you
make it a function as in LISP, or do away with it, as in functional languages.)
Solution: If we had the notion of "implicit accessors," we could write,
| var | self var: 42. Transcript show: self var printString; cr.
The code that implements doesNotUnderstand (or, even better, handles the exception MessageNotUnderstood) could then look in the local scope to see if there's a variable named "var" and handle the assignment and reference as "implicit accessing" -- this way it appears that we have accessors even for local temp. vars.
(This is very similar to several other schemes that use doesNotUnderstand for "generic behavior" or property list objects.)
If we did it this way, we could do away with all accessors (except for the speed hit we'd take passing though doesNotUnderstand on IV accesses).
But if we did it this way, that would also allow one to still write explicit accessors/setters which would be good both for cases where efficiency was important and cases where you want to invoke side affects. I like this proposal. You could extend it on the MetaClass side to make the implicit setters pass thru to the new instances. And you could do arbitrary ordered argument lists as well (I did this about 1 year or so ago in Squeak).
-- Travis Griggs (a.k.a. Lord of the Fries) Member, Fraven Skreiggs Software Collective Key Technology P-P-P-Penguin Power!
- We should keep the receiver in message patterns.
- We want to get rid of assignment.
We? :-)
Solution: If we had the notion of "implicit accessors," we could write,
| var | self var: 42. Transcript show: self var printString; cr.
But then do the full step and get rid of "| var |" That piece of syntax isn't needed at all. Make local variable creation (wait, you don't have variables so how to call them?) implicit. Python, btw, does the same and for a Smalltalker who's already used to argumenting for the advantages of dynamic typing against static typing it shouldn't be too difficult to also find some arguments for these dynamic storage location ;-)
"self var: 42" simply creates a new local storage and assigns 42 if there's no storage. Actually, it maintains a simply dictionary of key/value pairs. We can even make this explicit
self localsAt: #var put: 42 Transcript show: (self localsAt: #var) printString; cr
Object>>localsAt: key put: value (WeakMethodContextDict at: thisContext sender receiver ifAbsentPut: [Dictionary new]) at: key put: value Object>>localsAt: key ^(WeakMethodContextDict at: thisContext sender receiver) at: key
Of course, instead of self-sends, using symbols would also work :-)
But what's the benefit of this approach? I don't see it.
bye -- Stefan Matthias Aust // Bevor wir fallen, fallen wir lieber auf.
Yeccch, This is asking for un-debuggable code in which a simple typo takes hours to discover. I've used both Python and SuperCollider_1, which allow "auto-declaration" and I have to say that I'm just not a careful enough typist for them (as you all surely already know from my email to this list in the past). Please keep declarations around.
stp
Stefan Matthias Aust wrote:
- We should keep the receiver in message patterns.
- We want to get rid of assignment.
We? :-)
Solution: If we had the notion of "implicit accessors," we could write,
| var | self var: 42. Transcript show: self var printString; cr.
But then do the full step and get rid of "| var |" That piece of syntax isn't needed at all. Make local variable creation (wait, you don't have variables so how to call them?) implicit.
As an example, a: b does not have a receiver.
Well, I don't consider this as a problem. In Java and C++, in a send to "this" (aka self) "this" can be omited and nobody has trouble here. Okay, both languages have a larger set of syntactic rules which contain enough redundacy to help people to understand the statement (and it also looks like a familiar function now :-) but even for Smalltalk I don't consider this as a problem.
The problem IMHO is that now "self a: b" and "a: b" doesn't mean the same. While the first expression always accesses an instvar of the self object, the second expression will assign a temporary called "a" if one exists.
SELF has exactly the same problem. The authors simly say that explicit self sends are considered as bad style and should be omitted - if possible. So you basically exchanged the ":=" to
I consider the simple syntax one of the great things about Smalltalk both for learning and for code readability.
If might sound funny for Smalltalkers, but it is my experience from teaching Smalltalk and Java that people don't consider Smalltalk as an easy to learn language but because it looks more alien, difficult to understand. Java or especially Python are easier to learn for most people.
Another problem with Smalltalk is also, that its implementation must be understood before you can understand Smalltalk code because even the simplest conditional statements explicitly show the way they're implemented.
If anything were to be done with variables, I would suggest making them first-class objects. As they are, they are different from everything else and break the uniformity of the language. Assignments could then be handled for example as
var assign: x
Then use
#var <= x
which could be implemented (I think) without great difficulties, for example...
Symbol >> <= anObject | r | r := thisContext sender receiver. r instVarAt: (r class allInstVarNames indexOf: self asString) put: anObject
How if you use something like
thisContext locals: 'temp1 temp2'
instead of
| temp1 temp2 |
at the beginning of methods, you could even setup and access local variables with a minimal change to the above code :-)
bye -- Stefan Matthias Aust // Bevor wir fallen, fallen wir lieber auf.
From: Stefan Matthias Aust sma@netsurf.de
The problem IMHO is that now "self a: b" and "a: b" doesn't mean
the same.
While the first expression always accesses an instvar of the self
object,
the second expression will assign a temporary called "a" if one exists.
Well, the problem is the same as for a:=b. 'a' can be either an instance variable or a local variable. I am not saying this is good or bad, it's just the same is it is now.
Marcel
Marcel,
From: Stefan Matthias Aust sma@netsurf.de
The problem IMHO is that now "self a: b" and "a: b" doesn't mean the same.
Well, the problem is the same as for a:=b. 'a' can be either an instance variable or a local variable. I am not saying this is good or bad, it's just the same is it is now.
I should have written earlier that my emails weren't meant as critique. Please don't feel offended. I'm still unsure what solution I'd prefer, so I fired in all directions :-) You're right, with both ways, you've to carefully watch the temporary declaration to understand the meaning. I think - no I know - I dislike this.
--next-email--
I don't care [about implementation]
Funny, that was *exactly* the idea of my proposal.
I'm afraid I wasn't specific enough. I want to distinguish slot access and message sends. So my argument was not to show the fact that slot access is just another special case of method calls. From my experience, this distinction will help people to learn the language.
I know this isn't Smalltalk anymore but I don't care at this moment: The dot-operator is well known to access slots, so why not write "self.x" to access slot x of the current receiver or "anyObject.y" to access anyObject's slot. The :=-operator is well known for assignments, so use it to assign values to slots or local variables. The []-operator is known for indexed access, so use it instead of at: and at:put:. Actually all operators can be understood as macros.
Well, I guess that is the part that got sort of lost in the noise: If there are no accessors, the compiler compiles 'accessor/mutator' message sends to self as direct variable access. Therefore, the object itself can access its own instance variables (and local variables) even if the accessors are not defined, whereas in SELF there is an automatic definition of accessors.
Thinking about both alternatives, I think I'd prefer the explicit definition of accessors. Better tools - as already suggested - is probably the best way. Instead of adding space-separated identifiers to the ....instVarNames:... method call, the browser should generate slot and accessors.
Crucial difference.
....especially if you want to implement something like lazy initialization without workarounds like
slot self basic_slot ifNil: [self basic_slot: self compute_slot]. ^self basic_slot slot: object self basic_slot: object
where you have to call your slot "basic_slot" even if everybody else should know it as slot.
bye -- Stefan Matthias Aust // Bevor wir fallen, fallen wir lieber auf.
Stefan Matthias Aust wrote:
I know this isn't Smalltalk anymore but I don't care at this moment: The dot-operator is well known to access slots, so why not write "self.x" to access slot x of the current receiver or "anyObject.y" to access anyObject's slot. The :=-operator is well known for assignments, so use it to assign values to slots or local variables. The []-operator is known for indexed access, so use it instead of at: and at:put:. Actually all operators can be understood as macros.
:0 Noooooo.... Nooo... No.. not the dot operator... aaaaaahhhhhhh....!!!
Ahem. Please. Anything but the dot operator. Or come up with a different statement terminator. Semicolon anyone? :)
-- Travis Griggs (a.k.a. Lord of the Fries) Member, Fraven Skreiggs Software Collective Key Technology P-P-P-Penguin Power!
Travis Griggs wrote:
[...]
Ahem. Please. Anything but the dot operator. Or come up with a different statement terminator. Semicolon anyone? :)
....just a reminder that "." in Smalltalk is a statement *separator*
stp
Travis Griggs wrote:
:0 Noooooo.... Nooo... No.. not the dot operator... aaaaaahhhhhhh....!!!
Smalltalkers can be sooo emotional. Funny.
Open your mind.
Ahem. Please. Anything but the dot operator. Or come up with a different statement terminator. Semicolon anyone? :)
Actually, my prefered statement separator is simply newline :-)
Another "No" anyone?
bye -- Stefan Matthias Aust // Bevor wir fallen, fallen wir lieber auf.
Stefan Matthias Aust wrote:
Actually, my prefered statement separator is simply newline :-)
Another "No" anyone?
Sure. "Noooooo!!!!" How's that?
Newline as separator severely cramps code layout style, and breaks things like OrderedCollection>>at: (which, I would imagine, would turn out to be a bad thing).
(anInteger < 1 or: [anInteger + firstIndex - 1 > lastIndex]) ifTrue: [self errorNoSuchElement] ifFalse: [^ array at: anInteger + firstIndex - 1]
I'd hate to not be able to write something like that.
-Jesse Welton
Jesse Welton wrote:
Sure. "Noooooo!!!!" How's that?
Well, that's what I expected :-) But actually I'm sure, you format your code in a way to make it clear to the reader what belongs together and want don't. If the reader is able to understand this, the compiler should be able to do this, too.
(anInteger < 1 or: [anInteger + firstIndex - 1 > lastIndex]) ifTrue: [self errorNoSuchElement] ifFalse: [^ array at: anInteger + firstIndex - 1]
In this example, you indent the second and third line to signal that the statement that starts in the first line is continued in these two lines.
The Python parser is built this way. IMHO very easy to understand. While Smalltalk hasn't as much syntax as Python, I might be still useful.
bye -- Stefan Matthias Aust // Bevor wir fallen, fallen wir lieber auf.
Attached please find the most current version of the Applescript Plugin. In the attached .sit file, please find:
Applescript1.27Sep905pm.cs Applescript2.27Sep907pm.cs TestOSAPlugin
To install:
(*) Unstuff the SIT file, place all the files in your Squeak directory (1) Startup a fullly updated 2.6test Squeak (2) fileIn Applescript1 (3) fileIn Applescript2 (5) Execute the following doIt:
Applescript initialize
You should be good to go.
Principal differences between this upgrade and the one released with Squeak2.6test updates is a substantially more complete implementation of the Applescript API and supporting routines, and full support for Applescript contexts and script inheritance.
EXECUTION/COMPILATION OF SCRIPTS:
To run a script:
Applescript doIt: 'beep 3'
To compile and save a script (with its context) in a variable:
var _ Applescript on: 'beep 3'
To execute the compiled script in the null context:
var doIt
SCRIPT CONTEXTS:
The following sequence:
var _ Applescript on: ' property beepCount:0 set beepCount to beepCount + 1 beep beepCount'
Will beep an additional time with each repetition of:
var doIt
You can maintain independent contexts by compiling the mainline script mode:0, and passing the context as a parameter:
var _ Applescript on: ' global beepCount set beepCount to beepCount + 1 beep beepCount' mode: 0
context _ Applescript on: 'property beepCount'
And you can share the context across scripts, for example, with:
reset _ Applescript on: ' global beepCount set beepcount to 0'
mode: 0
so that executing the following doIt:
reset doItIn: context
resets the beepCount counter.
Other relevant commands:
Applescript do: aString in: aContext mode: anInteger Applescript on: aString mode: anInteger
scriptInstance doItMode: anInteger scriptInstance doItWith: aContext mode: anInteger
Attachment converted: Anon:Applescript1.27Sep905pm.cs (TEXT/MSIE) (00013B9B) Attachment converted: Anon:Applescript2.27Sep907pm.cs (TEXT/R*ch) (00013B9C) Attachment converted: Anon:TestOSAPlugin (shlb/????) (00013B9D)
squeak-dev@lists.squeakfoundation.org