I have a stupid question: How do you pass information into the #initialize
method at object creation time? You can't use any of the instance methods or accessors because they don't yet exist! So how do you pass information in? Thanks, Richard |
On Wed, 2008-01-16 at 08:46 -0500, Richard Eng wrote: > I have a stupid question: How do you pass information into the #initialize > method at object creation time? You can't use any of the instance methods or > accessors because they don't yet exist! So how do you pass information in? You do not! :) If you want to pass values into an object you may do this with your own constructor for the object. This contructor creates a new object and passes some values to it. Example: MyObject class>>on: aStream ^ self new stream: aStream in your code you do: myObject := MyObject on: aStream hope this helps, Norbert |
In reply to this post by Richard Eng
Hi Richard,
The instance variables and methods, including accessors, exist when the object is created. They do not depend on the initialize method. Thus you can access any instance variable or call any defined method, such as accessors, at any time after creation. Whether they have a value or return anything useful depends on your object and how you *chose* to initialize it. The use of #initialize is a convention to set-up object state *after* the object has been created. You do not have to stick to this. For example, consider the Point class. On the class side it defines: x: xInteger y: yInteger "Answer an instance of me with coordinates xInteger and yInteger." ^self basicNew setX: xInteger setY: yInteger And on the instance side: setX: xValue setY: yValue x _ xValue. y _ yValue So, effectively we have two constructor methods, one on the class side which passes parameters to the one on the instance side which does all the work. In this case, the #initialize methods is never called because the class side constructor sends #basicNew instead of #new. This makes more sense if we look at how #new is defined on Behaviour. new "Answer a new initialized instance of the receiver (which is a class) with no indexable variables. Fail if the class is indexable." ^ self basicNew initialize Some people use #initializeWith???: type methods instead of set???: methods. I'm not sure which is better. Having said all that, I often do what Norbert suggests and just call setter methods from the class side constructor: MyObject class>>on: aStream ^ self new stream: aStream; yourself This is great if I just want to set some instance variables and run. The possible downside is you may not want to have the setter #stream: around. Regards, Zulq. Richard Eng wrote: > I have a stupid question: How do you pass information into the #initialize > method at object creation time? You can't use any of the instance methods or > accessors because they don't yet exist! So how do you pass information in? > > Thanks, > Richard > > > > |
In reply to this post by Richard Eng
I'm not finding this to be true. I have a class #GSAssignmentList. It has
instance variable #clientId and accessor #clientId:. I do the following: self call: (GSAssignmentList new clientId: aValue) In the #initialize method for GSAssignmentList, I write to the Transcript: Transcript cr; show: 'RKE: clientId = ', clientId asString. It shows 'nil'. In #renderContentOn:, I write to the Transcript and get aValue, as expected. This is contrary to what you're telling me *if* the object is created with #clientId = aValue *before* #initialize starts to execute. You see, I need the value of aValue in order for #initialize to complete. Regards, Richard ---------------- Zulq Alam wrote: Hi Richard, The instance variables and methods, including accessors, exist when the object is created. They do not depend on the initialize method. Thus you can access any instance variable or call any defined method, such as accessors, at any time after creation. Whether they have a value or return anything useful depends on your object and how you *chose* to initialize it. The use of #initialize is a convention to set-up object state *after* the object has been created. |
new calls initialize.
On Jan 16, 2008 6:25 PM, Richard Eng <[hidden email]> wrote: > I'm not finding this to be true. I have a class #GSAssignmentList. It has > instance variable #clientId and accessor #clientId:. I do the following: > > self call: (GSAssignmentList new clientId: aValue) > > In the #initialize method for GSAssignmentList, I write to the Transcript: > > Transcript cr; show: 'RKE: clientId = ', clientId asString. > > It shows 'nil'. > > In #renderContentOn:, I write to the Transcript and get aValue, as expected. > This is contrary to what you're telling me *if* the object is created with > #clientId = aValue *before* #initialize starts to execute. > > You see, I need the value of aValue in order for #initialize to complete. > > Regards, > Richard > > ---------------- > > Zulq Alam wrote: > > Hi Richard, > > The instance variables and methods, including accessors, exist when the > object is created. They do not depend on the initialize method. Thus you > can access any instance variable or call any defined method, such as > accessors, at any time after creation. Whether they have a value or > return anything useful depends on your object and how you *chose* to > initialize it. > > The use of #initialize is a convention to set-up object state *after* > the object has been created. > > > > |
In reply to this post by Richard Eng
On Jan 16, 2008 9:25 AM, Richard Eng <[hidden email]> wrote:
> You see, I need the value of aValue in order for #initialize to complete. In that case, you probably want to move that part of the initialization code out of #initialize, and then write something like this: MyClass>>clientId: aValue clientId := aValue. self adjustForClientId: aValue. Of course, you'll also have to allow for the possibility that an object may sometimes not be fully initialized. For example, your #printOn: method may look like this: MyClass>>printOn: aStream clientId ifNil: [^super printOn: aStream]. .... Hope this helps! --Tom Phoenix |
In reply to this post by Richard Eng
Your original statement was that "You can't use any of the instance
methods or accessors because they don't yet exist!". I am saying you can use them, and the do exist, although they may or may not have a value depending on how you chose to initialize your object. If you do not change anything, then #new will send the newly created object #initialize. To avoid this behaviour you will need to create a class side method and send #basicNew to create your instance and then initialize it as you desire. Have a look at the Point example I included. Regards, Zulq. Richard Eng wrote: > I'm not finding this to be true. I have a class #GSAssignmentList. It has > instance variable #clientId and accessor #clientId:. I do the following: > > self call: (GSAssignmentList new clientId: aValue) > > In the #initialize method for GSAssignmentList, I write to the Transcript: > > Transcript cr; show: 'RKE: clientId = ', clientId asString. > > It shows 'nil'. > > In #renderContentOn:, I write to the Transcript and get aValue, as expected. > This is contrary to what you're telling me *if* the object is created with > #clientId = aValue *before* #initialize starts to execute. > > You see, I need the value of aValue in order for #initialize to complete. > > Regards, > Richard > > ---------------- > Zulq Alam wrote: > > Hi Richard, > > The instance variables and methods, including accessors, exist when the > object is created. They do not depend on the initialize method. Thus you > can access any instance variable or call any defined method, such as > accessors, at any time after creation. Whether they have a value or > return anything useful depends on your object and how you *chose* to > initialize it. > > The use of #initialize is a convention to set-up object state *after* > the object has been created. > > > > |
In reply to this post by Richard Eng
>>>>> "Richard" == Richard Eng <[hidden email]> writes:
Richard> In #renderContentOn:, I write to the Transcript and get aValue, as Richard> expected. This is contrary to what you're telling me *if* the object Richard> is created with #clientId = aValue *before* #initialize starts to Richard> execute. The purpose of aClass>>#initialize is to make a "bare object" with the internal state set up so that it can be *any* instance of that class. If you want a specific state set from a class-side constructor, then you do as has been said a few times in this thread already: call a (often private) instance method that further tweaks the state. "Foo class" makeWidgetWithX: x andY: y "instance creation" ^self basicNew initialize setX: x setY y; yourself. "Foo" setX: anXInteger andY: aYInteger "private" x := anXInteger. "set instance var" y := aYInteger. "set instance var" "returns self, but we don't care" Then you call myFoo := Foo makeWidgetWithX: 123 andY: 45. -- Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <[hidden email]> <URL:http://www.stonehenge.com/merlyn/> Perl/Unix/security consulting, Technical writing, Comedy, etc. etc. See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training! |
In reply to this post by Richard Eng
Hi Richard,
There are no Stupid ... well you know. I thought I'd add to this thread with another answer. There are plenty of ways to pass information into initialize. You can use any information that already exists and then just reference it in initialize. For example say you have some parameter that your application sets and you want to use the value of that parameter in your class. You could set your initialize to do something like this. MyDomainObject>>initialize "set initial values" super initialize. self myApplicationParameter: MyApplicationParameterClass someParameter. As long as you use information that exists somewhere else you can reference it. The issue that people are trying to point out is that if your information is not static and changes with each instantiation then you are better building an instance creation method. This method moves allows you to setup an object the way you need it during creation. For example MyDomainObject class>>newWithApplicationParameter: aParameter "return to the sender an instance of MyDomainObject" ^self new myApplicationParameter: aParameter; yourself Now instead of calling: aDomainObject := MyDomainObject new. You call aDomainObject := MyDomainObject newWithApplicationParameter: MyApplicationParameterClass someParameter. This makes much more sense since many people expect that initialize sets either default values or sets up ivars with proper classes. For Example you might use initialize to do something like this. MyDomainObject>>initialize "set initial values" super initialize. self collectionOfValues: OrderedCollection new. self initialState: #new. self applicationParameterHolder: (MyApplicationParameterHolder newFor: self). Hope that helps! Happy Squeaking Ron Teitelbaum President / Principal Software Engineer US Medical Record Specialists > From: Richard Eng > > I have a stupid question: How do you pass information into the > #initialize > method at object creation time? You can't use any of the instance methods > or > accessors because they don't yet exist! So how do you pass information in? > > Thanks, > Richard > > |
In reply to this post by Richard Eng
Though many of the comments have touched on the key points, you might find it useful to look at Kent Beck's Smalltalk Best Practice Patterns book which really covers this and other topics well. It's definitely not a stupid question and one has to think about the downstream implications of choosing an approach particularly wrt subclasses. Because of that I tend to use a variation of the initializeWith: approach that looks something like:
materializeUsing: aDictionary self beforeMaterializing: aDictionary. self initializeUsing: aDictionary. self afterMaterializing: aDictionary In Object, beforeMaterializing: and afterMaterializing: do nothing and initializeUsing: simply calls initialize. Having before and after hooks makes it easier to evolve the class. You can use this approach with many existing classes, though you may have to be careful to understand how a class's initialize really works. Then on there are two class side methods, materializeUsing: aDictionary ^self basicNew materializeUsing: aDictionary materialize ^self materializeUsing: Dictionary new. The actual code in my framework is slightly more complicated but not by much. There is some overhead but for me it's a small price to pay for the consistency and flexibility it buys. HTH, Laurence On Jan 16, 2008 8:46 AM, Richard Eng <[hidden email]> wrote: I have a stupid question: How do you pass information into the #initialize |
In reply to this post by Zulq Alam-2
>
> Richard Eng wrote: >> I'm not finding this to be true. I have a class #GSAssignmentList. >> It has >> instance variable #clientId and accessor #clientId:. I do the >> following: >> self call: (GSAssignmentList new clientId: aValue) >> In the #initialize method for GSAssignmentList, I write to the >> Transcript: >> Transcript cr; show: 'RKE: clientId = ', clientId asString. >> It shows 'nil'. Of course it does. You've simply written the code incorrectly. GSAssignmentList new creates a new GSAssignmentList instance with all instance variables set to nil. sends #initialize to that new instance. returns the new instance ... and then.... (new instance) clientId: aValue presumably sets the clientId instance variable to aValue. Do remember that you don't need to name them the same. Nothing wrong with having a method named #fred: that sets the value of an instvar named wilma. So if you report the value of clientId as part of an #initialize method, what value would you expect? How about 'nil'? Unless you actually explicitly set clientId in the initialize method before you show it on the Transcript how could you expect it to be anything else? Smalltalk syntax is very simple and concise unary binary keyword left to right parentheses limit local scope as in most syntaxes tim -- tim Rowledge; [hidden email]; http://www.rowledge.org/tim Oxymorons: Business ethics |
Free forum by Nabble | Edit this page |