borrowing Constants

R

Roedy Green

If you have some code like this:

class A
{
static String VERSION = "1.0b";
}

and
class B
{
static String VERSION = A.VERSION;
}

When you use Class B, does all of class A get instantiated?
Does all of class A get put in B's jar?


If so, it suggests you are better off to have a tiny common class and
have A and B reference it.
--
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.
 
A

Arne Vajhøj

If you have some code like this:

class A
{
static String VERSION = "1.0b";
}

and
class B
{
static String VERSION = A.VERSION;
}

When you use Class B, does all of class A get instantiated?

I don't think it can just initialize what is needed.

The overhead must be microscopic anyway.
Does all of class A get put in B's jar?

That depends on the one doing the "putting".
If so, it suggests you are better off to have a tiny common class and
have A and B reference it.

You should stick to good design and keep the versions where they
logical belong.

Arne
 
A

Arved Sandstrom

I don't think it can just initialize what is needed.

The overhead must be microscopic anyway.


That depends on the one doing the "putting".


You should stick to good design and keep the versions where they
logical belong.

Arne
Which logical place is not in the code at all. Granted, I don't know
that Roedy's example is doing anything more than using "VERSION" as a
generic variable name (I hope).

I'm not going to be unyielding on this, but I have personally never
encountered or read of any situation where source code needed to be
annotated with configuration or version control information. This
includes the RCS-style keywords; the argument is that these help if a
file is exported outside the development environment, but that's not a
compelling argument for me.

AHS
 
E

Eric Sosman

If you have some code like this:

class A
{
static String VERSION = "1.0b";
}

and
class B
{
static String VERSION = A.VERSION;
}

When you use Class B, does all of class A get instantiated?

"Instantiated" seems like the wrong word here; there's no
`new' or clone() or deserialization, so no "instantiation" in
the way the word is ordinarily used.

Class A certainly gets looked up, and loaded, and byte-code
verified, and initialized, and so on (my own grasp of all the
steps in preparing a class is rather feeble; I've only needed to
go into detail once, and that rather shallowly). But it's clear
that A must be "prepared" at least as far as running its static
initializers; otherwise, its VERSION would not have a value for
class B to copy. The `final' modifier might or might not make
a difference (that's where my grasp starts to slip).
Does all of class A get put in B's jar?

Who builds the jar?
If so, it suggests you are better off to have a tiny common class and
have A and B reference it.

Possibly, if you think that initializing a "tiny" class is
significantly cheaper than initializing class A. In the example
shown, it doesn't seem likely that a class "tinier" than A could
be of much use. And even if A were considerably bigger, how many
times do you expect to initialize B? (That's not a purely rhetorical
question: Try to estimate an actual number.)

Still, for something like VERSION it seems pretty weird for
class B to declare "My version is, is, well, it's whatever A says.
Although my source code hasn't been touched in three years, A's
never-ending churn of changes somehow makes me different. Or, A
is the placid one that's remained untouched for three years, while
I've changed so much that not a single original source line remains
(even the "class B" line has gained an "implements") -- no matter: A
hasn't changed, so neither have I." Neither stance seems to make
much sense, so you might want to refactor this on design grounds.
 
R

Roedy Green

Which logical place is not in the code at all. Granted, I don't know
that Roedy's example is doing anything more than using "VERSION" as a
generic variable name (I hope).

I chose it as an easy-to-understand example. In my example, VERSION
is something you might display in a an About box.

The question is really about accidentally dragging in some giant class
when you had no intention of using its code.
--
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.
 
R

Roedy Green

"Instantiated" seems like the wrong word here; there's no
`new' or clone() or deserialization, so no "instantiation" in
the way the word is ordinarily used.

At the JVM level there is. When you first use a class, e.g. reference
a static variable of that class or invoke a static method, a class
object is allocated for that class (1 per class per classloader). This
has nothing to do with instatiating new objects of that class.

Since this is not something that normally concerns application
programmers, I don't know if there is official terminology for it.

--
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.
 
M

markspace

When you use Class B, does all of class A get instantiated?
Does all of class A get put in B's jar?


I think so, yes. Not "instantiated" as others pointed out but
initialized. But yes, regardless.

I believe you can get around this by making VERSION final. The compiler
is allowed (possibly required?) to copy final static values as a kind of
constant, in order to avoid this kind of unneeded initialization.

class A
{
static final String VERSION = "1.0b";
}
 
L

Lew

Roedy said:
If you have some code like this:

class A
{
static String VERSION = "1.0b";
}

and
class B
{
static String VERSION = A.VERSION;
}

When you use Class B, does all of class A get instantiated?

Strictly speaking, and I am fairly sure you don't mean this, a class with only static members might never, or cannot ever be instantiated (depending on the use of certain idioms).

As you know, I favor exactitude, some think colo-rectitude in certain terminologies. It cuts both ways - I have to relearn terms when I have them wrong.

That aside, you no doubt refer to the evil twin processes of class loading and class initialization.

Without going all lawyerly, let's just note that there is a precise order of those stages and rather ornate rules to them.

Which all boil down to that you get a class all or nothing.

So yes, you will need the entire class in both the build and runtime paths of its clients.
Does all of class A get put in B's jar?

Short answer: Yes, it would have to. Classes are loaded in what the Java Language Specification (JLS) calls "compilation units". For this question, the key word is "unit".

Under certain circumstances you get more than one class at a time from the same compilation unit. These come all or nothing all together or not at all.
If so, it suggests you are better off to have a tiny common class and
have A and B reference it.

That's debatable for certain scenarios, but yes, absolutely it would suggest that otherwise.

The niggle is that such a rule shouldn't be too restrictive. Placement of members flows from architecture and design. You get a few utility classes, sure, but don't overdo it. Things belong where they belong.
 
A

Arne Vajhøj

The question is really about accidentally dragging in some giant class
when you had no intention of using its code.

Can you provide an example where it is even measurable to load a
single class (with only simple initialization of fields)?

Arne
 
L

Lew

markspace said:
I think so, yes. Not "instantiated" as others pointed out but
initialized. But yes, regardless.

I believe you can get around this by making VERSION final. The compiler
is allowed (possibly required?) to copy final static values as a kind of
constant, in order to avoid this kind of unneeded initialization.

class A
{
static final String VERSION = "1.0b";
}

You are correct. That has an interesting side effect on builds. Clients of class 'A', above:

class B
{
static final String FOO_VERSION = "Foo-" + A.VERSION;
}

can use the compile-time constant (there are rules for that) to build its own compile-time constant.

But B's view of 'A.VERSION' doesn't necessarily change when 'A' changes it.Constants are baked into the class file, so until 'B' recompiles, it willload the old version of 'A.VERSION' at runtime. Other classes in the application might see the change at different builds, depending on when they were last recompiled and which copies of which ".class" files were in the waywhen they compiled.

One can be surprised by this behavior. Cargo cults preach "rebuild the world" as the only true preventative. For any reasonably-organized project it's good advice.
 
L

Lew

Lew said:
Strictly speaking, and I am fairly sure you don't mean this, a class withonly static members might never, or cannot ever be instantiated (dependingon the use of certain idioms).

As you know, I favor exactitude, some think colo-rectitude in certain terminologies.
It cuts both ways - I have to relearn terms when I have them wrong.

For example, Roedy correctly points out that classes do have a class objectthat instantiates when they load.

There are two main stages to the usefulness of a type at runtime. One is load, the other initialize. They're like two steps in each class's private Big Bang of creation.

A class loads among other things upon reference to that class's instance variable, pointed to by the 'class' attribute. Under that particular circumstance it does not also initialize. That happens under non-pathological references to classes, such as access to behaviors or contents through their members. ('class' is not a member.) 'final' fields, especially 'static' ones, most especially compile-time constant variables, get special treatment in the initialization.

I'll stop now.
 
A

Arne Vajhøj

Which logical place is not in the code at all. Granted, I don't know
that Roedy's example is doing anything more than using "VERSION" as a
generic variable name (I hope).

I'm not going to be unyielding on this, but I have personally never
encountered or read of any situation where source code needed to be
annotated with configuration or version control information. This
includes the RCS-style keywords; the argument is that these help if a
file is exported outside the development environment, but that's not a
compelling argument for me.

A version number hardcoded in source code will at some point in time
get out of synch with the actual version number.

Arne
 
A

Arne Vajhøj

I think so, yes. Not "instantiated" as others pointed out but
initialized. But yes, regardless.

I believe you can get around this by making VERSION final. The compiler
is allowed (possibly required?) to copy final static values as a kind of
constant, in order to avoid this kind of unneeded initialization.

class A
{
static final String VERSION = "1.0b";
}

But that introduces the risk of B not being updated when
A is updated.

Arne
 
V

Volker Borchert

Roedy said:
If you have some code like this:

class A
{
static String VERSION = "1.0b";
}

and
class B
{
static String VERSION = A.VERSION;
}

When you use Class B, does all of class A get instantiated?
Does all of class A get put in B's jar?

If they're Constants, they should be final, and then the compiler
would "inline" the string into B's constant pool.
 
R

Roedy Green

class A
{
static String VERSION = "1.0b";
}

and
class B
{
static String VERSION = A.VERSION;
}

if I change that to
class A
{
static final String VERSION = "1.0b";
}

and
class B
{
static final String VERSION = A.VERSION;
}

I understand from Lew that effectively decouples the classes. A will
not necessarily appear in B's jar. A will not be loaded when B is
initialised.


--
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.
 
R

Roedy Green

class A
{
static String VERSION = "1.0b";
}

and
class B
{
static String VERSION = A.VERSION;
}

restating, if the expression for A.VERSION cannot be evaluated an
compile time, even final won't rescue you from having to include both
A in your jar and indirectly loading A when you load B.

So the rule of thumb use static final with values known at compile
time to avoid needless class loading. But be aware, you must recompile
B if the value of A.VERSION changes, or you will get the old value.

Another rule of thumb may be, instead of cross linking classes with
references to each others constants, refactor out the constants to a
third class, and reference it or extend it.

In a number of my projects I have a Config class where everything
constant (possibly computed) needed to configure a program for a
particular use are collected.
--
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.
 
E

Eric Sosman

restating, if the expression for A.VERSION cannot be evaluated an
compile time, even final won't rescue you from having to include both
A in your jar and indirectly loading A when you load B.

You keep harping on whether A is or is not present in "B's
jar." That depends on the jar packer, not on A and B.

Put it this way: Do you think java.lang.String appears in
"B's jar?"
 
M

markspace

Another rule of thumb may be, instead of cross linking classes with
references to each others constants, refactor out the constants to a
third class, and reference it


Generally, no. It's been tried, and found to not work well. A class
full of unrelated constants is just that: a class full of unrelated
constants. Put the constants where they belong. Use a decent build
system capable of figuring out what needs to be compiled.

or extend it.


Dear god no. Known bad practice. Avoid!
 
D

Daniel Pitts

I chose it as an easy-to-understand example. In my example, VERSION
is something you might display in a an About box.

The question is really about accidentally dragging in some giant class
when you had no intention of using its code.

If you are using a field from it, you *are* using its code.

Imagine the following scenario:

public class MyConstants {
public static final String VERSION;
public static final int ZERO;
static {
ZERO = 0;
VERSION = SomeOtherClass.calculateVersionNumber();
}
}

public class UsesOtherClass {
public static final VERSION = MyConstants.VERSION;
}

When UsesOtherClass is initialized, it requires MyConstants *and*
SomeOtherClass to be initialized.

In general, if you use some code, you are transiently using its
dependencies as well.

Although, I thought I read somewhere that constants can sometimes be
inlined (which can lead to other surprising behaviors if you recompile
only some of your classes on make).
 
L

Lew

If you are using a field from it, you *are* using its code.

Imagine the following scenario:

public class MyConstants {
public static final String VERSION;
public static final int ZERO;
static {
ZERO = 0;

Compile-time constant.
VERSION = SomeOtherClass.calculateVersionNumber();

Not a compile-time constant.

They are treated differently.
}
}

public class UsesOtherClass {
public static final VERSION = MyConstants.VERSION;
}

When UsesOtherClass is initialized, it requires MyConstants *and*
SomeOtherClass to be initialized.

But it compiles the compile-time constant in at compile time (hence the name, "compile-time" constant - amazing connection, eh?), so it doesn't need the source class at run time for that constant.
In general, if you use some code, you are transiently using its
dependencies as well.

The exception being compile-time constants.
Although, I thought I read somewhere that constants can sometimes be
inlined (which can lead to other surprising behaviors if you recompile
only some of your classes on make).

More precisely, it's *compile-time* constants that get special treatment. People bandy about the term "constant" very carelessly.

Compile-time constants are bound in at compile time (the logic is compelling) as as literals. The surprising behaviors come at runtime from version mismatches and from the fact that transitive class dependencies are hidden by the compile-time constants having been bound at compile time.
 

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

Similar Threads

constructing a constant HashMap 19
Java control panel anomaly 2
code generation for the ternary operator 33
in praise of type checking 33
New Java releases 1.6.0_29 and 1.7.0_01 3
@see scope 6
Ubunto 74
Where am I? 10

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top