Skip to content

Commit 75336e6

Browse files
committed
more doc
1 parent 1d3eb59 commit 75336e6

File tree

6 files changed

+123
-75
lines changed

6 files changed

+123
-75
lines changed

doc/modules/ROOT/examples/ast.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ struct Node {
1818
virtual ~Node() {}
1919
};
2020

21-
struct Literal : Node {
22-
explicit Literal(int value) : value(value) {}
21+
struct Variable : Node {
22+
explicit Variable(int value) : value(value) {}
2323

2424
int value;
2525
};
@@ -39,7 +39,7 @@ struct Negate : Node {
3939

4040
BOOST_OPENMETHOD(value, (virtual_ptr<Node>), int);
4141

42-
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Literal> node), int) {
42+
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Variable> node), int) {
4343
return node->value;
4444
}
4545

@@ -51,12 +51,12 @@ BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Negate> node), int) {
5151
return -value(node->child);
5252
}
5353

54-
BOOST_OPENMETHOD_CLASSES(Node, Literal, Plus, Negate);
54+
BOOST_OPENMETHOD_CLASSES(Node, Variable, Plus, Negate);
5555

5656
auto main() -> int {
5757
boost::openmethod::initialize();
5858

59-
Literal one(1), two(2);
59+
Variable one(1), two(2);
6060
Plus sum(one, two);
6161
Negate neg(sum);
6262

@@ -74,7 +74,7 @@ auto negate(virtual_ptr<Node> node) -> int {
7474

7575
auto main() -> int {
7676
// tag::final[]
77-
Literal one(1);
77+
Variable one(1);
7878
Negate neg(boost::openmethod::final_virtual_ptr(one));
7979
// end::final[]
8080

doc/modules/ROOT/examples/ast_unique_ptr.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ struct Node {
2020
virtual ~Node() {}
2121
};
2222

23-
struct Literal : Node {
24-
Literal(int value) : value(value) {}
23+
struct Variable : Node {
24+
Variable(int value) : value(value) {}
2525

2626
int value;
2727
};
@@ -41,7 +41,7 @@ struct Negate : Node {
4141

4242
BOOST_OPENMETHOD(value, (virtual_ptr<Node>), int);
4343

44-
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Literal> node), int) {
44+
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Variable> node), int) {
4545
return node->value;
4646
}
4747

@@ -53,15 +53,15 @@ BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Negate> node), int) {
5353
return -value(node->child);
5454
}
5555

56-
BOOST_OPENMETHOD_CLASSES(Node, Literal, Plus, Negate);
56+
BOOST_OPENMETHOD_CLASSES(Node, Variable, Plus, Negate);
5757

5858
auto main() -> int {
5959
boost::openmethod::initialize();
6060

6161
auto expr = make_unique_virtual<Negate>(
6262
make_unique_virtual<Plus>(
63-
make_unique_virtual<Literal>(1),
64-
make_unique_virtual<Literal>(2)));
63+
make_unique_virtual<Variable>(1),
64+
make_unique_virtual<Variable>(2)));
6565

6666
std::cout << value(expr) << "\n"; // -3
6767

doc/modules/ROOT/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
* xref:motivation.adoc[Motivation]
12
* Tutorials
23
** xref:hello_world.adoc[Hello World]
34
** xref:multiple_dispatch.adoc[Multiple Dispatch]

doc/modules/ROOT/pages/index.adoc

Lines changed: 21 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,35 @@
1-
//
2-
// Copyright (c) 2025 Jean-Louis Leroy (jean-louis.leroy@gmail.com)
3-
//
4-
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5-
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
6-
//
7-
// Official repository: https://github.com/boostorg/openmethod
8-
//
1+
= Boost.OpenMethod
92

3+
Boost.OpenMethod is a C++17 library that implements open-methods.
104

11-
# Introduction
5+
== Features
126

13-
Open-methods are similar to virtual functions, but they are not required to be
14-
members of a class. By being both free and virtual, tdoc/hello_world.adochey provide a solution to
15-
the Expression Problem:
7+
* Headers-only.
168

17-
> Given a set of types, and a set of operations on these types, is it possible
18-
to add new operations on the existing types, and new types to the existing
19-
operations, without modifying existing code?
9+
* Exception agnostic by default.
2010

21-
Open-methods also address the banana-gorilla-jungle problem:
11+
* Customization points for alternative RTTI systems, error handling, vptr
12+
placement.
2213

23-
> The problem with object-oriented languages is they’ve got all this implicit
24-
environment that they carry around with them. You wanted a banana but what you
25-
got was a gorilla holding the banana and the entire jungle. — Joe Armstrong,
26-
creator of Erlang progamming language
14+
== Requirements
2715

28-
As a bonus, open-methods can take more than one argument into account when
29-
selecting the appropriate function to call - aka multiple dispatch. For that
30-
reason, open-methods are often called multi-methods, but that term is
31-
misleading, as it suggests that the feature is useful only when multiple
32-
dispatch is needed. In reality,
33-
https://openaccess.wgtn.ac.nz/articles/thesis/Multiple_Dispatch_in_Practice/16959112/1[it
34-
has been observed] that, in large systems written in languages that support
35-
multi-methods, most methods use single-dispatch. The real benefit is in the
36-
solution to the Expression Problem.
16+
The library requires a compiler supporting at least C++17.
3717

38-
Open-methods were introduced by the Common Lisp Object System, and they are
39-
native to many languages: Clojure, Julia, Dylan, TADS, Cecil, Diesel, Nice, etc.
40-
Bjarne Stroustrup wanted open-methods in C++ almost from the beginning. In D&E
41-
he writes:
18+
== Tested Compilers
4219

43-
> I repeatedly considered a mechanism for a virtual function call based on more
44-
than one object, often called multi-methods. I rejected multi-methods with
45-
regret because I liked the idea, but couldn’t find an acceptable form under
46-
which to accept it. [...] Multi-methods is one of the interesting what-ifs of
47-
C++. Could I have designed and implemented them well enough at the time? Would
48-
their applications have been important enough to warrant the effort? What other
49-
work might have been left undone to provide the time to design and implement
50-
multi-methods? Since about 1985, I have always felt some twinge of regret for
51-
not providing multi-methods (Stroustrup, 1994, The Design and Evolution of
52-
C{plus}{plus}, 13.8).
20+
Boost.OpenMethod has been tested with the following compilers:
5321

54-
Circa 2007, he and his PhD students Peter Pirkelbauer and Yuriy Solodkyy wrote a
55-
series of papers and a prototype implementation based on the EDG compiler.
56-
Unfortunately, open-methods never made it into the standard. Stroustrup bemoans,
57-
in a more recent paper:
22+
* clang: 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
23+
* gcc: 8, 9, 10, 11, 12, 13, 14, 15
24+
* msvc: 14.3
5825

59-
> In retrospect, I don’t think that the object-oriented notation (e.g., x.f(y))
60-
should ever have been introduced. The traditional mathematical notation f(x,y)
61-
is sufficient. As a side benefit, the mathematical notation would naturally have
62-
given us multi-methods, thereby saving us from the visitor pattern workaround
63-
(Stroustrup, 2020, Thriving in a Crowded and ChangingWorld: C++ 2006–2020).
26+
== Quality Assurance
6427

65-
This library implements the features described in the
66-
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2216.pdf[N2216 paper],
67-
with some extensions:
28+
The development infrastructure for the library includes these per-commit
29+
analyses:
6830

69-
* a mechanism for calling the next most specialized overrider
31+
* Coverage reports
32+
* Clang sanitizers
33+
* Compilation and tests on Drone.io and GitHub Actions
7034

71-
* support for smart pointers
72-
73-
* customization points for RTTI, error handling, tracing, smart pointers...
74-
75-
Multiple and virtual inheritance are supported, with the exception of repeated
76-
inheritance.
35+
== Acknowledgments
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
2+
## Motivation
3+
4+
Consider a class hierarchy that represents and evaluates arithmetic expressions:
5+
6+
[source,cpp]
7+
----
8+
include::{examplesdir}/ast_virtual_function.cpp[tag=all]
9+
----
10+
11+
We want to add a new operation that prints the expression in postfix notation.
12+
13+
14+
How do we do it?
15+
16+
There is a simple way: add a new virtual function:
17+
18+
[source,cpp]
19+
----
20+
struct Node {
21+
// as before
22+
virtual void postfix(std::ostream& os) const = 0;
23+
};
24+
25+
struct Variable : Node {
26+
// as before
27+
virtual void postfix(std::ostream& os) const override { os << v; }
28+
};
29+
30+
struct Plus : Node {
31+
// as before
32+
void postfix(std::ostream& os) const override {
33+
left.postfix(os); os << ' '; right.postfix(os); os << " +";
34+
}
35+
};
36+
37+
struct Times : Node {
38+
// as before
39+
void postfix(std::ostream& os) const override {
40+
left.postfix(os); os << ' '; right.postfix(os); os << " *";
41+
}
42+
};
43+
44+
int main() {
45+
Variable a{2}, b{3}, c{4};
46+
Plus d{a, b}; Times e{d, c};
47+
e.postfix(std::cout);
48+
std::cout << " = " << e.value() << "\n"; // prints "20"
49+
}
50+
----
51+
52+
If the classes are part of a small, self-contained program, this may be the
53+
reasonable solution. Otherwise, there are serious problems with this approach.
54+
55+
* We need to modify all the classes in the hierarchy, which may be
56+
numerous and spread across multiple files, in a real program. This assumes that we have access to their source code.
57+
58+
* We need to recompile all the files that use the Node classes, because the
59+
layout of their virtual function tables (v-tables) has changed.
60+
61+
* If the Node classes put in a library, and used in several programs, they all
62+
pull all the overriders of the `postfix` function, even if they don't use
63+
`postfix` at all.
64+
65+
* They also pull `postfix`{empty}'s transitive dependencies, in this case `std::ostream`, locales, facets, exceptions, etc.
66+
67+
In C++, this problem is often handled via the Visitor design pattern. We may
68+
still need to modify Node to equip it with Visitor support, but once that is
69+
done, we can add all the operations we want, albeit in a clumsy fashion. Sadly,
70+
it is now difficult to add new _Node_ classes, because we have to modify the
71+
Visitor's interface, and all its implementations, and recompile all the files
72+
that use the Visitor.
73+
74+
Paul Graham said that design patterns are essentially workarounds for features
75+
that are missing in less expressive languages. Indeed, in some languages, our
76+
problem does not even exist. C# has extension classes. Lisp, Clojure, Dylan,
77+
Julia, Cecil, TADS, and others, have multi-methods.
78+
79+
But wait! What do multi-methods have to do with this problem? There is no
80+
multiple dispatch going on here! The thing is, "multi-methods" is not a very
81+
good name. In this document, we will use the term "open-methods" instead (or
82+
just "methods").
83+
84+
An open-method is like a virtual function, but it exists outside of a class, as
85+
a free-standing function. We can create all the open-methods we need, without
86+
ever needing to modify existing classes.
87+
88+
This library implements open-methods for C++17 and above.

doc/openmethod.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Jean-Louis Leroy
1212

1313
:leveloffset: +1
1414

15-
include::introduction.adoc[]
15+
include::motivation.adoc[]
1616
include::tutorial.adoc[]
1717
include::reference.adoc[]
1818

0 commit comments

Comments
 (0)