简体   繁体   中英

How to specify class for instance variable in smalltalk

Probably I haven't understood the concepts of smalltalk enough, but here is my problem:

I am creating a class, let's call it Main-class , that has an instance variable bar , that I want to be of a certain class - Other-class , and use this Other-class ' methods on that in the Main-class methods kind of like this:

    Object subclass: #Other-class
        instanceVariableNames: 'foo'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Custom-class'

setFoo: newFoo

    foo := newFoo.

And the Main-class :

  Object subclass: #Main-class
        instanceVariableNames: 'bar'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Custom-class'

newBar: val

    bar := Bar new. 
    bar setFoo: val.

Obviously, I get an error that there is no setFoo method. But how do I specify that I want bar to be variable of a specific class and then use that class' methods on it?

Concerning the question's title: you don't. Smalltalk is a dynamically typed language, which means that the value of a variable can have different types at different points in time -- types are not declared for variables. But for humans, you can note the actual types of the variables in the class comment (see the ? button next to the instance-side and class-side buttons in the system browser).

Concerning your problem: You have to make sure that the object that is assigned to the instance variable bar is of a suitable type. In this case it must understand the message setFoo: . In your second code snippet, this means either:

  1. that instead of Bar you should use another class that can respond to setFoo: , such as Other-class (which is an odd name by the way because of the hyphen, you cannot easily reference that in your methods, use CamelCase instead), to fill the variable, or
  2. that setFoo: must be implemented for the class Bar .

The respondsTo: method can be used to determine if an object responds to a message:

bar respondsTo: #setFoo
  ifTrue: [bar setFoo: val]
  ifFalse: [missiles launch]

If you don't want to launch the missiles when bar does not understand setFoo , then decide what you want to happen. Maybe your program should crash with an error. That's less extreme than launching the missiles, but still kind of extreme and rarely what you really want particularly if other people are using your software.

Option: Just use the right type of object

ifFalse: [bar := ClassWithSetFoo new; setFoo: val]

Option: extend the object to do what you need by modifying its Class

ifFalse: [ (bar class) addInstVarName: 'foo'.
           (bar class) compile: 'setFoo: newFoo [foo := newFoo]'.
           bar setFoo: val. ]

The second option may or may not be what you want to do depending on context. Even if it isn't, it illustrates the power of Smalltalk's dynamic typing. A good deal of the "magic" of Ruby on Rails is built using a similar strategy. It is possible because Ruby objects have a lot of philosophical similarity to Smalltalk's objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM