borrowing Constants

Discussion in 'Java' started by Roedy Green, Sep 24, 2011.

  1. Roedy Green

    Roedy Green Guest

    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.
     
    Roedy Green, Sep 24, 2011
    #1
    1. Advertising

  2. Roedy Green

    Arne Vajhøj Guest

    On 9/23/2011 8:40 PM, Roedy Green wrote:
    > 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
     
    Arne Vajhøj, Sep 24, 2011
    #2
    1. Advertising

  3. On 11-09-23 09:44 PM, Arne Vajhøj wrote:
    > On 9/23/2011 8:40 PM, Roedy Green wrote:
    >> 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
    >

    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

    --
    Romper, bomper, stomper boo. Tell me, tell me, tell me, do. Magic
    Mirror, tell me today, have all my friends had fun at play?
     
    Arved Sandstrom, Sep 24, 2011
    #3
  4. Roedy Green

    Eric Sosman Guest

    On 9/23/2011 8:40 PM, Roedy Green wrote:
    > 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.

    --
    Eric Sosman
    d
     
    Eric Sosman, Sep 24, 2011
    #4
  5. Roedy Green

    Roedy Green Guest

    On Fri, 23 Sep 2011 22:10:28 -0300, Arved Sandstrom
    <> wrote, quoted or indirectly quoted
    someone who said :

    >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.
     
    Roedy Green, Sep 24, 2011
    #5
  6. Roedy Green

    Roedy Green Guest

    On Fri, 23 Sep 2011 21:15:20 -0400, Eric Sosman
    <> wrote, quoted or indirectly quoted
    someone who said :

    > "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.
     
    Roedy Green, Sep 24, 2011
    #6
  7. Roedy Green

    markspace Guest

    On 9/23/2011 5:40 PM, Roedy Green wrote:

    > 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";
    }
     
    markspace, Sep 24, 2011
    #7
  8. Roedy Green

    Lew Guest

    Roedy Green wrote:
    > 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.

    --
    Lew
     
    Lew, Sep 24, 2011
    #8
  9. Roedy Green

    Arne Vajhøj Guest

    On 9/23/2011 9:39 PM, Roedy Green wrote:
    > 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
     
    Arne Vajhøj, Sep 24, 2011
    #9
  10. Roedy Green

    Lew Guest

    markspace wrote:
    > Roedy Green wrote:
    >> 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";
    > }


    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.

    --
    Lew
     
    Lew, Sep 24, 2011
    #10
  11. Roedy Green

    Lew Guest

    Lew wrote:
    > Roedy Green wrote:
    >> 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 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.

    --
    Lew
     
    Lew, Sep 24, 2011
    #11
  12. Roedy Green

    Arne Vajhøj Guest

    On 9/23/2011 9:10 PM, Arved Sandstrom wrote:
    > On 11-09-23 09:44 PM, Arne Vajhøj wrote:
    >> On 9/23/2011 8:40 PM, Roedy Green wrote:
    >>> 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.


    > 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
     
    Arne Vajhøj, Sep 24, 2011
    #12
  13. Roedy Green

    Arne Vajhøj Guest

    On 9/23/2011 9:44 PM, markspace wrote:
    > On 9/23/2011 5:40 PM, Roedy Green wrote:
    >> 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";
    > }


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

    Arne
     
    Arne Vajhøj, Sep 24, 2011
    #13
  14. Roedy Green wrote:
    > 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.

    --

    "I'm a doctor, not a mechanic." Dr Leonard McCoy <>
    "I'm a mechanic, not a doctor." Volker Borchert <>
     
    Volker Borchert, Sep 24, 2011
    #14
  15. Roedy Green

    Roedy Green Guest

    On Fri, 23 Sep 2011 17:40:20 -0700, Roedy Green
    <> wrote, quoted or indirectly quoted
    someone who said :

    >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.
     
    Roedy Green, Sep 24, 2011
    #15
  16. Roedy Green

    Roedy Green Guest

    On Fri, 23 Sep 2011 17:40:20 -0700, Roedy Green
    <> wrote, quoted or indirectly quoted
    someone who said :

    >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.
     
    Roedy Green, Sep 25, 2011
    #16
  17. Roedy Green

    Eric Sosman Guest

    On 9/24/2011 8:09 PM, Roedy Green wrote:
    > On Fri, 23 Sep 2011 17:40:20 -0700, Roedy Green
    > <> wrote, quoted or indirectly quoted
    > someone who said :
    >
    >> 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.


    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?"

    --
    Eric Sosman
    d
     
    Eric Sosman, Sep 25, 2011
    #17
  18. Roedy Green

    markspace Guest

    On 9/24/2011 5:09 PM, Roedy Green wrote:
    > 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!
     
    markspace, Sep 25, 2011
    #18
  19. Roedy Green

    Daniel Pitts Guest

    On 9/23/11 6:39 PM, Roedy Green wrote:
    > On Fri, 23 Sep 2011 22:10:28 -0300, Arved Sandstrom
    > <> wrote, quoted or indirectly quoted
    > someone who said :
    >
    >> 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.


    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).
     
    Daniel Pitts, Sep 25, 2011
    #19
  20. Roedy Green

    Lew Guest

    On Sunday, September 25, 2011 11:25:49 AM UTC-7, Daniel Pitts wrote:
    > Roedy Green wrote:
    >> 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;


    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.

    --
    Lew
     
    Lew, Sep 25, 2011
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Benjamin Todd

    constants declaration

    Benjamin Todd, Feb 12, 2004, in forum: VHDL
    Replies:
    2
    Views:
    6,148
    Benjamin Todd
    Feb 15, 2004
  2. whizkid

    TIME borrowing in synthesis

    whizkid, Nov 2, 2004, in forum: VHDL
    Replies:
    1
    Views:
    6,505
    Tom Verbeure
    Nov 2, 2004
  3. Replies:
    86
    Views:
    1,473
    Dave Thompson
    Feb 28, 2005
  4. Masood

    Making C better (by borrowing from C++)

    Masood, Dec 23, 2007, in forum: C Programming
    Replies:
    247
    Views:
    3,122
    David Thompson
    Jan 14, 2008
  5. Novice

    "Borrowing" code

    Novice, Feb 16, 2012, in forum: Java
    Replies:
    60
    Views:
    1,127
    Novice
    Feb 20, 2012
Loading...

Share This Page