Friday, July 08, 2005

Strange lookup rule

This post is purely technical and uninterested people can hit the back button immediately.

This is something I never knew and read about it recently in "Exceptional C++". Let me start with a code example...

namespace A {
  class S { };
  void foo(S& parm) { }
}

namespace B {
  void foo(A::S& parm) { }
  void bar(A::S& parm) {
    foo(parm); // Which "foo" does this call?
  }
}

Try this out and to your surprise you'll find that this gives a "call to foo is ambiguous" error. But why?? The only foo visible at the place of call is in namespace B. Why should this result in an error? Okay, now try this out - comment out the "foo" definition in namespace B.

namespace A {
  class S { };
  void foo(S& parm) { }
}

namespace B {
  // void foo(A::S& parm) { }
  void bar(A::S& parm) {
    foo(parm); // Which "foo" does this call?
  }
}

This compiles without errors! Surprised again? When you run the program, it'd have called A::foo. What happened here? Does this not appear to be a namespace violation. Apparently not! This strange behavior is explained by "Koenig lookup".

If you supply a function argument of class type (here parm, of type A::S), then to find the function name the compiler considers matching names in the namespace (here A) containing the argument's type.

But still, is'nt this a namespace violation?? NO. Just consider this piece of code...

std::string str("Hello");
std::cout << str ;

This works fine right? How? This works because of Koenig lookup. The function in question here is "operator <<" which is found in "namespace std". But we have'nt used any "using" declaration to bring that function into the current scope. Since std::string is going as an argument into that function, the compiler will automatically look into the std namespace and will find that function. Without this kind of lookup, the same function call would have to be written as...

std::operator <<( std::cout, str) ; // ugly! ain't it??

This is the great value that Koenig lookup gets us and we tend to use it every now and then without realising it. Interesting - is'nt it??

7 comments:

  1. Useful as it maybe and accepting the fact that it prevents ugly function calls, it is going against the very notion of a namespace alva?

    Also, how do u ensure that in the very first piece of code u wrote(the original example in question) the function f being called is the one defined in namespace B only? by using the :: operator?

    ReplyDelete
  2. yes - for the initial example, you'd have to namespace qualify the call to foo.
    > it is going against the very notion of a namespace alva?
    not really. may be you feel it that way. but there's something called "interface principle"(look this phrase up on google). if you read that, then you will be clarified about this kind of lookup.

    ReplyDelete
  3. Its no surprise that everyone(just like Murali here) has a 'What the ' moment when they see first come across the Koenig Lookup rule. It almost looks counter intuitive. But, on reading the interface principle, it all figures out.

    ReplyDelete
  4. I guess i had read about the Koenig Lookup in a mail or something.. dont remember..

    ReplyDelete
  5. the title says it all..
    "Strange" lookup rule!!! :)
    Amajing observation,
    i was thinking about a general rule to avoid ambiguities when it comes to method invocations....
    assign precedence, jus like the operators are assigned precedence, here, u can call it as "priority" of a method over the other...
    gives more freedom to the programmer and also, makes the code less ambiguos for someone who doesn't know the lookup procedure..
    I believe in making life easier for myself.

    ReplyDelete
  6. girz - yes, there is an order of rules for resolving call to overloaded functions. its clearly explained in C++ primer(Lippmann).

    ReplyDelete
  7. i know macha, thats where i thought why not all ambiguities resolved so there is jus one way of doing something...

    ReplyDelete

What I want to say is: