:exampledir: ../example

[#basics]

An _open-method_ is a free-standing function that has one or more _virtual_
_parameters_. When it is called, it forwards to an _overrider_ selected from a
set by examining the dynamic types of the virtual parameters.

If this sounds like a virtual function, that's because an open-method
with one virtual parameter is equivalent to a virtual function - with one big
difference: it exists outside of classes.

A virtual parameter is in the form `virtual_ptr<Class>`. It is a pointer-like
class that points to an instance of `Class`. `virtual_ptr` is defined in the library's main namespace,
`boost::openmethod`.

To create an open-method that implements the `postfix` operation, we use the
xref:BOOST_OPENMETHOD.adoc[BOOST_OPENMETHOD] macro:

```c++
BOOST_OPENMETHOD(
    postfix, (virtual_ptr<const Node> node, std::ostream& os), void);
```

`postfix` is the method's name. It takes one virtual parameter, `node`, and one
non-virtual parameter, `os`. It returns `void`. The macro generates the
following function:

```c++
inline auto postfix(virtual_ptr<const Node> node, std::ostream& os) -> void {
    // examine the type of *node
    // select an overrider
    // call it
}
```

Before we can call the method, we need to define overriders. For that we use the
xref:BOOST_OPENMETHOD_OVERRIDE.adoc[BOOST_OPENMETHOD_OVERRIDE] macro:

[source,cpp]
----
include::{examplesdir}/ast.cpp[tag=variable_overrider]
----

The overrider must have virtual parameters in the same positions as in the
method. The classes in the method's virtual parameters must be accessible,
non-ambiguous bases of the classes in the overrider. Note that this rules out
repeated inheritance. Apart from this restriction, multiple and virtual
inheritance are supported.

The non-virtual parameters must have exactly the same types as in the method.

Let's look at another overrider:

[source,cpp]
----
include::{examplesdir}/ast.cpp[tag=plus_overrider]
----

This one calls `postfix` recursively to print the left and right
sub-expressions. Note that we call the method just like an ordinary function.

`postfix` expects a `virtual_ptr<const Node>`, and we are passing it a _plain_
_reference_ to a `Node` object. This works because `virtual_ptr` has conversion
constructors from plain references or pointers to objects, or from other
`virtual_ptr`{empty}s.

There are two more things we need to do.

OpenMethod is a library, not a compiler. It needs to be informed of all the
classes that may be used as virtual parameters, and in method calls, and their
inheritance relationships. We provide that information with the
xref:BOOST_OPENMETHOD_CLASSES.adoc[BOOST_OPENMETHOD_CLASSES] macro:


[source,cpp]
----
include::{examplesdir}/ast.cpp[tag=class_registration]
----

Classes can be registered multiple times, in any order, and incrementally. Every
direct base of a class must appear together with it in at least one call to
`BOOST_OPENMETHOD_CLASSES`. This enables the library to deduce the complete
inheritance lattice.

The constructs used in this example require the classes to be polymorphic, in
the standard C++ sense, i.e. they must have at least one virtual function. The
library can also be used with non-polymorphic classes, with some restrictions.

Finally, we need to call `boost::openmethod::initialize()` before the first call
to an open-method. This builds the dispatch tables used during method calls. It
is typically done once, at the very beginning of main, and requires the
inclusion of `<boost/openmethod/initialize.hpp>`.

```c++
#include <boost/openmethod/initialize.hpp>

int main() {
    boost::openmethod::initialize();
    // ...
}
```

Putting it all together:

[source,cpp]
----
include::{examplesdir}/ast.cpp[tag=content]
----
