Why koenig lookup?

J

Juha Nieminen

The so-called koenig lookup allows doing odd things like this:

#include <algorithm>
#include <string>

int main()
{
std::string table[10];
sort(table, table+10);
}

(Notice how the 'sort' doesn't have the std:: prefix, yet it's
perfectly valid.)

I understand that the reason for the koenig lookup to exist is so that
you can write things like:

std::cout << 5;

This is actually equivalent to:

operator<<(std::cout, 5);

The koenig lookup allows the compiler to look for operator<< inside
the std namespace because one of the parameters is from that namespace.

With operators it makes sense. However, why perform the same lookup
for *all* functions? What's the advantage? Couldn't it be simply defined
that the koenig lookup is performed for operators but not for regular
functions?
 
C

Captain Trips

Juha said:
The so-called koenig lookup allows doing odd things like this:

#include <algorithm>
#include <string>

int main()
{
std::string table[10];
sort(table, table+10);
}

(Notice how the 'sort' doesn't have the std:: prefix, yet it's
perfectly valid.)

I understand that the reason for the koenig lookup to exist is so that
you can write things like:

std::cout << 5;

This is actually equivalent to:

operator<<(std::cout, 5);

The koenig lookup allows the compiler to look for operator<< inside
the std namespace because one of the parameters is from that namespace.

With operators it makes sense. However, why perform the same lookup
for *all* functions? What's the advantage? Couldn't it be simply defined
that the koenig lookup is performed for operators but not for regular
functions?

Well it saves a lot of typing, i think that's why it's working for
functions, too. If the function is valid in the namespace std, why
should you type it all the time. If you don't want to use std just don't
type "using namespace std;" at the beginning of your code. The compiler
will demand std:: all the time then.

If you type the line the compiler doesn't need the std:: anymore,
because you are already in the namespace std.
 
J

Juha Nieminen

Captain said:
Well it saves a lot of typing, i think that's why it's working for
functions, too. If the function is valid in the namespace std, why
should you type it all the time. If you don't want to use std just don't
type "using namespace std;" at the beginning of your code. The compiler
will demand std:: all the time then.

If you type the line the compiler doesn't need the std:: anymore,
because you are already in the namespace std.

Uh? I think you are talking about a completely different issue. I was
not talking about "using" at all.
 
J

James Kanze

The so-called koenig lookup allows doing odd things like this:
#include <algorithm>
#include <string>
int main()
{
std::string table[10];
sort(table, table+10);
}
(Notice how the 'sort' doesn't have the std:: prefix, yet it's
perfectly valid.)
I understand that the reason for the koenig lookup to exist is
so that you can write things like:
std::cout << 5;
This is actually equivalent to:
operator<<(std::cout, 5);
The koenig lookup allows the compiler to look for operator<<
inside the std namespace because one of the parameters is from
that namespace.
With operators it makes sense. However, why perform the same
lookup for *all* functions? What's the advantage? Couldn't it
be simply defined that the koenig lookup is performed for
operators but not for regular functions?

What's the difference between a function and an operator, except
the invocation syntax? Orthogonality, if nothing else, requires
that the same lookup applies. In addition:

#include <BigDecimal.hh>

int
main()
{
using SomeNamespace::BigDecimal ;
BigDecimal z1 ;
BigDecimal z2 = sin( z1 ) ;
// Do you really think it reasonable to have to write
// SomeNamespace::sin here?
}

And of course, in a template, you don't really even have the
choice.
 
J

James Kanze

* Juha Nieminen:
The so-called koenig lookup allows doing odd things like
this:
#include <algorithm>
#include <string>
int main()
{
std::string table[10];
sort(table, table+10);
}
(Notice how the 'sort' doesn't have the std:: prefix, yet
it's perfectly valid.)
I understand that the reason for the koenig lookup to exist
is so that you can write things like:
std::cout << 5;
This is actually equivalent to:
operator<<(std::cout, 5);
The koenig lookup allows the compiler to look for operator<<
inside the std namespace because one of the parameters is
from that namespace.
With operators it makes sense. However, why perform the same
lookup for *all* functions? What's the advantage? Couldn't
it be simply defined that the koenig lookup is performed for
operators but not for regular functions?

I don't think Andrew Koenig, or /anyone else/, fully grokked
the consequences at the time.

Well, he certainly didn't have any concrete experience with it
before it was standardized. However...
If ADL (argument-dependent lookup) was defined today, now that
we've had some experience with it, then I'm pretty sure it
would be restricted to operators, and perhaps -- but just
perhaps -- extended in another direction, namely for lookup
of arguments in classes, where it's a hassle to have to
qualify things all the time, as opposed to the case
exemplified above, where it just introduces problems and
complexity without conferring any advantage.

A few experimental implementations had been made with namespace,
and I think it was concrete experience with them that led to the
understanding that something had to be done with functions. All
functions, not just overloaded operators. Now, given the time
frame, I personally think that the "correct" solution would have
been to back out of the problem completely, and drop namespaces
from that version of the standard, because of a lack of
knowledge with regards to the real problems that it might
introduce. (And in honesty, I have to admit that my fears were
largely unfounded.)

Off hand, I think if there were anything to do differently
(given namespaces and the way they work), it would be to have
the built in types imply the global namespace, rather than no
namespace.
I guess that goes to show that the job of standardization is
not to innovate. ;-)

I think at least some members of the committee share your
opinion there---at least part of the motivation behind Boost was
to provide a place where innovation would be appropriate, which
could be standardized once concrete experience was established.
(Regretfully, it only applies to libraries.)
 
S

Sébastien M.

The koenig lookup allows the compiler to look for operator<< inside
the std namespace because one of the parameters is from that namespace.

With operators it makes sense. However, why perform the same lookup
for *all* functions? What's the advantage? Couldn't it be simply defined
that the koenig lookup is performed for operators but not for regular
functions?

Here is a good (but quite long) article which explain this :
http://www.gotw.ca/publications/mill02.htm
 
A

Andrew Koenig

I don't think Andrew Koenig, or /anyone else/, fully grokked the
consequences at the time.

Well, that kind of depends.

First, let me emphasize that I did not invent the idea of argument-dependent
lookup, nor was I particularly fond of the idea. The main reason my name
got hung on it was that I played a significant role in convincing the
standards committee that something like it was necessary.

The examples that show the need to find operators are too well known for me
to need to elaborate them further. The examples that are the real killers,
however, come up when we start using templates. Consider:

template <class T> void foo(T t1, T t2) {
// ...
T t3 = t1 + t2;
T t4 = combine(t1, t2);
// ...
};

I hope you will agree with me that it would not be a good thing if there
were no way to decide where to look up the + in t1 + t2. But if you agree
there, then what can we say about looking up "combine" in combine(t1, t2)?
Shouldn't it be possible to write

namespace Mine {
class Thing { /* ... */ };
Thing operator+(Thing, Thing);
Thing combine(Thing, Thing);
// ...
}

and then call foo(Mine::Thing(), Mine::Thing())?

If it's necessary for foo to be able to find Mine::eek:perator+ by looking at
the type of t1 and t2, isn't it equally necessary for foo to be able to find
Mine::combine for the same reason? Notice that in both cases, there is *no*
way for the author of foo to specify a namespace explicitly, because the
author of foo has no way of knowing what namespace to specify.

This problem first came to my attention pretty late in the standardization
process, and I realized that if the standard as it then stood were to be
approved, neither t3 nor t4's initializing expression would be able to be
compiled. So I explained the problem to the committee, mentioned that if we
didn't do anything about it, we would be faced with a lot of pretty obvious
programs that would not compile, and it was pretty much a matter of going
with the best we could come up with in the time available or revising the
schedule.

I don't recall having an opinion at the time about which was the better
course of action. However, it is now more than ten years later, and I don't
seem to see a consensus on a better solution to the problem--which suggests
that perhaps delaying the standard wouldn't have made things any better.

So I guess it comes down to which consequences I grokked. What I did know
is that we had discovered a very serious problem, that we did not know a
perfect solution, and that we had to do *something*. Short of reworking all
the name lookup rules from scratch, it's far from clear to me what other
alternatives we had.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top