Discussion:
Enumeration types
(too old to reply)
Ondrej Hrabal
2004-10-25 17:48:06 UTC
Permalink
Hi all!

I'd like to know what's your opinion on the enumeration types missing
in Oberon. I think it was a big mistake to remove them. I can't see a
satisfactory way to replace them:

1) Integer constants

-it's extremely easy to make an error in the declaration (e.g. use the
same value twice)
-if you need to add a new constant and still preserve a logical
ordering of the declarations you may have to increment all the values
-these declarations are the ugliest part of any Oberon source
-the programmer is forced to work with low-level information that he
doesn't want to care about and even make this information a part of
public interfaces
-the interfaces doesn't make it clear which INTEGER parameters and
which constants are to be used together
-it's possible to compute the result of "(Monday + LeftAlign) MOD
SunkenBorder" and pass it to a SetColor procedure
-and so on

Conclusion: good enough for a C programmer

2) Object types

For every enumeration type we could write a separate module that would
contain the following:

-an abstract type representing the enumeration (e.g. ButtonStyle,
DayOfWeek)
-a set of private subtypes implementing the individual values
-a set of factory procedures for the individual values (using the
Flyweight pattern for efficiency)
-a public (LIMITED) "mutable wrapper" type together with a factory
procedure

From a client's point of view this would be perfect, but definition of
an average enumeration type might take some 200 or 300 lines of
code...

3) My solution: a stupid one, but IMHO still the best one

Consider I need an alignment parameter with possible values Left, Top,
Right, Bottom and Center. I will happily declare it as a CHAR and use
self-explanatory character literals 'L', 'T', 'R', 'B', 'C'. This
remedies many of the "INTEGER solution" problems, but of course not
all.

Niklaus Wirth explained that the problem with the enumeration types
was that they weren't extensible, so they had to be removed from the
object-oriented Oberon. I think this was a mistake. After all, who
would like to extend the BOOLEAN type with a new value (perhaps
MAYBE)? Indeed, extension of an enumeration type would break all
existing implementations as they just wouldn't know what to do with
the new values.
=> The fact they are not extensible is an important feature, not a
weakness!

What's your opinion on the subject? And do you know any other solution
to simulate enum types?

Andy
Christian Demmer
2004-10-25 19:31:20 UTC
Permalink
Post by Ondrej Hrabal
I'd like to know what's your opinion on the enumeration types missing
in Oberon. I think it was a big mistake to remove them.
Wirth's goal was simplicity and removing enumerations and the whole
subrange types reduces complexity a lot. But I agree that it was not a
good idea in general.
Post by Ondrej Hrabal
1) Integer constants
In my opinion the only way to go if you want Oberon as it is.
Post by Ondrej Hrabal
What's your opinion on the subject? And do you know any other solution
to simulate enum types?
I think enumerations should be added but in a slightly different way
than in Modula. A valid objections is that enumerations polute the
namespace with the identifiers for the "constants". I suggest that
members of enumerations have to be qualified by the enumeration name and
are compatible to the integer type but not vice versa.

Example:

TYPE
Relation* = (eql*, neql*, gr*, greql*, le*, leql*, in*, is* );
...

VAR r : Relation;
i : INTEGER;
BEGIN
IF r = Relation.eql THEN ...
r := 42; (* error *)
i := Relation.eql (* ok *)

That allows use of enumeration members in sets because they are
compatible to integer types.
In practice I think this works well despite probably beeing a bit
verbose sometimes.

Greetings, Christian
Ondrej Hrabal
2004-10-26 20:50:46 UTC
Permalink
Post by Christian Demmer
I think enumerations should be added but in a slightly different way
than in Modula. A valid objections is that enumerations polute the
namespace with the identifiers for the "constants". I suggest that
members of enumerations have to be qualified by the enumeration name and
are compatible to the integer type but not vice versa.
TYPE
Relation* = (eql*, neql*, gr*, greql*, le*, leql*, in*, is* );
...
VAR r : Relation;
i : INTEGER;
BEGIN
IF r = Relation.eql THEN ...
r := 42; (* error *)
i := Relation.eql (* ok *)
That allows use of enumeration members in sets because they are
compatible to integer types.
In practice I think this works well despite probably beeing a bit
verbose sometimes.
Greetings, Christian
I like your proposal. It would also be possible to declare partially
or fully opaque types (with non-exported values), which could be
useful.

Andy
Chris Burrows
2004-10-26 01:12:04 UTC
Permalink
Post by Ondrej Hrabal
Hi all!
I'd like to know what's your opinion on the enumeration types missing
in Oberon. I think it was a big mistake to remove them. I can't see a
This was my only complaint when Oberon was first introduced. However, once I
understood the reasoning behind the decision I have been happy to live
without them. Read an informative post on the subject by Marc-Michael
Brandis from ETH published in the comp.lang.misc newsgroup back in 1991. You
can still access it through Google Groups:

http://tinyurl.com/6mw3j

Chris Burrows
CFB Software
http://www.cfbsoftware.com/gpcp
Ondrej Hrabal
2004-10-26 20:46:31 UTC
Permalink
Post by Chris Burrows
Post by Ondrej Hrabal
Hi all!
I'd like to know what's your opinion on the enumeration types missing
in Oberon. I think it was a big mistake to remove them. I can't see a
This was my only complaint when Oberon was first introduced. However, once I
understood the reasoning behind the decision I have been happy to live
without them. Read an informative post on the subject by Marc-Michael
Brandis from ETH published in the comp.lang.misc newsgroup back in 1991. You
http://tinyurl.com/6mw3j
Chris Burrows
CFB Software
http://www.cfbsoftware.com/gpcp
I still think the matter of extensibility is of no interest.
Simplicity of the language is a more important reason, but I'm not
sure that enums are the right target. To abandon them means to give up
part of type safety and interface clarity. Why not remove REPEAT, LOOP
et. al. that add no functionality at all?

Regards, Andy
Josef Templ
2004-10-29 14:55:35 UTC
Permalink
Hi everybody!

In addition to the the comments posted on this issue,
one should not forget about the problem of persisting
enumeration data. If you write an enumeration variable to file
and read it back in later, it needs to be converted into
an integer number and back. Stored enum numbers must not be changed
when a new enum constant is added or a reordering is performed later in the
program.
So this does not only require an unchecked conversion between enum and int
but also explicit control over the values.
The only alternative would really be to introduce type safe enums like in
Java 1.5
but this comes with some runtime overhead. An enum type is mapped to a class
and an
enum constant is mapped to an instance of this class. Store/Load needs to
deal with object identities and CASE needs a hash table, etc.

- Josef

August
2004-10-27 02:50:16 UTC
Permalink
Given that the number of "enumeration" constants is no greater than
MAX(SET) (which is at least 32) I find the following idiom quite
practical (not that it replaces a real enumeration type):

CONST
red = 0;
green = 1;
blue = 2;
colors = {red, green, blue};

(* SetColor(c) sets the color to c, where c is an element of colors.
*)
PROCEDURE SetColor(color: INTEGER);
BEGIN
ASSERT(color IN colors);
CASE color OF
red: (* ... *)
| green: (* ... *)
| blue: (* ... *)
END
END SetColor;

If you e.g. want to add the color "yellow" neither the procedure
documentation nor the precondition needs to be modified.

If an enumeration type is added then, for consistency, there is also a
need to add sets of enumerations. If the enumeration constants are not
qualified then two different enumerations can't share the same
identifier unless we see all the enumeration constants in a module as
a (mathematical) set. With qualified enumeration constants, outside
the defining module they tend to get quite long, e.g.
AModule.ButtonColor.red compared to AModule.red. Moreover in Oberon-2
it's possible use all kinds of anonymous types in
variable/field/parameter declarations, but if the enumeration type
uses qualified constants it's not so obvious how to designate them.

Regards,
August
Post by Ondrej Hrabal
Hi all!
I'd like to know what's your opinion on the enumeration types
missing
in Oberon. I think it was a big mistake to remove them. I can't see a
1) Integer constants
-it's extremely easy to make an error in the declaration (e.g. use the
same value twice)
-if you need to add a new constant and still preserve a logical
ordering of the declarations you may have to increment all the
values
-these declarations are the ugliest part of any Oberon source
-the programmer is forced to work with low-level information that he
doesn't want to care about and even make this information a part of
public interfaces
-the interfaces doesn't make it clear which INTEGER parameters and
which constants are to be used together
-it's possible to compute the result of "(Monday + LeftAlign) MOD
SunkenBorder" and pass it to a SetColor procedure
-and so on
Conclusion: good enough for a C programmer
2) Object types
For every enumeration type we could write a separate module that would
-an abstract type representing the enumeration (e.g. ButtonStyle,
DayOfWeek)
-a set of private subtypes implementing the individual values
-a set of factory procedures for the individual values (using the
Flyweight pattern for efficiency)
-a public (LIMITED) "mutable wrapper" type together with a factory
procedure
From a client's point of view this would be perfect, but definition of
an average enumeration type might take some 200 or 300 lines of
code...
3) My solution: a stupid one, but IMHO still the best one
Consider I need an alignment parameter with possible values Left, Top,
Right, Bottom and Center. I will happily declare it as a CHAR and use
self-explanatory character literals 'L', 'T', 'R', 'B', 'C'. This
remedies many of the "INTEGER solution" problems, but of course not
all.
Niklaus Wirth explained that the problem with the enumeration types
was that they weren't extensible, so they had to be removed from the
object-oriented Oberon. I think this was a mistake. After all, who
would like to extend the BOOLEAN type with a new value (perhaps
MAYBE)? Indeed, extension of an enumeration type would break all
existing implementations as they just wouldn't know what to do with
the new values.
=> The fact they are not extensible is an important feature, not a
weakness!
What's your opinion on the subject? And do you know any other
solution
to simulate enum types?
Andy
Chris Burrows
2004-10-27 03:24:47 UTC
Permalink
Post by Ondrej Hrabal
-if you need to add a new constant and still preserve a logical
ordering of the declarations you may have to increment all the values
If this is of concern a possible solution is to use the form:

CONST
hearts = 0;
clubs = hearts + 1;
diamonds = clubs + 1;
spades = diamonds + 1;

As well as indicating to the reader that there is a relationship between the
items, adding a new value later only requires a change to, at most, a single
existing item.

Chris Burrows
CFB Software
http://www.cfbsoftware.com
Loading...