dev@glassfish.java.net

Re: should constants be used in a modularized system?

From: Kedar Mhaswade <Kedar.Mhaswade_at_Sun.COM>
Date: Fri, 21 Mar 2008 06:21:57 -0700

Ken Paulsen wrote:
>
> Lloyd, Bill and others:
>
> To make sure I understand correctly, let me see if I can repeat back
> what you're saying...
>
> If you define a constant (public static final), for example:
>
> public static final String C = "hello";
>
> ...then another class references that code, it will be contained in
> bytecode (i.e. it won't look at the orginal C). In other words, if you
> change "hello" to "goodbye" w/o recompiling all classes using C, you'll
> still have "hello" in those classes that weren't recompiled.
>
> However... if you define your "constant" like this:
>
> private static String getC() { return "hello" }
> public static final String C = getC();
>
> Or even:
>
> public static final String C;
> static { C = "hello"; }
>
> Then code refering to "C" *WILL* refer back to the class instead of
> keeping it local via bytecode. This is arguably not a constant now
> (although public static final, it cannot be "inlined" by other .class
> code). In other words, if you change "hello" to "goodbye" and ONLY
> compile the class which defines C, it will still be seen in ALL classes
> referencing C (i.e. no more "hello" anywhere).
>
> Is that right? And if so, what is your recommendation or design pattern
> that we should follow? It was not clear (to me) from the email
> exchange. Which if these should be preferred:
>
> * Enum
> * "public static final" initialized via a static method
> * "public static final" initialized via a static block (probably the
> same thing to the JVM??)
> * No "public static final" use static getter method instead
> * or ??
>
> Thanks for bringing this up... this is one of those little things that
> could cause big problems. :)
>

I agree. This relates to the binary compatibility of classes and how
constant a defined constant really is. Static constants defined in a
module's classes have to be exported with care. Enums hardly help here because
enum constants can be modified without clients needing recompilation!

But I am yet to understand why this is a problem in modular system in
particular. I mean constants being changed (?) in this manner is a problem
anyway. It may be the case that a modular system is more vulnerable
to these changes. The example that you cite is an extreme one because
"hello" changing to "goodbye" is similar to changing a method x() to
do something different in another version of the same class.

I prefer not to rely on the constants unless they are the public interface
of a module.

If the goal of a module is to always expose its latest state in terms
of constants interface it exports, the public static final String XYZ =
get("xyz"); kind of declaration should be preferred. But it should be
noted however that there is no relaxation of the rule in this case. The
module must not change in an incompatible manner.

Unfortunately, the "value" of a constant variable is its only interface!

- Kedar

> Ken
>
> Lloyd L Chambers wrote:
>> Bill,
>>
>> Agreed...though problem with enums for management (JMX) include:
>>
>> - they require a new class that might not be available on a client
>> (across "the wire")
>> - they might not map automatically to other non-Java protocols
>>
>> At least that's my understanding.
>>
>> So for values returned across the wire through a management interface,
>> enums are an issue. A good example of this is
>> java.util.logging.Level; I ran into this problem recently working with
>> a developer on a JMX adapter.
>>
>> Lloyd
>>
>> On Mar 20, 2008, at 2:31 PM, Bill Shannon wrote:
>>> Lloyd L Chambers wrote:
>>>> In Glassfish V3 the system is highly modularized. Compiling one
>>>> module against another might mean using static constants eg:
>>>> // module B using org.glassfish.foo.bar from another module A
>>>> import org.glassfish.foo.bar.CONSTANT1;
>>>> ...
>>>> doSomething( CONSTANT1 );
>>>> ...
>>>> If I understand correctly, java constants are compiled into the
>>>> resulting bytecode.
>>>> So if the constant is later changed in the defining module, code
>>>> compiled against that module does *not* pick up the new value unless
>>>> it is recompiled.
>>>> In short, in a modular system, should constant values be fixed at
>>>> compile time, or picked up dynamically at runtime? If they are to
>>>> be dynamic, then our constants need to be written as methods eg:
>>>> public static String getCONSTANT1();
>>>> *not*
>>>> public static final String CONSTANT1 = "val"
>>>> Of course, there might not be a hard and fast rule. But if a module
>>>> is newly-built and has new values for its constants, it might be
>>>> reasonable to expect dependent modules to use the new values.
>>>
>>> Yes, we should all understand this. Primitives and String constants
>>> are stored by *value*, not name. Once you choose a value for one of
>>> these constants in a public API (across module boundaries), you're
>>> committing to it, no matter what name you might use.
>>>
>>> Many of these constants should probably be enums, which don't have this
>>> problem.
>>>
>>> String constants should really only be used for things that are
>>> externally
>>> defined and really won't change. Otherwise, if it can change, it's not
>>> really a constant! :-)
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe_at_glassfish.dev.java.net
>>> For additional commands, e-mail: dev-help_at_glassfish.dev.java.net
>>>
>>
>> ---
>> Lloyd L Chambers
>> lloyd.chambers_at_sun.com
>> Sun Microsystems, Inc
>>
>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_glassfish.dev.java.net
>> For additional commands, e-mail: dev-help_at_glassfish.dev.java.net
>>