Nil and nil Macro Conflict

  • I want to use a C++ software library which uses class names "nil" and "Nil" for a Cocoa application.

    Including the headers will fail due to name conflicts with the macros "Nil" and "nil".

    What are my options?

    Regards
    Andreas
  • On May 1, 2012, at 5:44 AM, Andreas Grosam wrote:

    > What are my options?

    You might have to wrap that sucker, so that you can compile that class as straight C++ and never include its header from Objective-C++, but instead use your wrapper class from Objective-C++.

    Assuming you don't want to change those class names and then have to re-do that every time you update the library...

    --
    Scott Ribe
    <scott_ribe...>
    http://www.elevated-dev.com/
    (303) 722-0567 voice
  • On May 1, 2012, at 3:56 PM, Scott Ribe wrote:

    > On May 1, 2012, at 5:44 AM, Andreas Grosam wrote:
    >
    >> What are my options?
    >
    > You might have to wrap that sucker, so that you can compile that class as straight C++ and never include its header from Objective-C++, but instead use your wrapper class from Objective-C++.

    Hm, the library is a header only template library - namely its spirit (from boost), so my chances to never include this library are zero ;)

    Basically, I need something like the following to compile:

    // file foo.m:

    #include <Foundation/Foundation.h>

    namespace nm {

        struct nil {};
        struct Nil {};
    }

    NSObject* o = nil;

    Andreas
  • On May 1, 2012, at 8:10 AM, Andreas Grosam wrote:

    > Hm, the library is a header only template library - namely its spirit (from boost), so my chances to never include this library are zero ;)

    I didn't say never include it; I said never include it from Objective-C++. The fact that it is a header-only template library does not change the fact that you can create wrapper classes to use from Objective-C++.

    --
    Scott Ribe
    <scott_ribe...>
    http://www.elevated-dev.com/
    (303) 722-0567 voice
  • On May 1, 2012, at 7:10 AM, Andreas Grosam <agrosam...> wrote:
    > Hm, the library is a header only template library - namely its spirit (from boost), so my chances to never include this library are zero ;)
    >
    > Basically, I need something like the following to compile:
    >
    > // file foo.m:
    >
    > #include <Foundation/Foundation.h>
    >
    > namespace nm {
    > struct nil {};
    > struct Nil {};
    > }
    >
    > NSObject* o = nil;

    If you never need to use boost's nil in your own code, you can carefully order your includes so the boost headers are always first.

    #include <boost/header-that-uses-nil.h>  // uses nil
    #include <Foundation/Foundation.h>      // #defines nil but doesn't affect the boost header
    NSObject *o = nil;  // uses objc's nil

    If you do need to use boost's nil in your own code, you can use macro tricks to rename their nil.

    #define nil boost_nil
    #include <boost/header-that-uses-nil.h>
    #undef nil
    #include <Foundation/Foundation.h>
    // now you have objc's nil and boost::boost_nil

    --
    Greg Parker    <gparker...>    Runtime Wrangler
  • Are not both Objective-C and C++, as well as Objective-C++
    case-sensitive?  If so, Nil and nil should be different symbols.  If
    they should be, and really are different symbols, but still conflict
    somehow, then you've actually got a different problem than you think
    you do.

    Do Not Let The Sun Go Down Until You've Read John Lakos' excellent
    book "Large Scale C++ Software Design", published by Addison-Wesley.
    Much of what he proposes will contribute to the solution of your
    conflicting symbol problem.

    Even if one's project isn't written in C++, even if one does not have
    a clue about C++ it's quite likely there is something in Lakos' text
    that will help one out in a substantial way.

    Lakos' employer Mentor Graphics - a leading Electronic Design
    Automation (EDA) vendor - was one of the very first adopters of one of
    the very first releases of the C++ programming language.  Their first
    attempts at writing EDA tools in C++ failed miserably, with their
    "finished" programs being huge, bug-laden, crashy and leaky rats'
    nests that they had no hope of ever debugging.  EDA tools have a lot
    of source; the computers of the day would take days on end to do a
    single build!

    Rather than abandon C++, Lakos and his people figured out how to write
    C++ the way C++ wants to be written, with "Large Scale C++ Software
    Design" being the written report of what they figured out.

    That is, Bjarne Stroustrup and his people at AT&T figured out the
    Computer Science of C++.  John Lakos and his people at AT&T figure out
    C++'s Software Engineering.  It's important to understand that
    Software Engineering and Computer Science are COMPLETELY different
    things!

    Primary among Lakos recommendations is that one should not create just
    one single header file - allegedly "for convenience" - that client
    coders #include from everywhere.

    He states all manner of good reasons for not doing that.  Long, long
    before I read his book, among my main practices at many of the coding
    shops where I worked was breaking up just such monolithic headers into
    much smaller headers, so that each source or intervening header could
    #include just what it needed.

    Note that Apple's SDK engineers are the worst offenders with this,
    with "#include <Cocoa.h>", "#include <Carbon.h>" and so on.

    Quite a long time ago I figured out how to get the ZooLib C++
    Cross-Platform Application Framework to build _without_ using #include
    <Carbon.h>, only to be informed by some Apple engineer - who
    undoubtably spoke with authority - that Carbon was not at all
    guaranteed to even work if one #included individual framework headers,
    rather than just the top-level header.

    Another of Lakos' recommendations, which apply even for languages that
    use no header files, is to "levelize" your codebase.

    That is, a very poorly structured codebase will have most modules
    depending in some way on most other modules.  You'll find that you'll
    never get the bugs out of that code.  You'll also find that it's very
    difficult for newly-hired engineers to understand enough of your
    codebase to begin working productively at your company.

    The dependencies in a poorly levelized program will resemble the
    "string art" that was so popular in the late sixties and early
    seventies.  We were heavily into string art during my elementary
    school days.

    One drives a bunch of finishing nails into a piece of wood, spaced
    evenly say in an elliptical shape.  Then one ties some brightly
    colored string to one nail, stretches the string across the middle of
    the ellipse, around another nail, back across the middle and so on,
    finally tying it off after wrapping around a few other nails.  Every
    nail is connected to at least a few other nails by several pieces of
    string.

    Close examination of most of your codebases is quite likely to find
    that the dependencies of your compilation units on each other is just
    like the connections between pairs of nails by strings!

    By "module" Lakos means a "compilation unit", that is, a source file
    and everything that source file depends on to build - its headers,
    their headers and so on.

    The first step in levelizing your codebase is to edit the source of
    each module just so that it is broken into several new smaller and
    simpler pieces.  For object-oriented code, permit no more than one
    class per source file or header.

    Occasionally one has "helper" or C++ friend classes that are required
    for a particular class to work.  If those classes will _never_ be used
    by other than the main class they contribute to, it would be
    permissible to place them in the SOURCE FILE but not in the header
    file for that class.  One places them in the source rather than the
    header so they are totally invisible to any other source.

    Similarly the headers for templates should be split into multiple
    files so that unrelated templates are in separate header files.

    Start with the simplest of your classes, and get just those classes to
    build all by themselves, to generate object files but not a full
    executable.

    For templates, create some manner of test driver that instantiates
    only the templates included in each particular template header in a
    few different ways - Foo<int>, Foo<int*>, Foo<vector<int> > and so on.

    Don't worry for now whether this broken up code actually works, just
    get it to build after having been broken up.

    These simplest classes or templates should have no dependencies other
    than what are supplied with your development system or the OS.

    Now identify the next-simplest classes and templates, in that they
    depend only on the first level of classes and templates that you
    previously built, or on the OS or SDK.  Again get just those
    next-simplest modules to build.

    Continue on in a heirarchical fashion, at the very end getting the
    compilation unit that contains main() to build.

    The chances are quite good at this point that the modules that require
    Objective-C's nil will be in a completely different sub-heirarchy of
    your codebase than the modules that require boost's Nil.

    If you edit your sources carefully enough, and set up your new builds
    carefully enough, you won't introduce any new bugs during the
    levelization process.

    But if you do find that you've introduced bugs - or really, if you
    have ANY bugs at all - fix them by writing automated tests just for
    the very lowest level of your heirarchy, then after fixing any bugs
    you discover in just that lowest level, write tests for just the
    second level.

    Do not proceed to writing new tests, or fixing any bugs for higher
    levels until you've fixed the bugs in the lower levels!  It ought to
    be plainly apparent as to why.

    I'll send you my bill in the mail.  ;-)
    --
    Don Quixote de la Mancha
    Dulcinea Technologies Corporation
    Software of Elegance and Beauty
    http://www.dulcineatech.com
    <quixote...>
  • On May 1, 2012, at 7:16 PM, Greg Parker wrote:

    > On May 1, 2012, at 7:10 AM, Andreas Grosam <agrosam...> wrote:
    >> Hm, the library is a header only template library - namely its spirit (from boost), so my chances to never include this library are zero ;)
    >>
    >> Basically, I need something like the following to compile:
    >>
    >> // file foo.m:
    >>
    >> #include <Foundation/Foundation.h>
    >>
    >> namespace nm {
    >> struct nil {};
    >> struct Nil {};
    >> }
    >>
    >> NSObject* o = nil;
    >
    > If you never need to use boost's nil in your own code, you can carefully order your includes so the boost headers are always first.
    >
    > #include <boost/header-that-uses-nil.h>  // uses nil
    > #include <Foundation/Foundation.h>      // #defines nil but doesn't affect the boost header
    > NSObject *o = nil;  // uses objc's nil

    I thought about this, too. But Foundation.h is often in a Prefix header, as in my case. So this would require to include the boost header(s) in the prefix header as well. It's a viable solution, since I control the prefix header. It makes the project setup a bit fragile, though (removing the prefix will cause the project to not compile anymore).

    But as you too would suggest it, and it seems this is still the least intrusive solution to this issue, I'll give it a try.

    >
    > If you do need to use boost's nil in your own code, you can use macro tricks to rename their nil.
    >
    > #define nil boost_nil
    > #include <boost/header-that-uses-nil.h>
    > #undef nil
    > #include <Foundation/Foundation.h>
    > // now you have objc's nil and boost::boost_nil

    That's a handy trick - still I need to put the boost header in front of the Foundation header within the prefix file.

    Thank you Greg, and thank you all others for the tips!

    Regards
    Andreas
  • On May 2, 2012, at 7:46 AM, Don Quixote de la Mancha wrote:

    > Are not both Objective-C and C++, as well as Objective-C++
    > case-sensitive?  If so, Nil and nil should be different symbols.

    They are case-sensitive. Both, "nil" and "Nil" are different macros defined for different purposes in Objective-C:

    "nil" is the NULL-pointer for an Object,
    "Nil" is the NULL-pointer for a Class (object).

    Both effectively map to __DARWIN_NULL  on Mac OS X.

    > If they should be, and really are different symbols, but still conflict
    > somehow, then you've actually got a different problem than you think
    > you do.

    To clarify, I don't have a conflict with "Nil" against "nil"  - but a conflict with a C++ class name
    nm::nil with nil, and a class name nm::Nil and Nil.

    where "nm" stands for an arbitrary qualifier list (namespaces).

    >
    > Do Not Let The Sun Go Down Until You've Read John Lakos' excellent
    > book "Large Scale C++ Software Design", published by Addison-Wesley.
    > Much of what he proposes will contribute to the solution of your
    > conflicting symbol problem.

    I can believe this is an excellent read and it would certainly add values to my knowledge. Though my current problem shouldn't be such an issue and it feels it's digressing.  It's just that an Objective-C++ module includes a C++ header with symbols "Nil" and "nil" - and there is no other non-Objective-C module at all where I could move it to.

    > …

    Your recommendations and suggestions in the above make certainly sense, and  I - as far as I can ensure you - try to follow these proposed guidelines, probably even drifting to the other extreme which results in more independent files than absolutely necessary. Though, in my current project, all code is templates and "header only" - encapsulation of "private symbols" is accomplished through namespaces.  (You may even take a look at the sources - they are open source ;)  )

    Regards
    Andreas
  • 1) When in doubt, use C4! (actually, plain old dynamite should work just fine!)
    2) Shoot the (idiot) developer of the C++ code for doing that (may result in serious jail time...)
    3) Fuggedabouddit!
    4) Wait for ObjC 3.0 and hope it has a feature to isolate badly written (or named) code in a namespace...

    On May 1, 2012, at 6:44 AM, Andreas Grosam wrote:

    > I want to use a C++ software library which uses class names "nil" and "Nil" for a Cocoa application.
    >
    > Including the headers will fail due to name conflicts with the macros "Nil" and "nil".
    >
    > What are my options?
    >
    >
    > Regards
    > Andreas
previous month may 2012 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today