Will two symbols with the same name clash?

Discussion in 'C++' started by DeMarcus, Apr 23, 2010.

  1. DeMarcus

    DeMarcus Guest

    Hi,

    Will two symbols with the same name but in different .cpp files clash?
    E.g.

    file1.cpp

    int varA;


    file2.cpp

    int varA;


    Will varA clash during linking? Of course I can test it myself, but is
    there a possibility that they are allowed to clash but the compiler
    chooses one of them?

    Sometimes I've seen compiler messages like: "multiple definitions of X,
    ignoring the latter".


    Thanks,
    Daniel
     
    DeMarcus, Apr 23, 2010
    #1
    1. Advertising

  2. DeMarcus

    DeMarcus Guest

    DeMarcus wrote:
    > Hi,
    >
    > Will two symbols with the same name but in different .cpp files clash?
    > E.g.
    >
    > file1.cpp
    >
    > int varA;
    >
    >
    > file2.cpp
    >
    > int varA;
    >
    >
    > Will varA clash during linking? Of course I can test it myself, but is
    > there a possibility that they are allowed to clash but the compiler
    > chooses one of them?
    >
    > Sometimes I've seen compiler messages like: "multiple definitions of X,
    > ignoring the latter".
    >
    >
    > Thanks,
    > Daniel


    Wait, I just came to think of that I have to declare them static!
    I.e.

    file1.cpp

    static int varA;

    file2.cpp

    static int varA;


    It was a long time since I used that. ;)
     
    DeMarcus, Apr 23, 2010
    #2
    1. Advertising

  3. * DeMarcus:
    > Hi,
    >
    > Will two symbols with the same name but in different .cpp files clash?


    Depends what you mean by "clash".

    If the symbols have extern linkage then C++ generally does not support that.
    It's called the "ODR", "One Definition Rule". But a linker may not necessarily
    detect the clash -- e.g. 'int a[5]' one place and 'int* a' another place.

    There are some execptions, where you are allowed multiple definitions of extern
    linkage things.

    The most important is "inline" routines.

    A similar exception is there for static lifetime data in templates.


    > E.g.
    >
    > file1.cpp
    >
    > int varA;
    >
    >
    > file2.cpp
    >
    > int varA;
    >
    >
    > Will varA clash during linking?


    Depends on the linker.

    But the code above is not well-defined C++.


    > Of course I can test it myself, but is
    > there a possibility that they are allowed to clash but the compiler
    > chooses one of them?


    No, not with the example above.

    You can do that via the exception for templates mentioned above.

    E.g., in each compilation unit, ...

    template< class Dummy >
    struct Var_ { static int a; };

    template< class Dummy >
    int Var_<Dummy>::a = 0;

    typedef Var_<void> Var;

    .... then use 'Var::a'.


    > Sometimes I've seen compiler messages like: "multiple definitions of X,
    > ignoring the latter".


    That sounds like you're in violation of C++ rules.


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Apr 23, 2010
    #3
  4. DeMarcus

    DeMarcus Guest

    >>
    >> file1.cpp
    >>
    >> int varA;
    >>
    >>
    >> file2.cpp
    >>
    >> int varA;
    >>
    >>
    >> Will varA clash during linking?

    >
    > Depends on the linker.
    >
    > But the code above is not well-defined C++.
    >
    >


    If I define the variables like this

    file1.cpp
    static int varA;

    file2.cpp
    static int varA;

    Am I allowed to send either varA pointer to other places in the application?
     
    DeMarcus, Apr 23, 2010
    #4
  5. DeMarcus <> writes:

    > DeMarcus wrote:
    >> Hi,
    >>
    >> Will two symbols with the same name but in different .cpp files clash?
    >> E.g.
    >>
    >> file1.cpp
    >>
    >> int varA;
    >>
    >>
    >> file2.cpp
    >>
    >> int varA;
    >>
    >>
    >> Will varA clash during linking? Of course I can test it myself, but
    >> is there a possibility that they are allowed to clash but the
    >> compiler chooses one of them?
    >>
    >> Sometimes I've seen compiler messages like: "multiple definitions of
    >> X, ignoring the latter".
    >>
    >>
    >> Thanks,
    >> Daniel

    >
    > Wait, I just came to think of that I have to declare them static!
    > I.e.
    >
    > file1.cpp
    >
    > static int varA;
    >
    > file2.cpp
    >
    > static int varA;
    >
    >
    > It was a long time since I used that. ;)


    This particular use of the static keyword is deprecated in C++, IIRC.
    To ensure that your two variables are not visible outside the
    translation unit they are required in, use un-named namespaces:

    // file1.cpp

    namespace {
    int varA;
    }


    // file2.cpp
    namespace {
    int varA;
    }

    Regards

    Paul Bibbings
     
    Paul Bibbings, Apr 23, 2010
    #5
  6. DeMarcus <> writes:

    >
    > If I define the variables like this
    >
    > file1.cpp
    > static int varA;
    >
    > file2.cpp
    > static int varA;
    >
    > Am I allowed to send either varA pointer to other places in the
    > application?


    Are you able to say a little more about what you are trying to achieve?
    With the little information we have, it strikes me, at least, as a
    little convoluted. Your question began with name clashing, then sought
    a method to make your same-named variables TU-local, and now you are
    asking how you can refer to these same-named variables outside of the TU
    they're defined in.

    Questions to be asked include, in the first instance, "Why are your
    variables named the same?" "What application-wide visibility do you want
    for these variables?" Then you might want to ask yourself to what
    extent your answers to these questions conflict.

    Regards

    Paul Bibbings
     
    Paul Bibbings, Apr 23, 2010
    #6
  7. * DeMarcus:
    >>>
    >>> file1.cpp
    >>>
    >>> int varA;
    >>>
    >>>
    >>> file2.cpp
    >>>
    >>> int varA;
    >>>
    >>>
    >>> Will varA clash during linking?

    >>
    >> Depends on the linker.
    >>
    >> But the code above is not well-defined C++.
    >>
    >>

    >
    > If I define the variables like this
    >
    > file1.cpp
    > static int varA;
    >
    > file2.cpp
    > static int varA;
    >
    > Am I allowed to send either varA pointer to other places in the
    > application?


    Yes, but keep in mind that here they're two distinct variables.


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Apr 23, 2010
    #7
  8. DeMarcus

    DeMarcus Guest

    Paul Bibbings wrote:
    > DeMarcus <> writes:
    >
    >> If I define the variables like this
    >>
    >> file1.cpp
    >> static int varA;
    >>
    >> file2.cpp
    >> static int varA;
    >>
    >> Am I allowed to send either varA pointer to other places in the
    >> application?

    >
    > Are you able to say a little more about what you are trying to achieve?
    > With the little information we have, it strikes me, at least, as a
    > little convoluted. Your question began with name clashing, then sought
    > a method to make your same-named variables TU-local, and now you are
    > asking how you can refer to these same-named variables outside of the TU
    > they're defined in.
    >
    > Questions to be asked include, in the first instance, "Why are your
    > variables named the same?" "What application-wide visibility do you want
    > for these variables?" Then you might want to ask yourself to what
    > extent your answers to these questions conflict.
    >


    I want to achieve the following.

    file_class.cpp
    const MessageClass ERROR( "Could not find file" );

    class FileClass
    {
    public:
    FileClass()
    {
    GlobalRegister::register( &ERROR );
    }

    void open( string s )
    {
    if( /* Error when opening file */ )
    std::cerr << ERROR << std::endl;
    }
    };

    calculation_class.cpp
    const MessageClass ERROR( "Could not calculate" );

    class CalculationClass
    {
    public:
    CalculationClass()
    {
    GlobalRegister::register( &ERROR );
    }

    void calculate()
    {
    if( /* Error during calculation */ )
    std::cerr << ERROR << std::endl;
    }
    };


    I want to allow any file be able to use the symbol ERROR but at the same
    time they shall be able to register the pointer to that variable without
    clashing with other variables with the same symbol name.
     
    DeMarcus, Apr 23, 2010
    #8
  9. DeMarcus

    DeMarcus Guest

    Paul Bibbings wrote:
    > DeMarcus <> writes:
    >
    >> DeMarcus wrote:
    >>> Hi,
    >>>
    >>> Will two symbols with the same name but in different .cpp files clash?
    >>> E.g.
    >>>
    >>> file1.cpp
    >>>
    >>> int varA;
    >>>
    >>>
    >>> file2.cpp
    >>>
    >>> int varA;
    >>>
    >>>
    >>> Will varA clash during linking? Of course I can test it myself, but
    >>> is there a possibility that they are allowed to clash but the
    >>> compiler chooses one of them?
    >>>
    >>> Sometimes I've seen compiler messages like: "multiple definitions of
    >>> X, ignoring the latter".
    >>>
    >>>
    >>> Thanks,
    >>> Daniel

    >> Wait, I just came to think of that I have to declare them static!
    >> I.e.
    >>
    >> file1.cpp
    >>
    >> static int varA;
    >>
    >> file2.cpp
    >>
    >> static int varA;
    >>
    >>
    >> It was a long time since I used that. ;)

    >
    > This particular use of the static keyword is deprecated in C++, IIRC.
    > To ensure that your two variables are not visible outside the
    > translation unit they are required in, use un-named namespaces:
    >
    > // file1.cpp
    >
    > namespace {
    > int varA;
    > }
    >
    >
    > // file2.cpp
    > namespace {
    > int varA;
    > }
    >
    > Regards
    >
    > Paul Bibbings


    Thanks!!!
     
    DeMarcus, Apr 23, 2010
    #9
  10. DeMarcus

    DeMarcus Guest

    Victor Bazarov wrote:
    > DeMarcus wrote:
    >> Paul Bibbings wrote:
    >>> DeMarcus <> writes:
    >>>
    >>>> If I define the variables like this
    >>>>
    >>>> file1.cpp
    >>>> static int varA;
    >>>>
    >>>> file2.cpp
    >>>> static int varA;
    >>>>
    >>>> Am I allowed to send either varA pointer to other places in the
    >>>> application?
    >>>
    >>> Are you able to say a little more about what you are trying to achieve?
    >>> With the little information we have, it strikes me, at least, as a
    >>> little convoluted. Your question began with name clashing, then sought
    >>> a method to make your same-named variables TU-local, and now you are
    >>> asking how you can refer to these same-named variables outside of the TU
    >>> they're defined in.
    >>>
    >>> Questions to be asked include, in the first instance, "Why are your
    >>> variables named the same?" "What application-wide visibility do you want
    >>> for these variables?" Then you might want to ask yourself to what
    >>> extent your answers to these questions conflict.
    >>>

    >>
    >> I want to achieve the following.
    >>
    >> file_class.cpp
    >> const MessageClass ERROR( "Could not find file" );
    >>
    >> class FileClass
    >> {
    >> public:
    >> FileClass()
    >> {
    >> GlobalRegister::register( &ERROR );

    >
    > What does that do?
    >


    It registers the ERROR MessageClass to a global register that keeps
    track of all messages to give them correct language.

    Actually the MessageClass looks more like this.

    const MessageClass ERROR( "Could_not_find_file_id" );

    where ERROR when used picks up correct language string.

    >> }
    >>
    >> void open( string s )
    >> {
    >> if( /* Error when opening file */ )
    >> std::cerr << ERROR << std::endl;
    >> }
    >> };
    >>
    >> calculation_class.cpp
    >> const MessageClass ERROR( "Could not calculate" );
    >>
    >> class CalculationClass
    >> {
    >> public:
    >> CalculationClass()
    >> {
    >> GlobalRegister::register( &ERROR );

    >
    > What does that do?
    >
    >> }
    >>
    >> void calculate()
    >> {
    >> if( /* Error during calculation */ )
    >> std::cerr << ERROR << std::endl;
    >> }
    >> };
    >>
    >>
    >> I want to allow any file be able to use the symbol ERROR but at the
    >> same time they shall be able to register the pointer to that variable

    >
    > Why? What for?
    >
    > > without
    >> clashing with other variables with the same symbol name.

    >
    > What does registering have to do with compilation? Are you confusing
    > run-time behavior (of your system) with the behavior of the compiler
    > (who determines and reports "name clashes")?
    >


    I want to be able to use the same symbols (here symbol ERROR) in
    different places. The symbols then may clash in link-time (unless I put
    them in different namespaces as suggested), however, each and every
    MessageClass are registered in a global register where the language can
    be changed.
     
    DeMarcus, Apr 23, 2010
    #10
  11. DeMarcus

    DeMarcus Guest

    Victor Bazarov wrote:
    > DeMarcus wrote:
    >> Victor Bazarov wrote:
    >>> DeMarcus wrote:
    >>>> Paul Bibbings wrote:
    >>>>> DeMarcus <> writes:
    >>>>>
    >>>>>> If I define the variables like this
    >>>>>>
    >>>>>> file1.cpp
    >>>>>> static int varA;
    >>>>>>
    >>>>>> file2.cpp
    >>>>>> static int varA;
    >>>>>>
    >>>>>> Am I allowed to send either varA pointer to other places in the
    >>>>>> application?
    >>>>>
    >>>>> Are you able to say a little more about what you are trying to
    >>>>> achieve?
    >>>>> With the little information we have, it strikes me, at least, as a
    >>>>> little convoluted. Your question began with name clashing, then
    >>>>> sought
    >>>>> a method to make your same-named variables TU-local, and now you are
    >>>>> asking how you can refer to these same-named variables outside of
    >>>>> the TU
    >>>>> they're defined in.
    >>>>>
    >>>>> Questions to be asked include, in the first instance, "Why are your
    >>>>> variables named the same?" "What application-wide visibility do you
    >>>>> want
    >>>>> for these variables?" Then you might want to ask yourself to what
    >>>>> extent your answers to these questions conflict.
    >>>>>
    >>>>
    >>>> I want to achieve the following.
    >>>>
    >>>> file_class.cpp
    >>>> const MessageClass ERROR( "Could not find file" );
    >>>>
    >>>> class FileClass
    >>>> {
    >>>> public:
    >>>> FileClass()
    >>>> {
    >>>> GlobalRegister::register( &ERROR );
    >>>
    >>> What does that do?
    >>>

    >>
    >> It registers the ERROR MessageClass to a global register that keeps
    >> track of all messages to give them correct language.

    >
    > I suppose it pre-loads the translations from some repository (like
    > Resources on Windows), am I close?
    >


    Yes, all IDs are language-configured in text files.

    >>
    >> Actually the MessageClass looks more like this.
    >>
    >> const MessageClass ERROR( "Could_not_find_file_id" );
    >>
    >> where ERROR when used picks up correct language string.

    >
    > OK, so the registration part of your system only cares about the *value*
    > of the string, not the actual address. Does it store a copy of it? Or
    > do you make your registration store the address of 'ERROR'? Not that
    > it's important, really... It should work either way.
    >
    > My question was mostly to ensure that your 'register' does not try to
    > use the name of the variable ("ERROR") in any way. Of course, the use
    > of '&' is somewhat hinting that 'register' doesn't care about the
    > variable linked to the object whose address you're passing to it...
    >


    Well, the MessageClass has some functions like
    const std::string& getID() const;
    const std::string& getDefaultMessage() const;

    One call to the global register could be:

    globalRegister.printAllIDs();

    That should be ok, right?

    >>
    >>>> }
    >>>> [...]
    >>>>
    >>>> I want to allow any file be able to use the symbol ERROR but at the
    >>>> same time they shall be able to register the pointer to that variable
    >>>
    >>> Why? What for?
    >>>
    >>> > without
    >>>> clashing with other variables with the same symbol name.
    >>>
    >>> What does registering have to do with compilation? Are you confusing
    >>> run-time behavior (of your system) with the behavior of the compiler
    >>> (who determines and reports "name clashes")?
    >>>

    >>
    >> I want to be able to use the same symbols (here symbol ERROR) in
    >> different places.

    >
    > OK. Judging from the code you posted so far, there should be no
    > problem. Of course, you (hopefully) already found that if you make the
    > object 'const' you don't have that problem because a const object has
    > internal linkage by default. If you don't declare your object 'const',
    > it has external linkage, and without 'static' (which forces internal
    > linkage) or placing it in an unnamed namespace (which changes the name
    > of the var so it becomes inaccessible from other TUs) you will get
    > problems with the linker.
    >


    Aha, does this mean that as long as I declare them const, I don't need
    the unnamed namespace? I.e. they will never be accessible or cause name
    clashes outside the file (TU) they're compiled in?

    > > The symbols then may clash in link-time (unless I put
    >> them in different namespaces as suggested), however, each and every
    >> MessageClass are registered in a global register where the language
    >> can be changed.

    >
    > Since those instances of 'MessageClass' all have their own storage,
    > their addresses are unique, and the "global register" should be able to
    > distinguish between two objects like that. Beware of address problems
    > when accessing objects across DLL boundaries (although this is quite
    > OS-specific), like defining the object in one DLL and using its address
    > in another.
    >


    This is a hard one. Is there a way to be totally sure it will work? I've
    used the flag -fPIC before. Is that a guarantee?
     
    DeMarcus, Apr 23, 2010
    #11
  12. DeMarcus

    DeMarcus Guest

    Pete Becker wrote:
    > DeMarcus wrote:
    >> GlobalRegister::register( &ERROR );

    >
    > There's a separate issue here: "register" is a keyword. You can't use it
    > as an identifier.
    >


    Actually it's called something like

    MessageSet::addMessage( &ERROR );
     
    DeMarcus, Apr 23, 2010
    #12
  13. DeMarcus <> writes:

    > Paul Bibbings wrote:
    >> DeMarcus <> writes:
    >>
    >>> If I define the variables like this
    >>>
    >>> file1.cpp
    >>> static int varA;
    >>>
    >>> file2.cpp
    >>> static int varA;
    >>>
    >>> Am I allowed to send either varA pointer to other places in the
    >>> application?

    >>
    >> Are you able to say a little more about what you are trying to achieve?
    >> With the little information we have, it strikes me, at least, as a
    >> little convoluted. Your question began with name clashing, then sought
    >> a method to make your same-named variables TU-local, and now you are
    >> asking how you can refer to these same-named variables outside of the TU
    >> they're defined in.
    >>
    >> Questions to be asked include, in the first instance, "Why are your
    >> variables named the same?" "What application-wide visibility do you want
    >> for these variables?" Then you might want to ask yourself to what
    >> extent your answers to these questions conflict.
    >>

    >
    > I want to achieve the following.
    >
    > file_class.cpp
    > const MessageClass ERROR( "Could not find file" );
    >
    > class FileClass
    > {
    > public:
    > FileClass()
    > {
    > GlobalRegister::register( &ERROR );
    > }
    >
    > void open( string s )
    > {
    > if( /* Error when opening file */ )
    > std::cerr << ERROR << std::endl;
    > }
    > };
    >
    > calculation_class.cpp
    > const MessageClass ERROR( "Could not calculate" );
    >
    > class CalculationClass
    > {
    > public:
    > CalculationClass()
    > {
    > GlobalRegister::register( &ERROR );
    > }
    >
    > void calculate()
    > {
    > if( /* Error during calculation */ )
    > std::cerr << ERROR << std::endl;
    > }
    > };
    >
    >
    > I want to allow any file be able to use the symbol ERROR but at the
    > same time they shall be able to register the pointer to that variable
    > without clashing with other variables with the same symbol name.


    I have looked over the skeleton code that you have provided here and,
    rather than it assisting me in thinking about how to best get around the
    problems of multiply-defined ERROR instances, I cannot escape feeling
    uneasy about the whole design. I am wondering if the very appearance of
    the specific problems that you are facing here are not symptomatic of a
    design that is otherwise flawed at a very fundamental level. Specific
    questions that jump to mind without resolution (for me) and which lead
    me to this through include the following:

    1. What is the necessity in the first place of instantiating an
    instance of an error message and then `registering' it by address?
    Why is it not the responsibility of the GlobalRegister itself to
    manage its own error messages - i.e., /contain/ them?

    2. Why do you give the responsibility to each specific class -
    FileClass, CalculationClass - for registering their respective error
    messages? Why isn't the initialization of all such error messages
    achieved at a single point of initialization at program startup?

    I ask this, as it derives from the next question:
    3. Why is it that each ERROR gets registered *every* time that an
    instance of the relevant class is instantiated when all the
    registration achieves is to add the *same* address to the *same*
    object to the registry over and over again? Essentially, on
    attempting to open 100 files or perform 1000 calculations, what is
    the purpose of the registry holding 100/1000 pointers to the same
    single ERROR instance?

    4. What is the purpose of registering in the first place, when you
    do not then make use of the registry to retrieve the appropriate
    error message in, for example, FileClass::eek:pen(string) and
    CalculationClass::calculate()? Instead, you short circuit the
    registry (in effect) and make use of the TU-local ERROR instance
    directly (and I would suggest that it is only because of this
    avoidance of the registry at this point that you suppose that the
    presence of these TU-local ERROR instances contributes to your
    design.)

    Without, clearly, having a full sense of the wider program this code
    applies to - for instance, I only have a vague idea from other posts of
    yours what the registry's purpose is - I nevertheless feel that some
    other design effort is required in order to centralise responsibilities
    where they belong and, in particular, to give to the registry full
    handling of the objects that you are registering with it; then, it is
    for the program code to *use* that registry.

    With a design broadly along these lines you will find there shall be no
    need for any ERROR objects outside of the registry, no necessity of them
    being similarly named and requiring special handling to avoid name
    clashes, and that the system as a whole will be better balanced in terms
    of design. It will also be more readily extensible.

    As an idea, I would suggest that you at least consider the following as
    alternatives to your present design:

    1. Let your `registry' be a full-fledged registry in the sense that
    it alone is responsible for managing the objects registered with it
    (i.e., let them not have an existence /outside/ of the registry
    itself);

    2. Let all interaction with the registered objects (error messages
    here) be through the interface of the registry;

    3. Let all such objects required by your program be registered in a
    single place during program startup, unless (which your example code
    doesn't indicate is the case) the error messages contain more
    detailed information about the /specific/ context in which a
    particular error has occurred.

    And finally, consider whether you need the registry at all. From other
    posts I am gathering that it's purpose is to enable appropriate error
    messages to be output in an appropriate language. Is this not the
    domain of std::locale? Why not just have appropriate error messages
    raised where required and have your MessageClass respond, in terms of
    what it actually outputs, according to the locale of the program user.
    Again, it's about responsibilities. It seems fair to argue that it is
    the responsibility of a MessageClass to be locale aware, itself, in this
    sense.

    Regards

    Paul Bibbings
     
    Paul Bibbings, Apr 23, 2010
    #13
  14. DeMarcus

    osmium Guest

    Victor Bazarov wrote:

    > Pete Becker wrote:
    >> DeMarcus wrote:
    >>> GlobalRegister::register( &ERROR );

    >>
    >> There's a separate issue here: "register" is a keyword. You can't
    >> use it as an identifier.
    >>

    >
    > Next standard should remove it, don't you think?


    I think removing it would simply makes things worse. That would produce a
    new and mostly unused dialect and a bunch of additional folklore to dig
    through in, say, 2050. Old computer languages should be allowed to die a
    peaceful death. I would put C++ near the top of that list.
     
    osmium, Apr 24, 2010
    #14
  15. DeMarcus

    DeMarcus Guest

    Paul Bibbings wrote:
    > DeMarcus <> writes:
    >
    >> Paul Bibbings wrote:
    >>> DeMarcus <> writes:
    >>>
    >>>> If I define the variables like this
    >>>>
    >>>> file1.cpp
    >>>> static int varA;
    >>>>
    >>>> file2.cpp
    >>>> static int varA;
    >>>>
    >>>> Am I allowed to send either varA pointer to other places in the
    >>>> application?
    >>> Are you able to say a little more about what you are trying to achieve?
    >>> With the little information we have, it strikes me, at least, as a
    >>> little convoluted. Your question began with name clashing, then sought
    >>> a method to make your same-named variables TU-local, and now you are
    >>> asking how you can refer to these same-named variables outside of the TU
    >>> they're defined in.
    >>>
    >>> Questions to be asked include, in the first instance, "Why are your
    >>> variables named the same?" "What application-wide visibility do you want
    >>> for these variables?" Then you might want to ask yourself to what
    >>> extent your answers to these questions conflict.
    >>>

    >> I want to achieve the following.
    >>
    >> file_class.cpp
    >> const MessageClass ERROR( "Could not find file" );
    >>
    >> class FileClass
    >> {
    >> public:
    >> FileClass()
    >> {
    >> GlobalRegister::register( &ERROR );
    >> }
    >>
    >> void open( string s )
    >> {
    >> if( /* Error when opening file */ )
    >> std::cerr << ERROR << std::endl;
    >> }
    >> };
    >>
    >> calculation_class.cpp
    >> const MessageClass ERROR( "Could not calculate" );
    >>
    >> class CalculationClass
    >> {
    >> public:
    >> CalculationClass()
    >> {
    >> GlobalRegister::register( &ERROR );
    >> }
    >>
    >> void calculate()
    >> {
    >> if( /* Error during calculation */ )
    >> std::cerr << ERROR << std::endl;
    >> }
    >> };
    >>
    >>
    >> I want to allow any file be able to use the symbol ERROR but at the
    >> same time they shall be able to register the pointer to that variable
    >> without clashing with other variables with the same symbol name.

    >
    > I have looked over the skeleton code that you have provided here and,
    > rather than it assisting me in thinking about how to best get around the
    > problems of multiply-defined ERROR instances, I cannot escape feeling
    > uneasy about the whole design. I am wondering if the very appearance of
    > the specific problems that you are facing here are not symptomatic of a
    > design that is otherwise flawed at a very fundamental level. Specific
    > questions that jump to mind without resolution (for me) and which lead
    > me to this through include the following:
    >
    > 1. What is the necessity in the first place of instantiating an
    > instance of an error message and then `registering' it by address?
    > Why is it not the responsibility of the GlobalRegister itself to
    > manage its own error messages - i.e., /contain/ them?
    >


    Thanks for your thorough examination. It's much appreciated.

    I've been turning this idea upside down, inside out several times to
    really make sure I'm doing the right thing. To be able to provide
    language neutral output, the actual point where the output is done
    cannot use plain text but must provide an ID to text representing the
    output. I.e.

    // Not language neutral
    output->print( "Error. Couldn't find file." );

    // Language neutral using a string ID.
    output->print( "file_not_found_error" );

    Now, using a string as ID has two problems.
    1. There is no compile-time check that the message exists.
    2. Decentralization of the ID spreading concrete IDs all over the code.

    After lots of investigation I took the design decision to use a constant
    class as ID.

    // Language neutral using a constant class ID.
    output->print( FILE_NOT_FOUND_ERROR );

    This solves some problems.
    1. Possible misspelling of an ID. The compiler will catch a misspelled
    constant.
    2. The programmer is now forced to create the message before any output
    can be done. With a plain string as ID the creation of the message
    can be postponed and forgotten.
    3. Name clashes of the ID is easier to resolve. A constant as ID can
    contain not only the message ID string but also a category and a
    default message, e.g.
    const MessageClass FILE_NOT_FOUND_ERROR(
    "XYZ_Inc_plugin",
    "file_not_found_error",
    "Error. Couldn't find file." );
    All this can be centrally maintained by inheritance of
    XYZIncMessageClass.


    > 2. Why do you give the responsibility to each specific class -
    > FileClass, CalculationClass - for registering their respective error
    > messages? Why isn't the initialization of all such error messages
    > achieved at a single point of initialization at program startup?
    >


    You're completely right. I just put that in the constructor to put it
    somewhere for the example. In the real design the registration is done
    in the constructor of MessageClass; a so-called self-registration.

    MessageClass
    {
    public:
    MessageClass( string category, string id, string defaultMessage )
    : category_(category), id_(id), defaultMessage_(defaultMessage)
    {
    MessageSet::addMessage( this );
    }
    };

    > I ask this, as it derives from the next question:
    > 3. Why is it that each ERROR gets registered *every* time that an
    > instance of the relevant class is instantiated when all the
    > registration achieves is to add the *same* address to the *same*
    > object to the registry over and over again? Essentially, on
    > attempting to open 100 files or perform 1000 calculations, what is
    > the purpose of the registry holding 100/1000 pointers to the same
    > single ERROR instance?
    >


    You're right, see above.

    > 4. What is the purpose of registering in the first place, when you
    > do not then make use of the registry to retrieve the appropriate
    > error message in, for example, FileClass::eek:pen(string) and
    > CalculationClass::calculate()? Instead, you short circuit the
    > registry (in effect) and make use of the TU-local ERROR instance
    > directly (and I would suggest that it is only because of this
    > avoidance of the registry at this point that you suppose that the
    > presence of these TU-local ERROR instances contributes to your
    > design.)
    >


    Sorry again, maybe I simplified the example too much. I have an own
    class doing the lookup of the internationalized message and the prints
    the output. E.g.

    class FileClass
    {
    public:

    void open( string s )
    {
    if( /* Error when opening file */ )
    output->print( FILE_NOT_FOUND_ERROR );
    }
    };

    In the output class it takes the category and id of the message, looks
    up the correct message for current language in the global register and
    prints it. If it for some reason can't find a translation in the
    register it falls back on the default message which is English.


    > Without, clearly, having a full sense of the wider program this code
    > applies to - for instance, I only have a vague idea from other posts of
    > yours what the registry's purpose is - I nevertheless feel that some
    > other design effort is required in order to centralise responsibilities
    > where they belong and, in particular, to give to the registry full
    > handling of the objects that you are registering with it; then, it is
    > for the program code to *use* that registry.
    >
    > With a design broadly along these lines you will find there shall be no
    > need for any ERROR objects outside of the registry, no necessity of them
    > being similarly named and requiring special handling to avoid name
    > clashes, and that the system as a whole will be better balanced in terms
    > of design. It will also be more readily extensible.
    >
    > As an idea, I would suggest that you at least consider the following as
    > alternatives to your present design:
    >
    > 1. Let your `registry' be a full-fledged registry in the sense that
    > it alone is responsible for managing the objects registered with it
    > (i.e., let them not have an existence /outside/ of the registry
    > itself);
    >


    The design is built on self-registration, and I was partly inspired by
    Jim Beveridge's article in Dr. Dobb's:
    www.drdobbs.com/184410633

    > 2. Let all interaction with the registered objects (error messages
    > here) be through the interface of the registry;
    >


    It is, but in a different way that one may be used to. I guess that you
    propose something like.

    std::cout << myReg->getMessage( "file_not_found" ) << std::endl;

    I try to do as much lazy evaluation as possible so almost nothing is
    evaluated out in the programmer's code but rather handled in
    output->print()
    that takes a pointer to the ID of the message.

    > 3. Let all such objects required by your program be registered in a
    > single place during program startup, unless (which your example code
    > doesn't indicate is the case) the error messages contain more
    > detailed information about the /specific/ context in which a
    > particular error has occurred.
    >


    It's actually a mix of centralization and decentralization where in the
    decentralization part one is able to provide messages in the same .cpp
    file as they are used, but since they are just plain IDs and
    self-registering the main work is centralized to one repository.

    > And finally, consider whether you need the registry at all. From other
    > posts I am gathering that it's purpose is to enable appropriate error
    > messages to be output in an appropriate language. Is this not the
    > domain of std::locale? Why not just have appropriate error messages
    > raised where required and have your MessageClass respond, in terms of
    > what it actually outputs, according to the locale of the program user.
    > Again, it's about responsibilities. It seems fair to argue that it is
    > the responsibility of a MessageClass to be locale aware, itself, in this
    > sense.
    >


    I'd like to use standardized tools but as far as I understand
    std::locale is not that powerful when it comes to message strings. For
    instance, as I understand, doing an output with variables is not
    supported. E.g. print( "There are $1 plug-ins loaded.", nPlugins );
     
    DeMarcus, Apr 25, 2010
    #15
  16. DeMarcus

    DeMarcus Guest

    Victor Bazarov wrote:
    > DeMarcus wrote:
    >> Victor Bazarov wrote:
    >>> DeMarcus wrote:
    >>>> Victor Bazarov wrote:
    >>>>> DeMarcus wrote:
    >>>>>> [...]
    >>>>>> I want to allow any file be able to use the symbol ERROR but at
    >>>>>> the same time they shall be able to register the pointer to that
    >>>>>> variable
    >>>>>
    >>>>> Why? What for?
    >>>>>
    >>>>> > without
    >>>>>> clashing with other variables with the same symbol name.
    >>>>>
    >>>>> What does registering have to do with compilation? Are you
    >>>>> confusing run-time behavior (of your system) with the behavior of
    >>>>> the compiler (who determines and reports "name clashes")?
    >>>>>
    >>>>
    >>>> I want to be able to use the same symbols (here symbol ERROR) in
    >>>> different places.
    >>>
    >>> OK. Judging from the code you posted so far, there should be no
    >>> problem. Of course, you (hopefully) already found that if you make
    >>> the object 'const' you don't have that problem because a const object
    >>> has internal linkage by default. If you don't declare your object
    >>> 'const', it has external linkage, and without 'static' (which forces
    >>> internal linkage) or placing it in an unnamed namespace (which
    >>> changes the name of the var so it becomes inaccessible from other
    >>> TUs) you will get problems with the linker.
    >>>

    >>
    >> Aha, does this mean that as long as I declare them const, I don't need
    >> the unnamed namespace? I.e. they will never be accessible or cause
    >> name clashes outside the file (TU) they're compiled in?

    >
    > If your linker does not complain (which it shouldn't), then you're set.
    >
    >>> > The symbols then may clash in link-time (unless I put
    >>>> them in different namespaces as suggested), however, each and every
    >>>> MessageClass are registered in a global register where the language
    >>>> can be changed.
    >>>
    >>> Since those instances of 'MessageClass' all have their own storage,
    >>> their addresses are unique, and the "global register" should be able
    >>> to distinguish between two objects like that. Beware of address
    >>> problems when accessing objects across DLL boundaries (although this
    >>> is quite OS-specific), like defining the object in one DLL and using
    >>> its address in another.
    >>>

    >>
    >> This is a hard one. Is there a way to be totally sure it will work?
    >> I've used the flag -fPIC before. Is that a guarantee?

    >
    > I have no idea what you're talking about. Those things platform- and
    > compiler-specific. You need to consult the newsgroup dedicated to your
    > OS, most likely.
    >
    > V


    Ok, I'll check that up. Thanks!
     
    DeMarcus, Apr 26, 2010
    #16
  17. DeMarcus

    Öö Tiib Guest

    On Apr 23, 4:20 pm, DeMarcus <> wrote:
    > Paul Bibbings wrote:
    > > DeMarcus <> writes:

    >
    > >> If I define the variables like this

    >
    > >> file1.cpp
    > >> static int varA;

    >
    > >> file2.cpp
    > >> static int varA;

    >
    > >> Am I allowed to send either varA pointer to other places in the
    > >> application?

    >
    > > Are you able to say a little more about what you are trying to achieve?
    > > With the little information we have, it strikes me, at least, as a
    > > little convoluted.  Your question began with name clashing, then sought
    > > a method to make your same-named variables TU-local, and now you are
    > > asking how you can refer to these same-named variables outside of the TU
    > > they're defined in.

    >
    > > Questions to be asked include, in the first instance, "Why are your
    > > variables named the same?" "What application-wide visibility do you want
    > > for these variables?"  Then you might want to ask yourself to what
    > > extent your answers to these questions conflict.

    >
    > I want to achieve the following.
    >
    > file_class.cpp
    > const MessageClass ERROR( "Could not find file" );
    >
    > class FileClass
    > {
    > public:
    >     FileClass()
    >     {
    >        GlobalRegister::register( &ERROR );
    >     }
    >
    >     void open( string s )
    >     {
    >        if( /* Error when opening file */ )
    >           std::cerr << ERROR << std::endl;
    >     }
    >
    > };
    >
    > calculation_class.cpp
    > const MessageClass ERROR( "Could not calculate" );
    >
    > class CalculationClass
    > {
    > public:
    >     CalculationClass()
    >     {
    >        GlobalRegister::register( &ERROR );
    >     }
    >
    >     void calculate()
    >     {
    >        if( /* Error during calculation */ )
    >           std::cerr << ERROR << std::endl;
    >     }
    >
    > };
    >
    > I want to allow any file be able to use the symbol ERROR but at the same
    > time they shall be able to register the pointer to that variable without
    > clashing with other variables with the same symbol name.


    If you run out of ideas or are stuck with something, then you can look
    at how GNU gettext works (translation tool poedit). Also how QT
    translations are made (translation tool qt-linguist). It feels that
    you are perhaps inventing something similar.
     
    Öö Tiib, Apr 27, 2010
    #17
  18. DeMarcus

    DeMarcus Guest

    On 2010-04-27 03:28, Öö Tiib wrote:
    > On Apr 23, 4:20 pm, DeMarcus<> wrote:
    >> Paul Bibbings wrote:
    >>> DeMarcus<> writes:

    >>
    >>>> If I define the variables like this

    >>
    >>>> file1.cpp
    >>>> static int varA;

    >>
    >>>> file2.cpp
    >>>> static int varA;

    >>
    >>>> Am I allowed to send either varA pointer to other places in the
    >>>> application?

    >>
    >>> Are you able to say a little more about what you are trying to achieve?
    >>> With the little information we have, it strikes me, at least, as a
    >>> little convoluted. Your question began with name clashing, then sought
    >>> a method to make your same-named variables TU-local, and now you are
    >>> asking how you can refer to these same-named variables outside of the TU
    >>> they're defined in.

    >>
    >>> Questions to be asked include, in the first instance, "Why are your
    >>> variables named the same?" "What application-wide visibility do you want
    >>> for these variables?" Then you might want to ask yourself to what
    >>> extent your answers to these questions conflict.

    >>
    >> I want to achieve the following.
    >>
    >> file_class.cpp
    >> const MessageClass ERROR( "Could not find file" );
    >>
    >> class FileClass
    >> {
    >> public:
    >> FileClass()
    >> {
    >> GlobalRegister::register(&ERROR );
    >> }
    >>
    >> void open( string s )
    >> {
    >> if( /* Error when opening file */ )
    >> std::cerr<< ERROR<< std::endl;
    >> }
    >>
    >> };
    >>
    >> calculation_class.cpp
    >> const MessageClass ERROR( "Could not calculate" );
    >>
    >> class CalculationClass
    >> {
    >> public:
    >> CalculationClass()
    >> {
    >> GlobalRegister::register(&ERROR );
    >> }
    >>
    >> void calculate()
    >> {
    >> if( /* Error during calculation */ )
    >> std::cerr<< ERROR<< std::endl;
    >> }
    >>
    >> };
    >>
    >> I want to allow any file be able to use the symbol ERROR but at the same
    >> time they shall be able to register the pointer to that variable without
    >> clashing with other variables with the same symbol name.

    >
    > If you run out of ideas or are stuck with something, then you can look
    > at how GNU gettext works (translation tool poedit). Also how QT
    > translations are made (translation tool qt-linguist). It feels that
    > you are perhaps inventing something similar.


    Yes, I will get some inspiration from there. For the frontend I will
    probably use Qt, but I'm still working on the backend where I want to
    avoid as much third party dependencies as possible. Right now it's only
    boost.
     
    DeMarcus, Apr 30, 2010
    #18
  19. DeMarcus

    Öö Tiib Guest

    On Apr 30, 2:11 pm, DeMarcus <> wrote:
    > On 2010-04-27 03:28, Öö Tiib wrote:
    >
    >
    >
    >
    >
    > > On Apr 23, 4:20 pm, DeMarcus<>  wrote:
    > >> Paul Bibbings wrote:
    > >>> DeMarcus<>  writes:

    >
    > >>>> If I define the variables like this

    >
    > >>>> file1.cpp
    > >>>> static int varA;

    >
    > >>>> file2.cpp
    > >>>> static int varA;

    >
    > >>>> Am I allowed to send either varA pointer to other places in the
    > >>>> application?

    >
    > >>> Are you able to say a little more about what you are trying to achieve?
    > >>> With the little information we have, it strikes me, at least, as a
    > >>> little convoluted.  Your question began with name clashing, then sought
    > >>> a method to make your same-named variables TU-local, and now you are
    > >>> asking how you can refer to these same-named variables outside of the TU
    > >>> they're defined in.

    >
    > >>> Questions to be asked include, in the first instance, "Why are your
    > >>> variables named the same?" "What application-wide visibility do you want
    > >>> for these variables?"  Then you might want to ask yourself to what
    > >>> extent your answers to these questions conflict.

    >
    > >> I want to achieve the following.

    >
    > >> file_class.cpp
    > >> const MessageClass ERROR( "Could not find file" );

    >
    > >> class FileClass
    > >> {
    > >> public:
    > >>      FileClass()
    > >>      {
    > >>         GlobalRegister::register(&ERROR );
    > >>      }

    >
    > >>      void open( string s )
    > >>      {
    > >>         if( /* Error when opening file */ )
    > >>            std::cerr<<  ERROR<<  std::endl;
    > >>      }

    >
    > >> };

    >
    > >> calculation_class.cpp
    > >> const MessageClass ERROR( "Could not calculate" );

    >
    > >> class CalculationClass
    > >> {
    > >> public:
    > >>      CalculationClass()
    > >>      {
    > >>         GlobalRegister::register(&ERROR );
    > >>      }

    >
    > >>      void calculate()
    > >>      {
    > >>         if( /* Error during calculation */ )
    > >>            std::cerr<<  ERROR<<  std::endl;
    > >>      }

    >
    > >> };

    >
    > >> I want to allow any file be able to use the symbol ERROR but at the same
    > >> time they shall be able to register the pointer to that variable without
    > >> clashing with other variables with the same symbol name.

    >
    > > If you run out of ideas or are stuck with something, then you can look
    > > at how GNU gettext works (translation tool poedit). Also how QT
    > > translations are made (translation tool qt-linguist). It feels that
    > > you are perhaps inventing something similar.

    >
    > Yes, I will get some inspiration from there. For the frontend I will
    > probably use Qt, but I'm still working on the backend where I want to
    > avoid as much third party dependencies as possible. Right now it's only
    > boost.


    Yes, good goal. If you avoid application logic dealing with
    interaction with user (i assume application logic is backend by you)
    then you can keep it as not translated. For example throw exceptions
    containing error codes, relevant data and English-only texts. Leave
    human interaction entirely as responsibility of user interface (i
    assume it is frontend by you). As result translations are user
    interfaces responsibility and QT handles it quite well.

    Showing raw exception or error texts to end user is dangerous because
    people sometimes write odd texts when handling hard to reproduce
    corner cases.

    void foo( int param )
    {
    if ( !usualValue(param) )
    {
    throw OurUnexpected("how we got such param here?", param);
    // TODO: figure it out
    }

    // ... usual logic
    }

    Such TODO-s will be often left as debt since thing works, unit test
    runs (exception, like expected), testers did not discover case when
    unusual value gets to foo, budget is used up and management pressures
    it to market. Results are humorous at best when such exception text is
    displayed to end user.
     
    Öö Tiib, May 1, 2010
    #19
    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. Jacob

    class name clash

    Jacob, Feb 6, 2004, in forum: Java
    Replies:
    14
    Views:
    834
    Larry Barowski
    Feb 10, 2004
  2. Martin Bless

    Q: distutils - name clash protection?

    Martin Bless, Jul 26, 2004, in forum: Python
    Replies:
    3
    Views:
    279
    Calvin Spealman
    Aug 2, 2004
  3. Olivier Vierlinck

    built-in function- module name clash

    Olivier Vierlinck, Sep 6, 2004, in forum: Python
    Replies:
    2
    Views:
    307
    Alex Martelli
    Sep 6, 2004
  4. George P
    Replies:
    3
    Views:
    688
    Alex Martelli
    Sep 11, 2004
  5. Joost
    Replies:
    3
    Views:
    256
    Gabriel Genellina
    Feb 5, 2007
Loading...

Share This Page