Class Constants - pros and cons

M

Magnus Warker

Hi,

in the past I used to declare my constants as this, e. g. the colors of a
chess board:

public static int COL_WHITE = 1;
public static int COL_BLACK = 2;

Now, I find class constants very useful:

public final class Color
{
public static final Color WHITE = new Color();
public static final Color BLACK = new Color();
....
}

The major advantage for me is that I can use the constants over the classes
name, e. g. Color.WHITE.

However, I found that I lose the ability to evaluate these constants in
switch statements:

switch(color)
{
case Color.WHITE:
...

Instead, I have to use cascading if-statements:

if (color==Color.WHITE)
{
}
else
if (color==Color.WHITE)
{
}
else
...

This is a major drawback in my opinion.

Have I missed something? How do you do that?

Thanks
Magnus
 
L

Lew

Magnus said:
in the past I used to declare my constants as this, e. g. the colors of a
chess board:

public static int COL_WHITE = 1;
public static int COL_BLACK = 2;

Those should have been 'final'.
Now, I find class constants very useful:

public final class Color
{
public static final Color WHITE = new Color();
public static final Color BLACK = new Color();
...
}

The major advantage for me is that I can use the constants over the classes
name, e. g. Color.WHITE.

Strictly speaking, in Java terms those aren't "constants" but "final
variables". To be "constants", they'd have to be initialized with a
compile-time constant expression, per
<http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#10931>
and
However, I found that I lose the ability to evaluate these constants in
switch statements:

switch(color)
{
case Color.WHITE:
...

Instead, I have to use cascading if-statements:

if (color==Color.WHITE)
{
}
else
if (color==Color.WHITE)
{
}
else
...

This is a major drawback in my opinion.

Have I missed something? How do you do that?

Make 'Color' an enum.
 
M

Magnus Warker

It's the readibility of the code.

With constant classes I can write something like this:

public void setColor (Color color)
{
if (color == Color.WHITE)
...
}

This is not possible with enums, since an enume type must be defined in a
class:

public void setColor (SomeClass.Color color)
{
if (color == SomeClass.Color.WHITE)
...
}

I think, it would be ok, if I needed the enum only in SomeClass.

But what about constants that are needed in many classes?

I saw that constant classes are used widely in the java api, e. g.
java.awt.PageAttributes.MediaType. But I also saw constants declared as
final ints anyway.

Thanks
Magnus
 
A

Alan Gutierrez

Magnus said:
This is not possible with enums, since an enume type must be defined in a
class:

Someone is about to pop in and give you chapter and verse of JLS that
tells you that's not so, but I'll just tell you that's not so.
 
J

Jean-Baptiste Nizet

Magnus Warker a écrit :
It's the readibility of the code.

With constant classes I can write something like this:

public void setColor (Color color)
{
if (color == Color.WHITE)
...
}

This is not possible with enums, since an enume type must be defined in a
class:

public void setColor (SomeClass.Color color)
{
if (color == SomeClass.Color.WHITE)
...
}

No. Read more about enums. Enums are classes, and can be top-level
classes. You define them, as regular classes, in their own .java file :

// Color.java
package com.foo.bar;

public enum Color {
WHITE,
BLACK;
}

// SomeClass.java
public void setColor(Color color) {
this.color = color;
if (color == Color.WHITE) {
// ...
}
switch (color) {
case WHITE :
// ...
}
}
I think, it would be ok, if I needed the enum only in SomeClass.

But what about constants that are needed in many classes?

You define them in their own .java file
I saw that constant classes are used widely in the java api, e. g.
java.awt.PageAttributes.MediaType. But I also saw constants declared as
final ints anyway.

Yes, because enums only appeared in Java 5, and lots of classes had
already been written before that, and thus used final ints or Strings
instead.
 
L

Lew

Magnus Warker a écrit :

Don't top-post!

No. That would be a bug. You'd write 'if ( color.equals( Color.WHITE ) )'.

And how is that less readable? Besides, it's wrong. 'Color' would *be* the
enum, so you'd still have 'Color.WHITE', unless 'Color' were a nested class,
but then it would be in the constant String scenario, too.

Further besides, with an enum you wouldn't say
if ( color.equals( Color.WHITE ))
{
foo( something );
}
or
if ( color == Color.WHITE )
{
foo( something );
}
you'd say
color.foo( something );

Jean-Baptiste Nizet said:
No. Read more about enums. Enums are classes, and can be top-level
classes. You define them, as regular classes, in their own .java file :

// Color.java
package com.foo.bar;

public enum Color {
WHITE,
BLACK;
}

// SomeClass.java
public void setColor(Color color) {
this.color = color;
if (color == Color.WHITE) {
// ...
}
switch (color) {
case WHITE :
// ...
}
}

Magnus Warker a écrit :
??

Have them refer to the enum.

Jean-Baptiste Nizet said:
You define them in their own .java file

Magnus Warker a écrit :
Jean-Baptiste Nizet said:
Yes, because enums only appeared in Java 5, and lots of classes had
already been written before that, and thus used final ints or Strings
instead.

That would still be helpful.

ints and Strings are not typesafe. enums are. Use enums.

If you expect a constant String 'GlueConstants.CHOIX' equal to "foobar" and
pass 'ShoeConstants.CHOIX' equal to "fubar" instead, the compiler won't
complain. If you pass the wrong enum it will.

Since enums are classes, they can contain behavior. That means you won't need
if-chains nor case constructs to select behavior; just invoke the method
directly from the enum constant itself and voilà!
 
J

Joshua Cranmer

No. That would be a bug. You'd write 'if ( color.equals( Color.WHITE ) )'.

To be pedantic, it would not be a bug if the Color class were written in
a certain way, i.e., there is no other Color instances other than those
in Color's static instance variables.
 
L

Lew

Joshua said:
To be pedantic, it would not be a bug if the Color class were written in
a certain way, i.e., there is no other Color instances other than those
in Color's static instance variables.

You are wrong, this once. (In your case, an extremely rare occurrence.)

It's impossible to enforce that for all clients 'color' is assigned the exact
instance, therefore that == will work if the static variables are Strings.
It's all too easy to accidentally push in a different constant String from
some other class, as outlined in my other response, or by other means to
create a different instance of a String that you intend even with the correct
value. So yes, to be pedantic, using == would be a bug waiting to happen, as
would using String constants when enum constants are so much safer (and
guaranteed to work with == ).
 
T

Tom Anderson

You are wrong, this once. (In your case, an extremely rare occurrence.)

It's impossible to enforce that for all clients 'color' is assigned the
exact instance, therefore that == will work if the static variables are
Strings. It's all too easy to accidentally push in a different constant
String from some other class, as outlined in my other response, or by
other means to create a different instance of a String that you intend
even with the correct value. So yes, to be pedantic, using == would be
a bug waiting to happen, as would using String constants when enum
constants are so much safer (and guaranteed to work with == ).

I won't argue with you about Strings.

But Joshua was talking about using instances of Color, where those
instances are singletons (well, flyweights is probably the right term when
there are several of them), exposed in static final fields on Color, and
the class is written in a certain way, which i take to mean having a
private constructor, not creating any instances other than those in the
statics, and implementing readResolve. In that case, how can there be
pairs of instances for which .equals is true and == isn't? Colour doesn't
make such instances, no other class can make such instances directly,
serialization won't, and sun.misc.Unsafe is a foul.

Indeed, this is exactly what enums do, so why do you think classes can't?

tom
 
L

Lew

Tom said:
I won't argue with you about Strings.

But Joshua was talking about using instances of Color, where those
instances are singletons (well, flyweights is probably the right term
when there are several of them), exposed in static final fields on
Color, and the class is written in a certain way, which i take to mean
having a private constructor, not creating any instances other than
those in the statics, and implementing readResolve. In that case, how
can there be pairs of instances for which .equals is true and == isn't?
Colour doesn't make such instances, no other class can make such
instances directly, serialization won't, and sun.misc.Unsafe is a foul.

Indeed, this is exactly what enums do, so why do you think classes can't?

We're talking apples and oranges here. I made a mistake and it's my fault. I
was focused on String constants and should not have used 'Color' instances as
an example, but 'Foo'. In my mind I had conflated the examples and was
imagining a fictitious 'Color' class with Strings not 'Color' instances, and
that was where I went wrong.

You and Joshua are, of course, correct.
 
T

Tom McGlynn

....
But Joshua was talking about using instances of Color, where those
instances are singletons (well, flyweights is probably the right term when
there are several of them), exposed in static final fields on Color, and
....
While I agree with Tom's main point here,I am dubious about his
suggestion for what the static instances should be called
in a class that only creates a unique closed set of such instances.

I don't think flyweights is the right word. For me flyweights
are classes where part of the state is externalized for some
purpose. This is orthogonal to the concept of singletons.
E.g., suppose I were running a simulation of galaxy mergers
of two 100-million-star galaxies. Stars differ only in position,
velocity and mass. Rather than creating 200 million Star objects
I might create a combination flyweight/singleton Star where each
method call includes an index that is used to find the mutable
state in a few external arrays. At least in some versions of Java this
could be a very useful optimization since we only need to create
of order 10 objects rather than 10^8.

So is there a better word than flyweights for the extension of a
singleton
to a set with cardinality > 1?


Tom McGlynn
 
L

Lew

Tom said:
E.g., suppose I were running a simulation of galaxy mergers
of two 100-million-star galaxies.  Stars differ only in position,
velocity and mass.  Rather than creating 200 million Star objects
I might create a combination flyweight/singleton Star where each
method call includes an index that is used to find the mutable
state in a few external arrays. At least in some versions of Java this
could be a very useful optimization since we only need to create
of order 10 objects rather than 10^8.

Except that that "mutable state in a few external arrays" still has to
maintain state for order 10^8 objects, coordinating position, velocity
(relative to ...?) and mass. So you really aren't reducing very much,
except simplicity in the programming model and protection against
error.
 
A

Andreas Leitgeb

Lew said:
Except that that "mutable state in a few external arrays" still has to
maintain state for order 10^8 objects, coordinating position, velocity
(relative to ...?) and mass. So you really aren't reducing very much,
except simplicity in the programming model and protection against
error.

About 2.4GB are not much?
(200 mill * (8bytes plain Object + 4bytes for some ref to each))

Of course that needs to be taken in relation to the perhaps 8GB of RAM
still needed for the 5 doubles per star: about 33% of payload would be
"packaging" costs with a separate instance for each star!

I for myself might choose the perhaps less cpu-efficient (due to all
the repeated indexing and for the defied locality) and also less simple
programming model, if it allowed me to solve larger problems with the
available RAM.

PS: Without further tricks, each single simulation-step would probably
take much too long, anyway, if for each star its interaction with each
other star needs to be calculated... But then it was only thought-
experiment, in the first place ("... suppose I were running ...")
 
T

Tom Anderson

While I agree with Tom's main point here,I am dubious about his
suggestion for what the static instances should be called in a class
that only creates a unique closed set of such instances.

I don't think flyweights is the right word. For me flyweights are
classes where part of the state is externalized for some purpose. This
is orthogonal to the concept of singletons. E.g., suppose I were running
a simulation of galaxy mergers of two 100-million-star galaxies. Stars
differ only in position, velocity and mass. Rather than creating 200
million Star objects I might create a combination flyweight/singleton
Star where each method call includes an index that is used to find the
mutable state in a few external arrays.

I am 90% sure that is absolutely not how 'flyweight' is defined in the
Gang of Four book, from which its use in the programming vernacular
derives. If you want to use a different definition, then that's fine, but
you are of course wrong.
So is there a better word than flyweights for the extension of a
singleton to a set with cardinality > 1?

Multipleton.

More seriously, enumeration.

tom
 
T

Tom Anderson

We're talking apples and oranges here. I made a mistake and it's my
fault. I was focused on String constants and should not have used
'Color' instances as an example, but 'Foo'. In my mind I had conflated
the examples and was imagining a fictitious 'Color' class with Strings
not 'Color' instances, and that was where I went wrong.

Ah, i thought it was probably something like that.

tom
 
L

Lew

Andreas said:
About 2.4GB are not much?
 (200 mill * (8bytes plain Object + 4bytes for some ref to each))

No, it isn't. Around USD 75 worth of RAM.
Of course that needs to be taken in relation to the perhaps 8GB of RAM
still needed for the 5 doubles per star: about 33% of payload would be
"packaging" costs with a separate instance for each star!

I for myself might choose the perhaps less cpu-efficient (due to all
the repeated indexing and for the defied locality) and also less simple
programming model, if it allowed me to solve larger problems with the
available RAM.

With that much data to manage, I'd go with the straightforward object
model and a database or the $75 worth of RAM chips. Or both.

Complicated code is more expensive than memory.

And what about when the model changes, and you want to track star age,
brightness, color, classification, planets, name, temperature,
galactic quadrant, ...? With parallel arrays the complexity and risk
of bugs just goes up and up. With an object model, the overhead of
maintaining that model becomes less and less significant, but the
complexity holds roughly steady.

Saving a single memory-stick's worth of RAM is a false economy.
 
A

Andreas Leitgeb

Lew said:
No, it isn't. Around USD 75 worth of RAM.

Except, if the machine is already RAM-stuffed to its limits...

Even if the machine wasn't yet fully RAM'ed, then buying more RAM
*and* using the arrays-kludge(yes, that's it, afterall) would allow
even larger galaxies to be simulated.
With that much data to manage, I'd go with the straightforward object
model and a database or the $75 worth of RAM chips. Or both.

On some deeper level, a relational DB seems to actually use the "separate
arrays" approach, too. Otherwise I cannot explain the relatively low cost
of adding another column to a table of 100 million entries already in it.
And what about when the model changes, and you want to track star age,
brightness, color, classification, planets, name, temperature,
galactic quadrant, ...? With parallel arrays the complexity and risk
of bugs just goes up and up. With an object model, the overhead of
maintaining that model becomes less and less significant, but the
complexity holds roughly steady.

100% agree to these points.

It's like fixing something with duct-tape. The result looks not very
good, but it may last for a particular use, that otherwise would have
required a redesign from scratch and possibly costly further ressources.
(changing object to separate arrays *may* still be less cost&effort than
switching to some database)

If, collisions and break-ups of stars were also simulated (thus a varying
number of them), then, suddenly, duct-tape won't fix it anymore, anyway...
 
L

Lew

Andreas said:
On some deeper level, a relational DB seems to actually use the "separate
arrays" approach, too. Otherwise I cannot explain the relatively low cost
of adding another column to a table of 100 million entries already in it.

There's a big difference between a database with tens of thousands, maybe far
more manhours of theory, development, testing, user feedback, optimization
efforts, commercial competition and evolution behind it, and an ad-hoc use of
in-memory arrays by a solo programmer.

A database system is far, far more than a simple "separate arrays" approach.
There are B[+]-trees, caches, indexes, search algorithms, stored procedures,
etc., etc., etc. Your comment is like saying that "on some deeper level" a
steel-and-glass skyscraper is like the treehouse you built for your kid in the
back yard.
 
T

Tom McGlynn

I am 90% sure that is absolutely not how 'flyweight' is defined in the
Gang of Four book, from which its use in the programming vernacular
derives. If you want to use a different definition, then that's fine, but
you are of course wrong.


Multipleton.

More seriously, enumeration.


Thanks Tom for responding to my real question about the vocabularly
rather than the example. That was just intended to clarify a
distinction between a singleton and my idea of a flyweight.

Here's a bit of what the GOF has to say about flyweights. (Page 196
in my version)....


"A flyweight is a shared object that can be used in multiple contexts
simultaneously. The flyweight acts as an independent object in each
context--it's indistinguishable from an instance of the object that's
not shared.... The key concept here is the distinction between
intrinsic and extrinsic state. Intrinsic state is stored in the
flyweight. It consists of information that's independent of the
flyweight's context, thereby making it shareable. Extrinsic state
depends on and varies with the flyweights context and therefore can't
be shared. Client objects are responsible for passing extrinsic state
to the flyweight when it needs it."

That's reasonably close to what I had in mind. In my simple example
stars may share some common state (e.g., age), but the information
about the position and velocity is extrinsic and supplied when the
object is used. In a more realistic example I might have multiple
flyweights for different types of stars.

Getting back to my original concern, I don't think enumeration is a
good word for the concept either. Enumerations are often used for an
implementation of the basis set -- favored in Java by special syntax.
However the word enumeration strongly suggests a list. In general
the set of special values may have a non-list relationship (e.g., they
could form a hierarchy). I like the phrase 'basis set' I used above
but that suggests that other elements can be generated by combining
the elements of the basis so it's not really appropriate either.

Regards,
Tom McGlynn
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,905
Latest member
Kristy_Poole

Latest Threads

Top