Like in Java, C# etc. How would I define something like enum Direction { input, output }
in Smalltalk?

- 4,722
- 6
- 37
- 58
-
I'm not a Java programmer so I'm not sure whether you are referring to a way to define constants in Smalltalk. If that's the case, you should create a `PoolDictionary` and declare the constants there. I can elaborate on this if you confirm that my interpretation is correct. – Leandro Caniglia Mar 23 '18 at 14:55
-
Mo an enum is a type such that a variable of type enum X can only have a set of values defined for X - e.g. in this case `x: = new Direction` means that x is input or ouput abd no possibilty of being anything else. – mmmmmm Mar 23 '18 at 15:23
4 Answers
Trivial Approach
The most trivial approach is to have class-side methods returning symbols or other basic objects (such as integers).
So you can write your example as follows:
Direction class>>input
^ #input
Direction class>>output
^ #output
And the usage:
Direction input
The main downsides are:
- any other "enum" that happens to return the same value will equals to this one, even though the enums are different (you could return e.g.
^ self name + '::input'
) - during debugging, you see the actual value of the object, which is especially ugly for number-based enums (Uh... what does this 7 mean?)
Object Approach
A better way is to create your own enum object and return instances of it.
Such object should:
- override
=
andhash
, so you can compare them by your value and use the enum as key in hashed collections (dictionaries) - store the actual unique value representation
- have custom
printOn:
method to ease debugging
It could look something like this
Object subclass: #DirectionEnum
slots: { #value }
classVariables: { }
category: 'DirectionEnum'
"enum accessors"
DirectionEnum class>>input
^ self new value: #input
DirectionEnum class>>output
^ self new value: #output
"getter/setters"
DirectionEnum>>value
^ value
DirectionEnum>>value: aValue
value := aValue
"comparing"
DirectionEnum>>= anEnum
^ self class = anEnum class and: [ self value = anEnum value ]
DirectionEnum>>hash
^ self class hash bitXor: self value hash
"printing"
DirectionEnum>>printOn: aStream
super printOn: aStream.
aStream << '(' << self value asString << ')'
the usage is still the same
Direction input.
DirectionEnum output asString. "'a DirectionEnum(output)'"
and the problems mentioned in the trivial approach are resolved.
Obviously this is much more work, but the result is better. If you have many enums, then it could make sense to move the basic behavior to a new superclass Enum
, and then DirectionEnum
would just need to contain the class-side methods.

- 9,617
- 5
- 38
- 51
-
1This is a very nice answer. I would just add that there are probably three reasons of why you need enums. 1) you want to have a programmatic name for some constant (that can be use by such tools as autocomplete or refactoring browser) and trivial approach is good for that; 2) you want to have a different functionality for a certain kind of an “enum” and here is where the object approach shines; 3) you want to restrict what is assigned to a variable: I general you don’t want to have this in smalltalk, but you can always add assertions to setters or use a custom validating Slot in Pharo – Uko Mar 26 '18 at 07:13
The closest Smalltalk feature to an enum type is the SharedPool
(a.k.a. PoolDictionary
). Therefore, if you are porting some enum from, say, Java to Smalltalk, you might want to use a SharedPool
. Here is how to do so:
For every enum in your type you will define an association in the pool with key
the type name and value
the type value.
In some dialects PoolDictionaries
are dictionaries, in Pharo they are subclasses of SharedPool
. In Pharo, therefore, you declare all the type names as class variables. Then you associate values to keys in an initialization method (class side).
For example, you could define a subclass of SharedPool
named ColorConstants
with the class variables 'Red', 'Green', 'Blue', 'Black', 'White'
, etc., like this:
SharedPool
subclass: #ColorConstants
instanceVariableNames: ''
classVariableNames: 'Red Green Blue Black White'
poolDictionaries: ''
package: 'MyPackage'
To associate names with values, add a class side initialization method on the lines of:
ColorConstants class >> initialize
Red := Color r: 1 g: 0 b: 0.
Green := Color r: 0 g: 1 b: 0.
Blue := Color r: 0 g: 0 b: 1.
Black := Color r: 0 g: 0 b: 0.
White := Color r: 1 g: 1 b: 1.
"and so on..."
Once you evaluate ColorConstants initialize
you will be able to use the pool in your class
Object
subclass: #MyClass
instanceVariableNames: 'blah'
classVariableNames: ''
poolDictionaries: 'ColorConstants'
package: 'MyPackage'
In MyClass
(and its subclasses) you can refer to the colors by name:
MyClass >> displayError: aString
self display: aString foreground: Red background: White
MyClass >> displayOk: aString
self display: aString foreground: Green background: Black

- 14,495
- 4
- 29
- 51
For simple cases, just use symbols as Peter suggested - you could also just store the possible values in an IdentityDictionary
.
If you mean the more powerful kind of enums that are available in Java (where they can be more than just a type of named constant; they can have behaviour, complex attributes, etc.), then I'd take it a step further than Peter and just create a subclass for each enum type. Even if you're talking a large number of enums (your use case seems to need only two), don't be afraid of having many subclasses that only have one or two methods in them that are just used to differentiate them from each other, with most of the work done in the common superclass.

- 4,848
- 4
- 42
- 72
Since Smalltalk is dynamically typed, you cannot restrict the value of a variable to a subset of objects anyway, so there is no difference between enum members and global constants, except for the namespacing through the enum name.
Edit: For options how to define your enum constants, see Peter's answer. Just let me mention that you can also use symbols directly if it is sufficient for your needs. direction := #input. direction := #output

- 3,006
- 1
- 20
- 26