Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Adding enums to Java.

3 views
Skip to first unread message

David Wheeler

unread,
Aug 20, 1996, 3:00:00 AM8/20/96
to

I'm looking into techniques to add some "missing"
functionality to Java, such as enumerated values (enums), while
still keeping its "write once, run everywhere" ideal.

Here are my thoughts on what an "enum" in Java could look like;
comments welcome.


For enumerations, the following issues exist:

* Where should enumerations be declared?
Since the "class" is the only Java structuring mechanism,
enumerations must be "inside" classes. This is consistent
with existing practice of declaring constants in classes
to simulate enumerated values.

* Should enumerations be new types (like C++ and Ada), or
rename an existing type (like C and current Java where int's are
used as enumeration values)? It's safer to consider enumerations
as new types, but it'd be nice to interface with "existing" Java
classes that use int's to simulate enumerated values.
Thus, the default is to consider enumerations as new types,
but permit a extra marker to define the underlying type.
We end up with two kinds of enums: "new-type" and "interchangeable".
A new-type enum looks like the following:
enum answer {NO, YES, MAYBE};
An interchangeable enum (say, with an "int") looks like:
enum alignment (int) {LEFT, CENTER, RIGHT};

{Is this a reasonable syntax for interchangeable enums? Alternatives:
int enum alignment {LEFT, CENTER, RIGHT};
enum (int) alignment {LEFT, CENTER, RIGHT};
}

* Should enumeration values be settable? Most languages let users
set the values of each enumeration entry. This is easy to
support by itself, but complicates implementation of enumeration
operations, especially for the new-type variety.
This is especially true if the enumeration range isn't continguous.

For interchangeable enums, you may as well let any enumeration
value be set; after all, these are just specific values of the
base type. For new-type enums, things are more uncertain.
Permitting the setting of the _first_ value of the enum probably
is not a significant issue, since continguity is easy to ensure
after that. Arbitrarily setting values after the first one is
less certain.

* operations: What operations should be supported, and should ranges
be checked? Again, for interchangeable enums, this isn't a real
issue; it's just the base type, so the checking of the base
type is a sensible choice. For new-type enums, increment (++) and
decrement (--) seem like minimums, and some simple way to create
ranges (in for loops), and casts. Should the range be checked
after each operation? Probably so (in some cases the checks could be
optimized away).

Here's an enumeration syntax based on ANSI C (See K&Rv2, A8.4):

enum-specifier:
"enum" identifier {enum-base-type} "{" enumerator-list "}"

// Note: don't permit "void" as a type here!

enum-base-type:
"(" simple_type_specifier ")"

enumerator-list:
enumerator
enumerator-list "," enumerator

enumerator:
identifier { = constant-expression }

--- David A. Wheeler
Net address: whe...@ida.org


Bill Wilkinson

unread,
Aug 20, 1996, 3:00:00 AM8/20/96
to David Wheeler

David Wheeler wrote:
>
> Here's an enumeration syntax based on ANSI C (See K&Rv2, A8.4):
>
> enum-specifier:
> "enum" identifier {enum-base-type} "{" enumerator-list "}"
>
> // Note: don't permit "void" as a type here!
>
> enum-base-type:
> "(" simple_type_specifier ")"
>
> enumerator-list:
> enumerator
> enumerator-list "," enumerator
>
> enumerator:
> identifier { = constant-expression }
>

I don't really see the need for the "enum-base-type".
Unless you are a real space fanatic, what harm does
it do to let the compiler determine the space needed
by an enum? (Or, in keeping with the Java
philosophy of NOT letting the compiler make such
decisions, why not just choose a size and be done
with it. "int" size works for me. You will seldom
gain any REAL space with anything smaller, anyway,
just because of the way most classes are written.)

Also, on most machines an "int" will be the most
efficient size for speed.

As for allowing "settable" values: I tend to like
the feature because I want to avoid zero and -1
as legal values that can crop up by accident. But
I'd probably be happy if enumeration values simply
NEVER started with zero and if a zero value was
treated as illegal (an exception) by the runtime.

Having said all that...

As ugly as it is, I can live without them. I just
use an "int" argument and then "weird" final int
values. I validate the values when called.

Example:

class Frap {

public static final int NotOpen = 0xACCE550;
// sort of spells "ACCESS 0"
public static final int ReadOnly = 0xACCE551;
public static final int ReadScribble = 0xACCE552;
public static final int ReadWrite = 0xACCE553;
public static final int Exclusive = 0xACCE554;

void doSomething( int accessMode )
{
switch (accessMode) {
case NotOpen:
...
default:
throw SomeSortOfException( );
}
...
}
...
}

// then use it thus:
Frap f = new Frap( );
f.doSomething( Frap.Exclusive );
...

If somebody REALLY WANTS to call me via
f.doSomething( 0xACCE554 );
well, what the heck, let them. If every once
in a while I purposely change my "enumeration" values,
I'll eventually catch them at it, won't I? (big grin)

With 32 bits to play with, surely you can dream up a
handful of bit patterns that nobody is likely to happen
onto by accident, so your "int that is really an enum"
is reasonably safe.

BUT...

Despite my "having said all that"...

The very first thing I noticed to be REALLY missing in
Java was "enum". So if you can convince the powers that
be to add them in...

(Now if you'd just start working on templates.)

Doug Bell

unread,
Aug 22, 1996, 3:00:00 AM8/22/96
to

Bill Wilkinson <Bi...@Asymetrix.com> wrote:

> David Wheeler wrote:
> >
> > Here's an enumeration syntax based on ANSI C (See K&Rv2, A8.4):
> >
> > enum-specifier:
> > "enum" identifier {enum-base-type} "{" enumerator-list "}"
> >
> > // Note: don't permit "void" as a type here!
> >
> > enum-base-type:
> > "(" simple_type_specifier ")"
> >
> > enumerator-list:
> > enumerator
> > enumerator-list "," enumerator
> >
> > enumerator:
> > identifier { = constant-expression }
> >
>
> I don't really see the need for the "enum-base-type".
> Unless you are a real space fanatic, what harm does
> it do to let the compiler determine the space needed
> by an enum? (Or, in keeping with the Java
> philosophy of NOT letting the compiler make such
> decisions, why not just choose a size and be done
> with it. "int" size works for me. You will seldom
> gain any REAL space with anything smaller, anyway,
> just because of the way most classes are written.)
>
> Also, on most machines an "int" will be the most
> efficient size for speed.

Gee, and I was thinking about using a 'long', or maybe even a 'float'... :)

The thing that I found missing in ANSI C enums was the lack of a type.
When used in expressions with other data types (byte, short in Java), it
can cause unexpected casting. This is less of an issue in Java, since
most operations must be cast to an int or long because the bytecodes don't
directly support the operation as an int or long, so the cast is going to
happen anyway.

The other issue is that Java requires explicit casting whenever precision
is lost, so it can make the code ugly to have the enums always be 'int',
if say they are going to typically be assigned to a 'byte' or 'short'.

But really, I can live without enums. This minimalist approach to
language design is starting to grow on me. :)

Doug Bell
db...@shvn.com

Jim Balter

unread,
Aug 26, 1996, 3:00:00 AM8/26/96
to

In article <dbell-22089...@news3.cts.com>,

Doug Bell <db...@shvn.com> wrote:
>But really, I can live without enums.

You'll say otherwise when you encounter some obscure bug caused by two
"enumint"s having the same value. It's totally bizarre, in a language that
makes true and false unconvertible, to find that all enum values, which are
conceptually separate abstract instances of separate types, to be all mushed
together as ints. From the perspective of type safety and abstraction (not to
mention the manual labor involved), this is just plain WRONG.

The other type botch is that there's no *typedef* or other way to create
abstract numeric types (Integer etc. don't qualify). Sure you don't need
typedef for objects, but numeric values belong to abstract types too. How do
I convert my C arithmetic encoding routines, which have types like
ArithEncoderVal, FreqVal, and AEOverFreqVal, which help me keep these all
straight? It's like going back to the Version 6 C compiler, before Ritchie
added typedef to the language; man, things were *primitive* back then (e.g.,
*all* struct members were in the *same* name space). Or *worse*: no typedefs
*and* no preprocessor. When the Java authors say they tossed typedef because
it isn't needed, they are fudging. They tossed it so the parser could handle
things like (p)-q, which is ambiguous in C without predeclaring all typenames
(if p is a typename, this is a cast). Since there are no typedefs in Java and
since p can't be a classname because -q must be primitive (they depend upon no
operator overloading here, too!) the compiler knows the '-' is binary. Very
clever, finding a way to keep the C-like syntax but dropping the requirement
that types be declared before being used. Too clever. One of the problems
with this sort of cleverness is that it's real hard to undo if you decide
later that it was a mistake. The Java syntax *depends* upon the names of
primitive types being keywords of the language and upon no operator
overloading. This is the sort of tight coupling we avoid like the plague in
OOP, and it is no better in a syntax definition. There's a lot in Java that
is very intelligent and well thought out. But there are also a few things
that just plain suck.

>This minimalist approach to
>language design is starting to grow on me. :)

As Albert Einstein said, "Make it as simple as possible, *but no simpler*".
--
<J Q B>


Mike Cowlishaw

unread,
Aug 26, 1996, 3:00:00 AM8/26/96
to

Always seemed to me that enums, being names, are best expressed as strings.
If you're worried about space, use short names; if not, use good names.

Mike Cowlishaw, IBM Fellow
http://www2.hursley.ibm.com


Paul Schwartz

unread,
Aug 26, 1996, 3:00:00 AM8/26/96
to

The problem with using strings as enumms is that it isn't compile time type safe.
ie if an enumm (as a string) is specified as a formal parmeter then ANY string
could be used as an actual parmeter. There are some solutions floating around out
there which allow you to emulate using classes. (I don't have them with me right
now and I'd rather not get it ALMOST right).

Paul
--
//---ps...@hitl.washington.edu------------------

Human Interface Technology Laboratory, University of Washington

For beatification |"Notes From a Bottle
two miracles are required; | Found on the Beach at Carmel"
For martyrdom, none. | Evan S. Connell, Jr.

Doug Bell

unread,
Aug 26, 1996, 3:00:00 AM8/26/96
to

j...@netcom.com (Jim Balter) wrote:

> Doug Bell <db...@shvn.com> wrote:
> >But really, I can live without enums.
>
> You'll say otherwise when you encounter some obscure bug caused by two
> "enumint"s having the same value. It's totally bizarre, in a language that
> makes true and false unconvertible, to find that all enum values, which are
> conceptually separate abstract instances of separate types, to be all mushed
> together as ints. From the perspective of type safety and abstraction (not to
> mention the manual labor involved), this is just plain WRONG.

I don't see how enums are going to avoid the obscure bug you suggest. At
least in C++, two or more enums in the same list can have the same value.
In fact, this is frequently desired.

As to the other issue, the added type safety and abstraction would be
nice, but then I could probably list a lot of things that would be nice to
have but aren't necessary. I think that by first stripping the language
down to the minimum, rather than reflexively throwning in all those
features from other languages, Java is off to a better start. If it's
language features you want, then you'll probably be quite happy with Ada.

If you really want the type safety, then use Objects...that's what they're
there for. For example:

class MyEnum {
public static final MyEnum One = new MyEnum();
public static final MyEnum Two = new MyEnum();
public static final MyEnum Three = new MyEnum();
}

Then you can use MyEnum for declaration, be guaranteed of type safety
(even have hierarchical enums), get true abstraction and even get
unconvertable values so they can't be mixed with ints. If you want to get
a little fancier, have:

class MyEnum {
public static final MyEnum One = new MyEnum("One");
public static final MyEnum Two = new MyEnum("Two");
public static final MyEnum Three = new MyEnum("Three");

public String toString () { return name; }

private String name;
private MyEnum (String name) { this.name = name; }
}

And the set of enums will be locked in so it will be entirely type safe.

Sometimes it just takes a little thought to abandon ingrained ways...


> The other type botch is that there's no *typedef* or other way to create
> abstract numeric types (Integer etc. don't qualify). Sure you don't need
> typedef for objects, but numeric values belong to abstract types too. How do
> I convert my C arithmetic encoding routines, which have types like
> ArithEncoderVal, FreqVal, and AEOverFreqVal, which help me keep these all
> straight?

Well, I have to admit to missing this use of typedef. But again, I'm
getting by without it. Besides, in C/C++, you could have:

typedef int ArithEncoderVal;
typedef int FreqVal;

FreqVal x = 1;
ArithEncoderVal y = x;

without ever hearing a peep from the compiler, so it really only amounted
to inline documentation to use the typedef names except when you wanted to
change the actual underlying type. Given that Java has defined the sizes
of the underlying types (what a concept!), this probably isn't as big of
an issue anymore.


> >This minimalist approach to
> >language design is starting to grow on me. :)
>
> As Albert Einstein said, "Make it as simple as possible, *but no simpler*".

Well, quantum physics is probably a little less subjective than the issue
at hand.

Doug Bell
db...@shvn.com

Jonathan W. Locke

unread,
Aug 27, 1996, 3:00:00 AM8/27/96
to

i agree. you have a good point about enums. and unfortunately, they
didn't put 'enum' in the list of reserved keywords listed here in my java
in a
nutshell book... oops.

but as for the typedef argument, i find it ironic that you are essentially
arguing
that Java isn't OOP enough because it's going to force you to make a real
object
instead of aliasing the name of a basic type... yet i do understand what
you're getting
at here... i also think it's possible that there were other issues to
consider...
obviously a great deal of care went into design of the bytecode verifier
and a lot
of that work had to do with type-safety. so perhaps they decided that
typedef
would complicate that more than it was really worth (although perhaps you
could
put that under the heading of 'fudging' as well...)

for my two cents, i very rarely seem to run into cases where i want to do
operator overloading. what's more, i think it's nice to *always* know what
'+' and '*'
mean. so, simplicity may have been the design principle that got rid of
typedefs
and overloading...

what i personally miss most from C++ are:

1) method pointers (i constantly run into things i can't do without
these... *sigh*)
i've thought semi-seriously about things like dynamically generating
classes in
memory to get around this awful limitation. there must be something
hard about
making this fit into java because i can't imagine they didn't think
about this one at all...
2) multiple inheritance of *implementation* (i understand why they didn't
put this in
and i can live with that... for now...)
3) overloaded return values. i really can't figure out why this one wasn't
included...
again, i'll just have to assume there was some principle at stake
here... and the
restriction could always be lifted...
4) oh darn... and variable arguments could have been *so very* pretty in
java...

void foo(int a, ... args)
{
Object[] x = args;
}

(my syntax might be considered wacky by some, but you get the idea...)
and with instanceof and all, sprintf could have been typechecked
finally!
of course there are definitely deeper issues here too because basic
types
would have to be coerced to Objects to make it work... still this could
be added
without breaking anything (that i know of anyway...)!

of course there are lots of things from other languages i would have liked
too,
but i'd rather err on the side of simplicity than end up with unmanageable
feature
creep. give me 1, 3 and 4 and i'll be happy enough. i'd rather have
someone
smart think long and hard about 2 before deciding exactly how to add it!

cheers!

J

/**
* Contract Java programmer at large (Jo...@SealevelSoftware.com)
* @param codeSpecifications Your project requirements.
* @return High quality, well documented Java code.
* @see SealevelSoftware at http://www.sealevelsoftware.com/sealevel/
*/
public JavaCode Jonathan_Locke(String codeSpecifications) { /*
Undocumented algorithm... ;-) */ }

Jim Balter <j...@netcom.com> wrote in article <jqbDwq...@netcom.com>...
: In article <dbell-22089...@news3.cts.com>,


: Doug Bell <db...@shvn.com> wrote:
: >But really, I can live without enums.
:
: You'll say otherwise when you encounter some obscure bug caused by two
: "enumint"s having the same value. It's totally bizarre, in a language
that
: makes true and false unconvertible, to find that all enum values, which
are
: conceptually separate abstract instances of separate types, to be all
mushed
: together as ints. From the perspective of type safety and abstraction
(not to
: mention the manual labor involved), this is just plain WRONG.

:
: The other type botch is that there's no *typedef* or other way to create


: abstract numeric types (Integer etc. don't qualify). Sure you don't need
: typedef for objects, but numeric values belong to abstract types too.
How do
: I convert my C arithmetic encoding routines, which have types like
: ArithEncoderVal, FreqVal, and AEOverFreqVal, which help me keep these all

: straight? It's like going back to the Version 6 C compiler, before

:
: >This minimalist approach to


: >language design is starting to grow on me. :)
:
: As Albert Einstein said, "Make it as simple as possible, *but no
simpler*".

: --
: <J Q B>
:
:

Doug Bell

unread,
Aug 27, 1996, 3:00:00 AM8/27/96
to

"Jonathan W. Locke" <jo...@sealevelsoftware.com> wrote:

[snip]


> what i personally miss most from C++ are:
>
> 1) method pointers (i constantly run into things i can't do without
> these... *sigh*)
> i've thought semi-seriously about things like dynamically generating
> classes in
> memory to get around this awful limitation. there must be something
> hard about
> making this fit into java because i can't imagine they didn't think
> about this one at all...

I have yet to run into anything that can't be done with interfaces and/or
functors (function objects.) Have you?

In fact, functors are considerably *more* powerful than method pointers.


> 2) multiple inheritance of *implementation* (i understand why they didn't
> put this in
> and i can live with that... for now...)

Occassionally this is annoying, but I'm rather glad to see it left out.
Interfaces are quite powerful, and when combined with static methods, you
can get default implementations with just a little extra work.


> 3) overloaded return values. i really can't figure out why this one wasn't
> included...
> again, i'll just have to assume there was some principle at stake
> here... and the
> restriction could always be lifted...

How would you resolve the case where the return value is ignored? Require
the result to be cast? This is just off the top of my head, and I'm sure
there are other ambiguous cases. If clean and unambiguous rules could be
worked out, this might be nice, but again, this isn't functionally
restrictive since you just have to use a different name for the method
(e.g. maxint(), maxdouble(), etc.)


> 4) oh darn... and variable arguments could have been *so very* pretty in
> java...
>
> void foo(int a, ... args)
> {
> Object[] x = args;
> }
>
> (my syntax might be considered wacky by some, but you get the idea...)
> and with instanceof and all, sprintf could have been typechecked
> finally!
> of course there are definitely deeper issues here too because basic
> types
> would have to be coerced to Objects to make it work... still this could
> be added
> without breaking anything (that i know of anyway...)!

Interesting idea. Of course again this can be accomplished with Java,
just change the syntax a little to create the Object[] before the function
call. :)

Doug Bell
db...@shvn.com

Jonathan W. Locke

unread,
Aug 27, 1996, 3:00:00 AM8/27/96
to

if you're really worried about repeating the same constant values, how
about this?

class Enum
{
private static int val = 0;
static final int next()
{
return val++;
}
}

class test
{

static final int VAL1 = Enum.next();
static final int VAL2 = Enum.next();

static public void main(String[] arg)
{
System.out.println("VAL1 = " + VAL1);
System.out.println("VAL2 = " + VAL2);
}
}

so nice, i may even use it myself! ;-)

J

/**
* Contract Java programmer at large (Jo...@SealevelSoftware.com)
* @param codeSpecifications Your project requirements.
* @return High quality, well documented Java code.
* @see SealevelSoftware at http://www.sealevelsoftware.com/sealevel/
*/
public JavaCode Jonathan_Locke(String codeSpecifications) { /*
Undocumented algorithm... ;-) */ }


Doug Bell <db...@shvn.com> wrote in article
<dbell-26089...@news3.cts.com>...
: j...@netcom.com (Jim Balter) wrote:
:

: > Doug Bell <db...@shvn.com> wrote:
: > >But really, I can live without enums.
: >
: > You'll say otherwise when you encounter some obscure bug caused by two
: > "enumint"s having the same value. It's totally bizarre, in a language
that
: > makes true and false unconvertible, to find that all enum values, which
are
: > conceptually separate abstract instances of separate types, to be all
mushed
: > together as ints. From the perspective of type safety and abstraction
(not to
: > mention the manual labor involved), this is just plain WRONG.
:

: I don't see how enums are going to avoid the obscure bug you suggest. At

:

:
: > The other type botch is that there's no *typedef* or other way to
create
: > abstract numeric types (Integer etc. don't qualify). Sure you don't
need
: > typedef for objects, but numeric values belong to abstract types too.
How do
: > I convert my C arithmetic encoding routines, which have types like
: > ArithEncoderVal, FreqVal, and AEOverFreqVal, which help me keep these
all
: > straight?

:
: Well, I have to admit to missing this use of typedef. But again, I'm


: getting by without it. Besides, in C/C++, you could have:
:
: typedef int ArithEncoderVal;
: typedef int FreqVal;
:
: FreqVal x = 1;
: ArithEncoderVal y = x;
:
: without ever hearing a peep from the compiler, so it really only amounted
: to inline documentation to use the typedef names except when you wanted
to
: change the actual underlying type. Given that Java has defined the sizes
: of the underlying types (what a concept!), this probably isn't as big of
: an issue anymore.

:

:
: > >This minimalist approach to
: > >language design is starting to grow on me. :)
: >
: > As Albert Einstein said, "Make it as simple as possible, *but no
simpler*".
:

: Well, quantum physics is probably a little less subjective than the issue

:

Doug Bell

unread,
Aug 27, 1996, 3:00:00 AM8/27/96
to

"Jonathan W. Locke" <jo...@sealevelsoftware.com> wrote:

> Doug Bell wrote:
>
> : I have yet to run into anything that can't be done with interfaces and/or


> : functors (function objects.) Have you?
> :
> : In fact, functors are considerably *more* powerful than method pointers.
>

> all right, you got me... please do explain what a functor object is! how
> will they help me to make a table driven event dispatcher? in particular,
> in my component's action() method, i get an Event. i want to look in a
> table until i find the right entry and then call whatever method is
> associated with that table entry. simple enough. but i don't see how it
> can be done... *sigh* perhaps the problem is the usual Java problem. if
> you can't do something, you probably are going about it all wrong... ;-)


Sure thing...just happen to have this handy from an earlier post I made on
this same issue. Here are examples of using interfaces and functors for
method dispatch:

--------------------------------------------------------------------

// Method one
// This uses a Hashtable to store the events to be dispatched,
// but certainly an array or any other data structure could be
// used for keeping track of the dispatch table. Also, this
// uses MyEvent objects to specify the event to be handled, but
// an int could be used as well, although the Hashtable handling
// would require use of Integer wrappers.

interface Dispatch {
void dispatch (); // or whatever method declaration you need
};

class FooEvents implements Dispatch {
// other class methods

public void dispatch () {
// code which handles event or dispatch function
}
}

class GooEvents implements Dispatch {
// other class methods

public void dispatch () {
// code which handles event or dispatch function
}
}

class FooSon extends FooEvents {
}

class MyEvent {
// any class which is used to uniquely specify which event to handle
}


class EventHandler {
java.util.Hashtable dispatchTable = new java.util.Hashtable();

public void addDispatch (Dispatch handler, MyEvent event) {
dispatchTable.put(event, handler);
}

boolean dispatch (MyEvent event) {
Dispatch d = (Dispatch)dispatchTable.get(event);
if (d == null)
return false; // event not handled
d.dispatch();
return true;
}
}

public class Example {
static void main (String args[]) {
EventHandler handler = new EventHandler();
FooEvents foo = new FooEvents();
GooEvents goo = new GooEvents();
FooSon son = new FooSon();
MyEvent evta = new MyEvent();
MyEvent evtb = new MyEvent();
MyEvent evtc = new MyEvent();

handler.addDispatch(foo, evta);
handler.addDispatch(goo, evtb);
handler.addDispatch(son, evtc);
handler.dispatch(evtb); // will cause goo.dispatch() to be called
handler.dispatch(evta); // will cause foo.dispatch() to be called
handler.dispatch(evtc); // will cause son.dispatch() to be called
handler.dispatch(new MyEvent()); // no event dispatch, returns false
}
}

--------------------------------------------------------------------

// Method two.
// Uses functors to implement method callbacks.
// Uses a Hashtable with Integer event references.

abstract class EventFunctor {
public abstract void dispatch ();
}

class FooFunctor extends EventFunctor {
private Foo foo;

FooFunctor (Foo foo) {
this.foo = foo;
}

public void dispatch () {
foo.doSomething();
}
}

class GooFunctor extends EventFunctor {
private Goo goo;
private int param;

GooFunctor (Goo goo, int param) {
this.goo = goo;
this.param = param;
}

public void dispatch () {
goo.doSomethingElse(param);
}
}

class Foo {
// other class methods

public void doSomething () {
// code which handles event or dispatch function
}
}

class Goo {
// other class methods

public void doSomethingElse (int param) {
// code which handles event or dispatch function
}
}


class EventHandler {
java.util.Hashtable dispatchTable = new java.util.Hashtable();

public void addDispatch (EventFunctor handler, int event) {
dispatchTable.put(new Integer(event), handler);
}

boolean dispatch (int event) {
EventFunctor f = (EventFunctor)dispatchTable.get(new Integer(event));
if (f == null)
return false; // event not handled
f.dispatch();
return true;
}
}

public class Example {
static void main (String args[]) {
EventHandler handler = new EventHandler();
Foo foo = new Foo();
Goo goo = new Goo();

handler.addDispatch(new FooFunctor(foo), 1);
handler.addDispatch(new GooFunctor(goo, 10), 2);
handler.dispatch(2); // will cause goo.dispatch(10) to be called
handler.dispatch(1); // will cause foo.dispatch() to be called
handler.dispatch(3); // will not dispatch event; will return false
}
}

--------------------------------------------------------------------


There are advantages and disadvantages to each of these approaches, and
which one to use is dependent on the particular situation. Overall, functors
offer more flexibility, but also a little more overhead and are sometimes less
convenient.

The advantages of functors are:
> functors can contain state information since they are objects
> the method invoked in the target object does not need to have any
particular name or fit any specific method signature due to
indirection
> functors are sometimes the only solution when interfacing to
classes which were written by others (e.g. the Java API classes.)
> multiple methods in the same object can be used as dispatch
functions
> functors can invoke class (static) methods

The advantages of interfaces are:
> conceptually simpler
> doesn't require definition of functor classes
> doesn't require instantiation of functor objects
> often all of the object to be dispatched have common functionality anyway,
and interfaces (or inheritance) leverages this naturally
> less runtime overhead

Usually, interfaces are used for callbacks because the object which will
be initiating the callback needs to accept a known type as a parameter, but
it is possible to combine interfaces and functors by having the functors
implement the callback interface.

So the choice is yours. Functors are really superior to method pointers,
since isolating a method independent of its object (or class) breaks the
object metaphor.

> : Occassionally this is annoying, but I'm rather glad to see it left out.

> : Interfaces are quite powerful, and when combined with static methods, you
> : can get default implementations with just a little extra work.
>

> right, but any time you add to your multiply inherited base class, you wind
> up changing N other classes just to delegate to the silly aggregate. what
> i'm saying is that all i want is the *syntactic* convenience. i don't care
> if it *works* like multiple inheritance! ie., couldn't they add
> "auto-aggregates" that automatically create delegation code in the
> containers they are aggregated in? seems to me you wouldn't have to change
> anything but the front end
> of the compiler to do this, and it would help save my hands. also the idea
> of objects that auto-aggregate themselves could be extended to allow
> auto-accessors to variables... ie., "auto String name" would mean "this is
> a string object and i also want the following code:"
>
> public void setName(String name)
> {
> this.name = name;
> }
>
> etc...
>
> of course you need some way of specifying whether the object should be
> referenced or cloned... but that seems to be a generic problem in java
> (some of that problem could be solved with const) it would be nice to be
> able to somehow tag and track deep and shallow copies...

I see what you're getting at here, and I admit to dealing with exactly the
same problem from time to time (that is, adding methods to an interface
and then having to go through all the implementors of the interface to add
shell methods to call my static default implementation.)

However, I would probably resist the addition to java of anything as
seemingly complicated as what you've described. I think the main issues
with multiple inheritance of implementation that make it a mess are the
issues with order of constructors, multiple inheritance of the same
classes through different inheritance chains, name-space collision (not
necessarily avoided with interfaces, but since you don't inherit an
implementation it doesn't present the same level of problem), and multiple
overshadowed variables with the same names from different hierarchies.
Interfaces are lightweight enough that most of these are not issues, and
functional enough to address most of what multiple inheritance gives you.
I wouldn't mind seeing a slightly heavier interface design, but am just as
happy not to have to deal with the types of "clever" designs that
C++-style MII brings.

> : > 3) overloaded return values. i really can't figure out why this one


> wasn't
> : > included...
> : > again, i'll just have to assume there was some principle at stake
> : > here... and the
> : > restriction could always be lifted...

> :
> : How would you resolve the case where the return value is ignored?

> Require
> : the result to be cast? This is just off the top of my head, and I'm sure
> : there are other ambiguous cases. If clean and unambiguous rules could be
> : worked out, this might be nice, but again, this isn't functionally
> : restrictive since you just have to use a different name for the method
> : (e.g. maxint(), maxdouble(), etc.)
>

> yes, but it gets annoying and some day it may *become* functionally
> restrictive if we, say, get the ability to invoke methods by name. you
> will then perhaps prefer "int max()" and "double max()" etc. the compiler
> should just complain anytime you do something ambiguous. i think if you
> write "int foo()" and "double foo()" that you should be required to say
> "(int)foo();" to call the method! if it hurts, "don't do that!".

Yes, but of course what about when you want to get a double foo() and cast
it to an int, and don't want an int foo(). It's confusing...

> : Interesting idea. Of course again this can be accomplished with Java,


> : just change the syntax a little to create the Object[] before the
> : function call. :)
>

> exactly! just change the front end of the compiler a little. of course
> there are frequently subtle difficult things that get overlooked in loose
> discussions like this...

Yes, but that's why they're so fun...we don't have to worry about
implementing what we dream up or fixing the problems we create. :) It's
always easier to be a film critic rather than a movie director.

Doug Bell
db...@shvn.com

Jim Balter

unread,
Aug 28, 1996, 3:00:00 AM8/28/96
to

In article <dbell-26089...@news3.cts.com>,

Doug Bell <db...@shvn.com> wrote:
>j...@netcom.com (Jim Balter) wrote:
>
>> Doug Bell <db...@shvn.com> wrote:
>> >But really, I can live without enums.
>>
>> You'll say otherwise when you encounter some obscure bug caused by two
>> "enumint"s having the same value. It's totally bizarre, in a language that
>> makes true and false unconvertible, to find that all enum values, which are
>> conceptually separate abstract instances of separate types, to be all mushed
>> together as ints. From the perspective of type safety and abstraction (not to
>> mention the manual labor involved), this is just plain WRONG.
>
>I don't see how enums are going to avoid the obscure bug you suggest. At
>least in C++, two or more enums in the same list can have the same value.
>In fact, this is frequently desired.

Please. There's a difference between the *possiblity* that something will
happen and the *likelihood* that something will happen. Equating two enums is
actually very rare, and is certainly bad practice. I'd be willing to
stipulate no aliasing; I'd even be willing to stipulate no integer assignment
at all; in fact, I prefer that they are a distinct abstract type, like
boolean, not just an alias for integers. Now do you get my point? (There's
something in philosophy called The Principle of Charity; always counter the
*strongest* case, even if your correspondent didn't make it). If I have
hundreds of items in an enum, perhaps in a lex routine, without any explicit
value assignment, some may come and go; getting an alias is quite possible
from pick/put errors; it isn't possible with abstract enum names. In
addition, making each enum an entirely separate type provides type safety (iy
is so *easy* to pass the wrong kind of "enumint" to a method, either the C
kind or the fake Java ones). This is *exactly* the same as what they did with
boolean. But I already alluded to that.

>As to the other issue, the added type safety and abstraction would be
>nice, but then I could probably list a lot of things that would be nice to
>have but aren't necessary. I think that by first stripping the language
>down to the minimum, rather than reflexively throwning in all those
>features from other languages, Java is off to a better start. If it's
>language features you want, then you'll probably be quite happy with Ada.

Abstract enums would be *consistent* with the Java philosophy, as would be
general abstract numeric types. Your argument is specious. I didn't complain
about the removal of the C++ kitchen sink, did I?

I would not be "quite happy with Ada", because Java the language is the
language component of Java the system, which is why I'm here in the Java
world. Progamming languages, including much better ones than Java, are a dime
a dozen. Java is widespread because of its *other* attributes, not because of
its quality as a language (just consider perl before it). As long as it is
where it is, it is worth considering its major flaws, especially those that are
inconsistencies.

>If you really want the type safety, then use Objects...that's what they're
>there for. For example:
>
>class MyEnum {
> public static final MyEnum One = new MyEnum();
> public static final MyEnum Two = new MyEnum();
> public static final MyEnum Three = new MyEnum();
>}
>
>Then you can use MyEnum for declaration, be guaranteed of type safety
>(even have hierarchical enums), get true abstraction and even get

>unconvertable values so they can't be mixed with ints. If you want to get


>a little fancier, have:
>
>class MyEnum {
> public static final MyEnum One = new MyEnum("One");
> public static final MyEnum Two = new MyEnum("Two");
> public static final MyEnum Three = new MyEnum("Three");
>
> public String toString () { return name; }
>
> private String name;
> private MyEnum (String name) { this.name = name; }
>}
>
>And the set of enums will be locked in so it will be entirely type safe.
>
>Sometimes it just takes a little thought to abandon ingrained ways...

I grant that this gets type safety, but it is a bit like going back to
assembler to do everything so low level. This sort of thing is going to
*drive* people to preprocessors; it's already happening. This is a great flaw
with overly simplified languages, is that they encourage the development of
dialects (rememer BASIC? Remember Pascal?). At least Ada has a law about
subsetting.

In addition, I'm a little concerned about the garbage collector dealing with all
these objects, but I suppose good garbage collectors age things; I'll admit that this is
"ingrained thinking" probably left over from my early days on IBM 1620's that
had 20000 digits of memory and could do a no-op in 160 usec. :-)

So anyway, we are on the same track, but I think it's a reasonable language
feature. To again point out the *inconsistency*, booleans were not done this
way. Why are they primitives instead of Objects? In fact, why isn't null an
Object, so you could do null.toString() instead of having to add static
toString() to libraries like everyone's doing?

>> The other type botch is that there's no *typedef* or other way to create
>> abstract numeric types (Integer etc. don't qualify). Sure you don't need
>> typedef for objects, but numeric values belong to abstract types too. How do
>> I convert my C arithmetic encoding routines, which have types like
>> ArithEncoderVal, FreqVal, and AEOverFreqVal, which help me keep these all
>> straight?
>
>Well, I have to admit to missing this use of typedef. But again, I'm
>getting by without it.

Yes, yes, we all *get by*. I used to get by with fanfold paper tape read at 10 bits/sec
and putting little bits of tape on it to make patches. *Getting by* isn't the point.
These are *engineering* issues.

>Besides, in C/C++, you could have:
>
>typedef int ArithEncoderVal;
>typedef int FreqVal;
>
>FreqVal x = 1;
>ArithEncoderVal y = x;
>
>without ever hearing a peep from the compiler, so it really only amounted
>to inline documentation to use the typedef names except when you wanted to
>change the actual underlying type.

This is totally specious. The fact that you *can* make an error with C
typedefs is totally beside the point that I can't use them *at all* in Java to
clarify my code. You say *only*, as if I shouldn't be allowed type
abstraction just because I can't have type safety! (It recall my mother not
allowing me to eat desert before I finished the steak, by which time I didn't
have room. :-) And changing underlying type is an important feature! In my
ArithEncoder routines, I have versions where the values in 16 bits, and I have
versions where the values fit in 32 bits. Without typedefs, macros, or
templates, what do I do? This is a fundamental failure in the language, as
far as I can see, without a fix like your Enum class.

>Given that Java has defined the sizes
>of the underlying types (what a concept!), this probably isn't as big of
>an issue anymore.

This is a *portability* issue; it has *nothing* to do with *abstraction*. You
keep mixing things up; data abstraction, type safety, and portability are all
*different* concepts, even if type names are used in all three cases.

And I'm not about to put all my ints into Objects (not even if I had operator
overloading, which I don't want, so don't throw C++ and Ada at me again).
Nor am I about to adopt Hungarian, which is totally the *opposite* of type
abstraction.

>> >This minimalist approach to
>> >language design is starting to grow on me. :)
>>
>> As Albert Einstein said, "Make it as simple as possible, *but no simpler*".
>
>Well, quantum physics is probably a little less subjective than the issue
>at hand.

He wasn't just talking about quantum physics. Sheesh.
--
<J Q B>


Jonathan W. Locke

unread,
Aug 28, 1996, 3:00:00 AM8/28/96
to

: I have yet to run into anything that can't be done with interfaces and/or
: functors (function objects.) Have you?
:
: In fact, functors are considerably *more* powerful than method pointers.

all right, you got me... please do explain what a functor object is! how
will they help me to make a table driven event dispatcher? in particular,
in my component's action() method, i get an Event. i want to look in a
table until i find the right entry and then call whatever method is
associated with that table entry. simple enough. but i don't see how it
can be done... *sigh* perhaps the problem is the usual Java problem. if
you can't do something, you probably are going about it all wrong... ;-)

: Occassionally this is annoying, but I'm rather glad to see it left out.

: Interfaces are quite powerful, and when combined with static methods, you
: can get default implementations with just a little extra work.

right, but any time you add to your multiply inherited base class, you wind
up changing N other classes just to delegate to the silly aggregate. what
i'm saying is that all i want is the *syntactic* convenience. i don't care
if it *works* like multiple inheritance! ie., couldn't they add
"auto-aggregates" that automatically create delegation code in the
containers they are aggregated in? seems to me you wouldn't have to change
anything but the front end
of the compiler to do this, and it would help save my hands. also the idea
of objects that auto-aggregate themselves could be extended to allow
auto-accessors to variables... ie., "auto String name" would mean "this is
a string object and i also want the following code:"

public void setName(String name)
{
this.name = name;
}

etc...

of course you need some way of specifying whether the object should be
referenced or cloned... but that seems to be a generic problem in java
(some of that problem could be solved with const) it would be nice to be
able to somehow tag and track deep and shallow copies...

: > 3) overloaded return values. i really can't figure out why this one


wasn't
: > included...
: > again, i'll just have to assume there was some principle at stake
: > here... and the
: > restriction could always be lifted...

:
: How would you resolve the case where the return value is ignored?
Require
: the result to be cast? This is just off the top of my head, and I'm sure
: there are other ambiguous cases. If clean and unambiguous rules could be
: worked out, this might be nice, but again, this isn't functionally
: restrictive since you just have to use a different name for the method
: (e.g. maxint(), maxdouble(), etc.)

yes, but it gets annoying and some day it may *become* functionally
restrictive if we, say, get the ability to invoke methods by name. you
will then perhaps prefer "int max()" and "double max()" etc. the compiler
should just complain anytime you do something ambiguous. i think if you
write "int foo()" and "double foo()" that you should be required to say
"(int)foo();" to call the method! if it hurts, "don't do that!".

: Interesting idea. Of course again this can be accomplished with Java,


: just change the syntax a little to create the Object[] before the
function
: call. :)

exactly! just change the front end of the compiler a little. of course
there are frequently subtle difficult things that get overlooked in loose
discussions like this...

cheers!

J

:
: Doug Bell
: db...@shvn.com
:

Jim Balter

unread,
Aug 28, 1996, 3:00:00 AM8/28/96
to

In article <01bb945c$abca8920$04111dcc@v-jonlop90>,

Jonathan W. Locke <jo...@sealevelsoftware.com> wrote:
>
>if you're really worried about repeating the same constant values, how
>about this?
>
>class Enum
>{
> private static int val = 0;
> static final int next()
> {
> return val++;
> }
>}
[etc.]

>so nice, i may even use it myself! ;-)

Yes, this sort of thing and Doug Bell's encapsulated version may make me
grumble a little less. :-) Now if you can come up with abstract
numeric types ....
--
<J Q B>


Jim Balter

unread,
Aug 28, 1996, 3:00:00 AM8/28/96
to

In article <01bb93db$505fd800$53101dcc@v-jonlop90>,

Jonathan W. Locke <jo...@sealevelsoftware.com> wrote:
>but as for the typedef argument, i find it ironic that you are essentially
>arguing
>that Java isn't OOP enough because it's going to force you to make a real
>object
>instead of aliasing the name of a basic type...

I can't treat numbers as real objects; even if it weren't for the efficiency
issue, there are no operators and no conversions .... All I want to do is
give *names* to numeric ranges. This really isn't much to ask, even from a
"web programming" language (the whole point here is that Java is a good
general purpose language and it should be usable in a wide variety of
domains).



>yet i do understand what
>you're getting
>at here... i also think it's possible that there were other issues to
>consider...
>obviously a great deal of care went into design of the bytecode verifier
>and a lot
>of that work had to do with type-safety. so perhaps they decided that
>typedef
>would complicate that more than it was really worth (although perhaps you
>could
>put that under the heading of 'fudging' as well...)

typedefs that aren't separate types are purely a syntactic issue, and have
nothing to do with bytecodes, so yes, you are definitely in deep chocolate
here. :-) Making numeric ranges really be distinct types looks nice at first
blush, but the problem of allowing conversions and tracking the resultant
types turns into full blown symbolic algebra. Perhaps there's something new
on this front from the type theory people, but that's really not what I'm
expecting. I'll give up on type safety with numbers because I must, but that
doesn't mean I should have to give up on type abstraction too.

>for my two cents, i very rarely seem to run into cases where i want to do
>operator overloading. what's more, i think it's nice to *always* know what
>'+' and '*'
>mean. so, simplicity may have been the design principle that got rid of
>typedefs
>and overloading...

I'm not asking for operator overloading. Really. Just type aliases. It's a
pure syntax issue, and I'm bound sooner or later to start running my Java code
through m4 or something (which will also allow me to comment out whole classes
and methods and the thousands of other *platform-independent* things that
large system developers do with preprocessing that isn't covered by the
if(false) hack in Java's flow analysis (if you don't know just what this hack
is, read the language spec; it's really quite amusing)). [Yes, yes, using
nested parentheses in English writing makes me out to be a geek for sure.]

>
>what i personally miss most from C++ are:
>
>1) method pointers (i constantly run into things i can't do without
>these... *sigh*)

You'll have to use functors instead.

> i've thought semi-seriously about things like dynamically generating
>classes in
> memory to get around this awful limitation. there must be something
>hard about
> making this fit into java because i can't imagine they didn't think
>about this one at all...

But Java doesn't have pointers at all, except for .... NullPointerException !!
Someone fell asleep on that one for sure; it should have been more like
NullReferenceException. What's in a name? Clean design ....

>2) multiple inheritance of *implementation* (i understand why they didn't
>put this in
> and i can live with that... for now...)

Trouble brewing there. Templates would help.

>3) overloaded return values. i really can't figure out why this one wasn't
>included...
> again, i'll just have to assume there was some principle at stake
>here... and the
> restriction could always be lifted...

Seems dangerous, but I dunno. I only been using this stuff for a couple of
weeks.

>4) oh darn... and variable arguments could have been *so very* pretty in
>java...

My fingers are breaking over all those "++""++""++""++""++++++
I'm gonna hafta break out the elisp manual and whip up a macro.

> (my syntax might be considered wacky by some, but you get the idea...)
> and with instanceof and all, sprintf could have been typechecked
>finally!

gcc typechecks sprintf diligently; in fact, there are *so many* restrictions
in Java that seem to be inspired by traditional errors in C, such as
if (i = 0) ...
that *never* bite someone using a good compiler that warns about these things.

> of course there are definitely deeper issues here too because basic
>types
> would have to be coerced to Objects to make it work... still this could
>be added
> without breaking anything (that i know of anyway...)!

They could be encapsulated in Integer etc. Variable arguments is a special
case, but it is a *deserving* special case, because it provides important
notational power that is otherwise lacking. I think the Java designers went
way overboard in preventing things that *could* be abused; making the language
verifiably safe is great; everything else is optional. As it is, people are
managing to write horrible Java code anyway, often *because* of the restrictions.

>of course there are lots of things from other languages i would have liked
>too,
>but i'd rather err on the side of simplicity than end up with unmanageable
>feature
>creep. give me 1, 3 and 4 and i'll be happy enough. i'd rather have
>someone
>smart think long and hard about 2 before deciding exactly how to add it!

Well, I think there is a tendency to be very insular, and compare everything
to C/C++ (like, you can't put enums into Java, because enums in C let you
assign arbitrary integers to the values). There other very clean language
designs out there, and if you want to look for what might have been left out
of Java, you may want to look there, not just at C++.
--
<J Q B>


Jim Balter

unread,
Aug 28, 1996, 3:00:00 AM8/28/96
to

In article <01bb9484$72923900$53111dcc@v-jonlop90>,

Jonathan W. Locke <jo...@sealevelsoftware.com> wrote:
>: I have yet to run into anything that can't be done with interfaces and/or
>: functors (function objects.) Have you?
>:
>: In fact, functors are considerably *more* powerful than method pointers.
>
>all right, you got me... please do explain what a functor object is! how
>will they help me to make a table driven event dispatcher? in particular,
>in my component's action() method, i get an Event. i want to look in a
>table until i find the right entry and then call whatever method is
>associated with that table entry. simple enough. but i don't see how it
>can be done... *sigh* perhaps the problem is the usual Java problem. if
>you can't do something, you probably are going about it all wrong... ;-)

Put each method into its own class, as the execute() method of that class.
Then just point your table entries to instances of those classes. If the
processing for some of the table entries is similar, you can use the same
class but encapsulate the parameters (which can be dynamic) in instance
variables. That's the "more powerful" part; of course, this is no different
from in C, where you would store a pointer to a structure that includes a
pointer to a function, instead of a pointer to the function directly.

>: Interesting idea. Of course again this can be accomplished with Java,
>: just change the syntax a little to create the Object[] before the
>function
>: call. :)
>
>exactly! just change the front end of the compiler a little. of course
>there are frequently subtle difficult things that get overlooked in loose
>discussions like this...

I think Doug meant to reorganize your code. Something like

{Object[] args = { "%d * %d = %d\n", new Integer(n), new Integer(m),
new Integer(m*n) };
printf(args);}

(The outer {} are so you can redeclare args in the next call.)

Not exactly elegant. I'm not sure that the language designers intended these
sorts of hacks and tricks as the (inevitable, I would say) consequence of the
sparsity of the language.
--
<J Q B>


Jim Balter

unread,
Aug 28, 1996, 3:00:00 AM8/28/96
to

In article <4vshbu$k...@zen.hursley.ibm.com>,

Mike Cowlishaw <m...@hursley.ibm.com> wrote:
>Always seemed to me that enums, being names, are best expressed as strings.
>If you're worried about space, use short names; if not, use good names.

Well, you can't switch on strings, but again that's a syntactic restriction.
With string constants being interned in Java, though, this is a pretty good
suggestion.

>Mike Cowlishaw, IBM Fellow

I seem to recall that's how it's done in REXX .... :-)


--
<J Q B>


Jonathan W. Locke

unread,
Aug 28, 1996, 3:00:00 AM8/28/96
to

<functor examples were here>

thanks. i had thought of the interface approach already. and while
functors are certainly a cool and interesting solution that i don't
currently have a problem for, both are really huge overkill for what i want
to do and i would argue that both approaches break encapsulation if the
whole point of dispatching is to call a method implemented in _this_.
specifically, in an AWT action() call, i'd like to be able to look through
a dispatch table and call the right onFooClicked() handler method. the
handler method *isn't* (and shouldn't be) associated with the Button, an
external dispatch class or anything else. it belongs in the container
class that holds the button. and there should be a programmatic way of
invoking one of these handlers. i still think i need method pointers. uh,
well... you might be able to get me to buy into some sort of argument about
nested classes... but that seems like overhead that's not needed.

: So the choice is yours. Functors are really superior to method pointers,


: since isolating a method independent of its object (or class) breaks the
: object metaphor.

: However, I would probably resist the addition to java of anything as


: seemingly complicated as what you've described. I think the main issues

i probably wouldn't want my implementation either... ;-) but something
*like* it would be good. i certainly agree about the auto-accessor part.
that was just brainstorming and i wouldn't want it unless it somehow fell
out of a more general solution found by pursuing the auto-aggregation idea.

: with multiple inheritance of implementation that make it a mess are the


: issues with order of constructors, multiple inheritance of the same
: classes through different inheritance chains, name-space collision (not
: necessarily avoided with interfaces, but since you don't inherit an
: implementation it doesn't present the same level of problem), and
multiple
: overshadowed variables with the same names from different hierarchies.
: Interfaces are lightweight enough that most of these are not issues, and
: functional enough to address most of what multiple inheritance gives you.

: I wouldn't mind seeing a slightly heavier interface design, but am just
as
: happy not to have to deal with the types of "clever" designs that
: C++-style MII brings.

again, "if it hurts... don't do that!" MI is something that is very often
not the right approach to a problem. but when it is, having single
inheritance is a major pain in the butt. in the rare instances where i
used MI in C++, i would go to a great deal of trouble to prefix my
inheritable names so they wouldn't be likely to conflict with anything that
wasn't essentially trying to do so!

btw, the auto-aggregation technique would solve the constructor order
problem and the variable inheritance problem. all that would be left is
ensuring that you pick reasonable method names... in fact you could think
of it as having the compiler do what you are doing by hand anyway!

: Yes, but that's why they're so fun...we don't have to worry about


: implementing what we dream up or fixing the problems we create. :) It's
: always easier to be a film critic rather than a movie director.

you hit the nail on the head there! life is a lot easier in the peanut
gallery!

J


Doug Bell

unread,
Aug 28, 1996, 3:00:00 AM8/28/96
to

j...@netcom.com (Jim Balter) wrote:

> Doug Bell <db...@shvn.com> wrote:
> >j...@netcom.com (Jim Balter) wrote:
> >
> >> Doug Bell <db...@shvn.com> wrote:
> >> >But really, I can live without enums.
> >>
> >> You'll say otherwise when you encounter some obscure bug caused by two
> >> "enumint"s having the same value. It's totally bizarre, in a language that
> >> makes true and false unconvertible, to find that all enum values, which are
> >> conceptually separate abstract instances of separate types, to be all
mushed
> >> together as ints. From the perspective of type safety and
abstraction (not to
> >> mention the manual labor involved), this is just plain WRONG.
> >
> >I don't see how enums are going to avoid the obscure bug you suggest. At
> >least in C++, two or more enums in the same list can have the same value.
> >In fact, this is frequently desired.
>
> Please. There's a difference between the *possiblity* that something will
> happen and the *likelihood* that something will happen. Equating two enums is
> actually very rare, and is certainly bad practice.

Well, I actually have seen enum used like

enum {
this,
that,
somethingelse,
max = somethingelse
}

quite frequently. Maybe you just haven't been using those same libraries.

Besides, my suggested solution eliminates the possibility of equivalence,
unless of course you want to add that capability by overriding
Object.equals() and Object.hashCode().


> I'd be willing to
> stipulate no aliasing; I'd even be willing to stipulate no integer assignment
> at all; in fact, I prefer that they are a distinct abstract type, like
> boolean, not just an alias for integers. Now do you get my point? (There's
> something in philosophy called The Principle of Charity; always counter the
> *strongest* case, even if your correspondent didn't make it).

I think I got your point clearly the first time. You apparently read my
entire post but chose not to respond to it as a whole or started
responding before finishing it. You're actually responding to a *weaker*
case than I made.


> If I have
> hundreds of items in an enum, perhaps in a lex routine, without any explicit
> value assignment, some may come and go; getting an alias is quite possible
> from pick/put errors; it isn't possible with abstract enum names. In
> addition, making each enum an entirely separate type provides type safety (iy
> is so *easy* to pass the wrong kind of "enumint" to a method, either the C
> kind or the fake Java ones). This is *exactly* the same as what they did with
> boolean. But I already alluded to that.

And I already addressed all these issues with my suggested solution, which
took about a minute to think of while I was responding to your post. My
whole point is that you can get all these features, and more, by building
your own enums in Java. The C/C++ enums are perhaps the less functional
as you can't really define your own behavior for them like defining
human-readable names for output.


> >As to the other issue, the added type safety and abstraction would be
> >nice, but then I could probably list a lot of things that would be nice to
> >have but aren't necessary. I think that by first stripping the language
> >down to the minimum, rather than reflexively throwning in all those
> >features from other languages, Java is off to a better start. If it's
> >language features you want, then you'll probably be quite happy with Ada.
>
> Abstract enums would be *consistent* with the Java philosophy, as would be
> general abstract numeric types. Your argument is specious. I didn't complain
> about the removal of the C++ kitchen sink, did I?

Not in this particular thread, but you seem to have covered a great deal
of it in other posts. I hope your problem with having conditional tests
actually require a *boolean* expression (what a concept!) is coming
along. :-)

I don't argue that abstract enums aren't consistent with Java, just unnecessary.

Why is this low-level?

You wanted a separate type, this is a separate type.

You wanted type safety, this is type safe (declare the class in the second
example as 'final', and there's no spoofing possible...there will only be
'null' or legal enum values which the compiler willl accept as MyEnum.)

You wanted types unconvertible to int, this is it. (If you want them
convertible to int, you can have that to.)

You wanted an abstraction, this is about as abstract as you're going to get.

It gives *far* more flexibility that the enums from C/C++.

If by "low-level" you mean that it requires more keystrokes, I'll agree.
I figure that's more an issue of getting a better editor than redesigning
the language. Put your macros in the editor, not the language.


> This sort of thing is going to
> *drive* people to preprocessors; it's already happening.

In the early days, people used to do all kinds of things with the C
preprocessor that are frowned upon these days. As the language evolved
and software development became a more sophisticated and structured
process, many of the shortcuts of the past were discarded in favor of
producing more reliable and maintainable code. Along the way, a lot of
extra keystrokes were required, yet we survived and I would even say,
prospered.

If people want to use preprocessers that output compilable Java code,
that's their choice. I don't see that as fundamentaly different than
using visual tools to build your Java program. Or are you going to argue
against that as well?


> This is a great flaw
> with overly simplified languages, is that they encourage the development of
> dialects (rememer BASIC? Remember Pascal?). At least Ada has a law about
> subsetting.

Yes, Java needs more laws. There is entirely too much illegal activity
going on out there experimenting with dangerous dialects. Should we focus
enforcement on the producers, distributers or the users? :-/


> In addition, I'm a little concerned about the garbage collector dealing
with all
> these objects, but I suppose good garbage collectors age things; I'll
admit that this is
> "ingrained thinking" probably left over from my early days on IBM 1620's that
> had 20000 digits of memory and could do a no-op in 160 usec. :-)
>
> So anyway, we are on the same track, but I think it's a reasonable language
> feature. To again point out the *inconsistency*, booleans were not done this
> way. Why are they primitives instead of Objects?

This is specious. (You seem to like that word, so I thought I ought to
throw in at least one usage of it. :)

Booleans have several operators specific to them. What operators, other
than ==, != and =, do you need for enums? Afterall, you wanted them to be
abstract. (And if you change your mind, you can have any operator you
want.)

Booleans have language constructs (if, for, do, while) specific to them.
What language constucts are specific to enums? (And if you say 'switch',
I'll tell you how to do that with my enum approach...but I'll leave it as
an exercise for the reader for now.)


> In fact, why isn't null an
> Object, so you could do null.toString() instead of having to add static
> toString() to libraries like everyone's doing?

There is some logic to making 'null' an Object. I imagine the arguments
against this were heavily weighted by the desire to catch undesireable
behavior rather than making it harder to detect. Plus, 'null' needs to be
type neutral, which I don't see how you get if you make it an Object.


> >> The other type botch is that there's no *typedef* or other way to create
> >> abstract numeric types (Integer etc. don't qualify). Sure you don't need
> >> typedef for objects, but numeric values belong to abstract types
too. How do
> >> I convert my C arithmetic encoding routines, which have types like
> >> ArithEncoderVal, FreqVal, and AEOverFreqVal, which help me keep these all
> >> straight?
> >
> >Well, I have to admit to missing this use of typedef. But again, I'm
> >getting by without it.
>
> Yes, yes, we all *get by*. I used to get by with fanfold paper tape
read at 10 bits/sec
> and putting little bits of tape on it to make patches. *Getting by*
isn't the point.
> These are *engineering* issues.
>
> >Besides, in C/C++, you could have:
> >
> >typedef int ArithEncoderVal;
> >typedef int FreqVal;
> >
> >FreqVal x = 1;
> >ArithEncoderVal y = x;
> >
> >without ever hearing a peep from the compiler, so it really only amounted
> >to inline documentation to use the typedef names except when you wanted to
> >change the actual underlying type.
>
> This is totally specious.

There you go with that word again. :)

> The fact that you *can* make an error with C
> typedefs is totally beside the point that I can't use them *at all* in Java to
> clarify my code. You say *only*, as if I shouldn't be allowed type
> abstraction just because I can't have type safety! (It recall my mother not
> allowing me to eat desert before I finished the steak, by which time I didn't
> have room. :-)

I say "only" to clarify exactly what it is that has been lost with the
removal of typedef. I already conceded the usefulness of abstraction for
fundamental data types.

> And changing underlying type is an important feature! In my
> ArithEncoder routines, I have versions where the values in 16 bits, and I have
> versions where the values fit in 32 bits. Without typedefs, macros, or
> templates, what do I do? This is a fundamental failure in the language, as
> far as I can see, without a fix like your Enum class.

Well, what you do is have separate subclasses, or overload methods within
the classes to deal with the different types of encoding. Recompiling the
same class with the same name and different data types probably isn't the
best design approach anyway. I know this isn't a satisfactory solution,
but changing the underlying data type is not really that common. (I say
this even though I've had to do it a number of times in C projects in the
past.)

Given what Java might have had to give up (no #includes, no predefined
types, automatic resolution of inter-dependencies by the compiler, ??) I'm
not sure I would trade that for typedefs. (I say might because I don't
really know, so be gentle with me. :) But, I agree this is useful, and I
don't have a "Java" work-around--at least not what I would consider a
reasonable one.


> >Given that Java has defined the sizes
> >of the underlying types (what a concept!), this probably isn't as big of
> >an issue anymore.
>
> This is a *portability* issue; it has *nothing* to do with *abstraction*. You
> keep mixing things up; data abstraction, type safety, and portability are all
> *different* concepts, even if type names are used in all three cases.

I know they're different concepts, but I was exercising "The Principle of
Charity" and responding to the other arguments you didn't make.


> And I'm not about to put all my ints into Objects (not even if I had operator
> overloading, which I don't want, so don't throw C++ and Ada at me again).
> Nor am I about to adopt Hungarian, which is totally the *opposite* of type
> abstraction.

Hey, we're making progress. You'll be singing the praises of Java yet. ;)


> >> >This minimalist approach to
> >> >language design is starting to grow on me. :)
> >>
> >> As Albert Einstein said, "Make it as simple as possible, *but no simpler*".
> >
> >Well, quantum physics is probably a little less subjective than the issue
> >at hand.
>
> He wasn't just talking about quantum physics. Sheesh.

I recognize the quote, but don't know the context and you didn't give one,
so I guessed it was related to his quest for a unified theory. A
unification theory would pretty much qualify as less subjective than this
issue. :)


If you spent the same effort applying yourself to how to do things in Java
as you do complaining about what it doesn't have from your favorite
languages, it would probably get you further. Then, when experience with
the language has distilled your list of desired features down to those you
find critically missing, you'll know where to spend your ammunition in
fighting for changes to the language. I'm just trying to point out some
alternatives.

BTW, the tone in your reply is more than a little arrogant. If you'd care
to have a civilized discussion that's fine, if not, I can find plenty of
others who do. (I couldn't think of a more diplomatic way to say this,
but I would have rather that I could have.)

Doug Bell
db...@shvn.com

Jonathan W. Locke

unread,
Aug 28, 1996, 3:00:00 AM8/28/96
to

i would prefer type safety in my enums. seems like a good approach would
be to use the Enum class i posted earlier that returns unique values in
conjunction with a subclass of Integer. it would guarantee uniqueness when
you wanted that and would have the added benefit of type safety.

J

Jim Balter <j...@netcom.com> wrote in article <jqbDwu...@netcom.com>...
: In article <4vshbu$k...@zen.hursley.ibm.com>,

:
:

Bill Wilkinson

unread,
Aug 28, 1996, 3:00:00 AM8/28/96
to Jonathan W. Locke

Jonathan W. Locke wrote:
>
> if you're really worried about repeating the same constant values, how
> about this?
>
> class Enum
> {
> private static int val = 0;
> static final int next()
> {
> return val++;
> }
> }
>
> class test
> {
>
> static final int VAL1 = Enum.next();
> static final int VAL2 = Enum.next();
>
> static public void main(String[] arg)
> {
> System.out.println("VAL1 = " + VAL1);
> System.out.println("VAL2 = " + VAL2);
> }
> }
>
> so nice, i may even use it myself! ;-)
> Well, this doesn't work so well if you are trying
to deliver a library. You would have to have
an "enum generator" unique to your library OR
everyone in the world has to agree to use the
same one. Not saying it's a bad idea, just
that it needs agreement among the participants.

I still think my scheme of simply using "weird"
constants is adequate and, because you can use
"switch" with it (unlike the ones based on
object addresses), can be quite fast.

In my "Database" class, for example, I have
defined


static final int ReadOnly = 0xACCE551;

static final int ReadWrite = 0xACCE552;
// cutesy: ACCE55 looks like "ACCESS"

and then you can call
Database DB = Database.open( "whatever",
Database.ReadWrite );

and my code can do
switch ( requested_access ) {
case ReadOnly:
... etc. ...

Jeremy Fitzhardinge

unread,
Sep 1, 1996, 3:00:00 AM9/1/96
to Jim Balter

In article <jqbDwq...@netcom.com>,
j...@netcom.com (Jim Balter) writes:
> In article <dbell-22089...@news3.cts.com>,

> Doug Bell <db...@shvn.com> wrote:
>>But really, I can live without enums.
>
> You'll say otherwise when you encounter some obscure bug caused by two
> "enumint"s having the same value. It's totally bizarre, in a language that
> makes true and false unconvertible, to find that all enum values, which are
> conceptually separate abstract instances of separate types, to be all mushed
> together as ints. From the perspective of type safety and abstraction (not to
> mention the manual labor involved), this is just plain WRONG.

It's actually worse than that. The Java->bytecode compiler has a
tendency to inline all constants into the classes which use them. This
means that if you have a class with named constants as part of its
interface, the compiler will inline those constants into the classes
which use the interface.

While the existance of the constants is part of the interface, their
actual values are part of the implementation. If I change something in
the class which changes the constants, all the classes which use it
need to be recompiled, since they depend on part of the
implementation.

If I develop a class using someone else's class, I can't tell what
exact version of the class I'll meet "out there" in someone's browser.
While Java is pretty good at defining interfaces in a way that allows
them to be verified at bind time, it really fails with named
constants.

Enums shouldn't even be viewed as "constants". They're just tags, and
they should always be refered to symbolically. At bind time, the
runtime can decide how to implement them and how to make sure everyone
sees a consistent view. Different enums should be distinct in a
type-safe way, and there certainly shouldn't be any of C's "an enum is
really an integer" laxity.

J

0 new messages