Many things which are difficult or even impossible to solve in other programming
languages are simple or trivial in a highly reflective system such as Smalltalk.
Many of the patterns as collected and described by the gang of four are not needed
or are much simpler in Lisp or in Smalltalk.
This document will show some of this kind -
it is not about things you can do in smalltalk which you can also do in any other
language, but about things which are very easily done in smalltalk but drive you mad in
other languages.
Even if you are already a smalltalker, it may also be interesting to read and to get new ideas.
In Common Lisp I have often wanted to iterate through the fields of a struct-- to comb out references to a deleted object, for example, or find fields that are uninitialized. I know the structs are just vectors underneath. And yet I can't write a general purpose function that I can call on any struct. I can only access the fields by name, because that's what a struct is supposed to mean.
In smalltalk, you can access an object's slot via the "instvarAt:"
message. The names of the slots are known to the class and can be
aquired with "allInstanceVariableNames".
Thus, a debugging method to dump *ANY* object's contents could be:
of course, you can also write a block (aka-function) for this:
dump: someObject
someObject class allInstanceVariableNames
doWithIndex:[:name :idx |
Transcript
show:name;
show:' is ';
showCR:(someObject instVarAt:idx).
]
and iterate over a collection of objects to be dumped with:
dumper :=
[:someObject |
someObject class allInstanceVariableNames
doWithIndex:[:name :idx |
Transcript
show:name;
show:' is ';
showCR:(someObject instVarAt:idx).
]
].
to dump the Transcript, try:
objectsDoBeDumped do:dumper
dumper value:Transcript
|s b|
s := '[:a :b | (a squared + b squared) sqrt ]'.
b := (Block fromString:s).
Transcript showCR:(b value:3 value:4)
Its a bit of a pity, that the internal represenation differs much more
from the textual one as it does in Lisp-like languages. But fair anough for our needs...
You can (and should) analyze the code for the messages being sent, to make sure that no
bad messages (i.e. only allowed ones) are introduced if the codestring originates from a user:
for example, to verify that the user does not inject bad code into a scripting engine:
|s b allMessages|
s := '[:a :b | (a squared + b squared) sqrt ]'.
b := (Block fromString:s).
allMessages := b homeMethod literals.
Transcript show:'block contains messages: '; showCR:allMessages.
Use this as a basis to write your own spread-sheet; if required, write your own parser which
adds proper operator precedence, or use the built-in JavaScript parser...
|s b codeString allowedMessages|
allowedMessages := #( + - * / sqrt squared sin cos value ).
codeString := Dialog request:'Give an expression on a and b.
Use parenthesis as in (a*5) + (b sin):'.
codeString notEmptyOrNil ifTrue:[
s := '[:a :b | ',codeString,']'.
b := (Block fromString:s).
((b homeMethod literals)
contains:[:msg |
(allowedMessages includes:msg) not
])
ifTrue:[
Transcript showCR:'Sorry - the block contains a bad message'.
] ifFalse:[
Transcript show:'The value of "',codeString,'" for a=4,b=5 is '; showCR:(b value:4 value:5).
].
].
Number
compile:'cubed ^ self * self * self'
and can be used immediately as in:
5 cubed
or with a floating point number, as in
5.0 cubed
or, it can be forgotten:
Number removeSelector:#cubed
(retry the above example after the removal, to see that integers really no longer know
how to compute volumes...)
|cls|
cls := Object
subclass:'anonymous'
instanceVariableNames:'firstName lastName'
classVariableNames:nil
poolDictionaries:nil
category:nil
inEnvironment:nil.
cls compile:'firstName ^firstName'.
cls compile:'firstName:s firstName := s'.
cls compile:'lastName ^lastName'.
cls compile:'lastName:s lastName := s'.
((cls new firstName:'hello') lastName:'world') inspect.
... more to be added here ...
|a| a := '[:a | Transcript show:''|a| a := '';showCR:a storeString,''.'';showCR:''(Block readFrom:a) value:a'' ]'.
(Block readFrom:a) value:a
Copyright © 2007 eXept Software AG, all rights reserved
<info@exept.de>