On Sun, 18 May 2003 00:27:41 +0100, Dominic Fox dominic.fox1@ntlworld.com wrote:
- If I want to expose an instance's private fields, do I have to code
accessor methods every time? Is there an alternative to writing
getFoo ^ foo
and
setFoo: newFoo foo := newFoo
over and over again?
You can write code that generates the accessor and generator methods. You can add such code to the Browser, and provide menu options that run the code for any selected set of instance variables.
An example of the necessary code:
| names | names := MyClass instVarNames. 1 to: names size do: [:index | | name capitalizedName | name := localNames at: index. capitalizedName := name withFirstCharCapitalized. MyClass compile: 'set', capitalizedName, ': a', capitalizedName, ' ', name, ' := a', capitalizedName classified: #accessing]
Also, you can use the #instVarAt: and #instVarAt:put: primitives:
'Hello' asText instVarAt: 1 "Evaluates to the String contained in the 'string' instance variable of a Text."
- Is the best way to make what in C++ or Java you'd call "constructors"
to write class methods that create, initialize and then return an instance, e.g.
newFooWithBar: initialBar | newFoo | newFoo := Foo new; setBar: initialBar. ^ newFoo
or is there a more concise way?
Class methods are the way to go, unless one also wants to use the Strategy pattern to dynamically vary how instances get initialized--in which case explicit "factory" objects might be called for.
A note on the syntax in your example: 'Foo new; setBar: initialBar' does not do what you think it does. It results in sending the message #setBar: to the class Foo, not to the instance you've created in the previous message send. To code what you intended, use one of the following:
1: self basicNew setBar: initialBar "use when #setBar: is fully responsible for initializing the instance" 2: self new setBar: initialBar "use when #setBar: is NOT fully responsible for initializing the instance"
Usually, the #new class method answers an initialized instance. It should be coded in an abstract superclass (so that all the subclasses inherit it) as follows:
new ^self basicNew initialize
By convention, the method #basicNew always answers a new but uninitialized object. Using #basicNew therefore guarantees that a) there won't be any unexpected recursion in the class methods that participate in constructing initialized instances, and b) there won't be any unecessary duplication of work, or creation of throw-away objects, during the initialization process.
- Can I treat blocks as first-class entities, e.g. return them from
methods, pass them around etc? Can I use them to implement LISP-like closures? Even if I can, is this a "natural" smalltalky way to do things?
Yes, in most Smalltalk implementations. Unfortunately, Squeak does not yet fully support blocks as closures. Blocks as full closures were first implemented in Smalltalk in the 80's by a company known as ParcPlace. A version of Smalltalk descended from ParcPlace's implementation is still available as the VisualWorks product form Cincom. Both Squeak and VisualWorks are direct descendents of the original ST-80 described in the "Blue Book."
- What about function/method pointers? Can I treat one of an instance's
methods as a block, or do I have to make a new block and call the method inside that?
The latter. And it is relatively trivial to create classes with Block-like APIs that internally invoke some method with some object as the receiver. See, for example, Object>perform:, Object>perform:with: and Object>withArguments:
Finally,
- Is this list a good place to ask questions like this? If it isn't, is
there a more suitable one?
This list is one place to ask such questions. Another option would be the newsgroup comp.lang.smalltalk.