Argument dependent name lookup

from Wikipedia, the free encyclopedia

Argument dependent name lookup (often argument dependent lookup or ADL for short , in German argument-dependent name resolution ; formerly Koenig-Lookup after the computer scientist Andrew Koenig) is a technique to display symbols from others in programming languages with the support of namespaces as well as free functions under certain circumstances Import namespaces automatically. One example is the programming language C ++ .

Overview

A simple example for ADL in C ++ is the use of the stream classes:

#include <iostream>

int main()
{
  std::cout << "Hallo, Welt!" << std::endl;
}

This example uses the stream operator function defined operator<<in the namespace std, as well as the rest of the stream classes. Without the use of ADL, the above example would not work. You would either have to stdmove the corresponding code into the namespace or explicitly use the operator

using std::operator<<;

import. But even this does not solve the underlying problem, because at the latest when user-defined data types from several different namespaces are to be used together with the stream classes in std, there are usually different definitions of operator<<in different namespaces.

It is also possible to completely dispense with the Infix notation:

#include <iostream>

int main()
{
  std::operator<<(std::cout, "Hallo, Welt").operator<<(std::endl);
}

The function notation allows the function calls to be qualified with the corresponding namespaces, but it requires significantly more paperwork. In addition, the caller must know whether the overload version of the operator (two-digit in the example) is a free-standing function (in the example: first call with two parameters) or a component of a class (in the example: second call with a period and one parameter). Function calls, even in simple examples like the one above, significantly limit the usefulness of operator overloading in particular; therefore the C ++ standard (Section 3.4.2) specifies that the compiler must also search through the namespaces belonging to the argument types (the so-called associated namespaces ).

The interface principle in C ++

The reason why argument-dependent name resolution is necessary in C ++ ultimately lies in the interpretation of what is seen as the class interface of a class . In contrast to most other languages, C ++ interprets a function as belonging to a class if it accepts arguments of the class type on the one hand and is in the same namespace as the class on the other. ADL allows such free functions to be used largely as if they were a direct part of the class interface.

The stream classes of the standard library are an application example for the interface principle. In order to be able to use your own data types with the standard streams, you would otherwise have to extend the stream classes for each new class so that they can handle them. This is not practical. Operator definitions for the output on streams can therefore not be methods of the stream classes, but must be implemented as free functions.

Such functions are also very closely linked to the class whose stream output they enable. For this reason, they are usually defined in the same namespace as the associated class. The ADL mechanism then makes it possible to take them into account when resolving the operator overload :

#include <iostream>

namespace geometry
{
  struct vector2D
  {
    vector2D() : x(0), y(0) {}
    vector2D(double x_new, double y_new) : x(x_new), y(y_new) {}
    double x;
    double y;
  };

  std::basic_ostream<char>& operator<<(std::basic_ostream<char>& stream, const vector2D& v)
  {
    stream << "(" << v.x << ", " << v.y << ")";
    return stream;
  }
}

int main()
{
  geometry::vector2D v(1, 2);

  std::cout << v << std::endl;
}

trouble

The argument-dependent resolution of symbols can lead to subtle errors and unportable code between different implementations. Another problem is the occasional counter-intuitive behavior of the compiler during ADL resolution, especially when using usinginstructions.

The problems caused by argument-dependent name resolution (mainly unintentional overload) are in principle the same as those that occur in programming languages ​​without namespaces. Therefore, they restrict the protective function of namespaces.

If the function name stdto be resolved is, for example, identical to a function from the namespace , it can happen that the compiler selects this function instead of the one provided by the programmer, since all assigned namespaces are first imported. Only then is the specific function selected based on the signatures (even if the programmer usinghas requested a specific version via directive).

For example, the following program cannot be translated by every C ++ implementation:

#include <vector>

namespace N
{
  struct X{};

  template <typename T>
  int* operator+(T, unsigned int i)
  {
    return i + 1;
  }
}

int main()
{
  std::vector<N::X> v(5);
  const N::X& elem = v[0];

  // (...)
}

Whether the above program can be compiled ultimately depends on the implementation of vector. In some implementations, element access is v[0]implemented using iterators, which in turn are operator+()applied. Depending on the implementation details, it can happen that the namespace is Ntaken into account as the associated namespace when the iterator access is resolved and the above implementation of the + operator is used incorrectly. To make matters worse, any error messages that may appear come from the standard library, which makes diagnosis very difficult. In the worst possible case, the compiler compiles the program without an error message, but generates the wrong program code.

Further problems are caused by implementation errors of individual compilers in the ADL resolution. The differences in the standard libraries and compilers are the reason why a program can behave differently when translating with GNU C ++ than with Microsoft Visual C ++ .

Alternatives

Other programming languages ​​such as Java or C # manage without argument-dependent name resolution. This is mainly because these programming languages ​​are more strictly object-oriented. In contrast to this, C ++ is a multi-paradigm language that does not force object-oriented work and whose standard library is based more on genericity than on object orientation.

In more strictly object-oriented languages, all user-defined types usually represent classes that Objectinherit from a common base (usually or something similar). The base class defines a basic interface that is made available by every user-defined type. The above example of input and output using standard functions is solved in these languages ​​using object orientation and virtual methods .

Current developments

Due to various formulation gaps in the C ++ standard, there have been repeated suggestions in the past as to how the current ADL mechanism could be adapted in C ++ in order to avoid unexpected behavior by the programmer as far as possible and also to improve the compatibility of different implementations.

A suggestion made by computer scientist David Abrahams in 2004 consisted of the introduction of so-called explicit namespaces in which ADL resolution should de facto be switched off or significantly restricted. Another suggestion by Herb Sutter called for certain restrictions on the ADL resolution, which were intended to maintain extensive compatibility with existing source text and at the same time eliminate the most important difficulties.

The C ++ 11 standard does not consider any of these suggestions, but defines the ADL algorithm in more detail than in earlier versions, in particular several cases are now defined in which ADL does not make sense and should not be carried out by the compiler.

Individual evidence

  1. Herb Sutter: What's In a Class? - The Interface Principle . Retrieved November 18, 2009
  2. ^ David Abrahams: Explicit Namespaces . Retrieved November 15, 2009
  3. ^ Herb Sutter: A Modest Proposal: Fixing ADL (revision 2) . (PDF; 345 kB) accessed on November 15, 2009
  4. Current draft (PDF; 10.8 MB) of the new ISO-C ++ standard ("C ++ 0x"); Retrieved November 15, 2009