
Dmitry - thanks for being the review manager for this library, and Jean-Louis - thanks for submitting it! I am the technical writer for the C++ Alliance, and have only reviewed the documentation. *Review of OpenMethod library documentation* The documentation falls short in a number of key areas that I try to address in this review. It is good that there is enough information to provide detailed feedback. Currently though the documentation would get a "D" - not a pass mark - a decent base but requires work. INTRODUCTION An introduction to a library should be suitable for developers who are not familiar with the role of open methods. They should already be decent C++ developers. The goal of an introduction is to answer the question - "why should I be interested in this?". I suggest something like this: Open methods are a language mechanism that allows you to define new behaviors (essentially, methods) for existing types *without *modifying those types. C++ doesn't natively support open methods in the way that some dynamic languages (like Common Lisp) do. Keys to the purpose of open methods are the *Open/Closed Principle* (OCP) - where a software entity (class, module, function, etc.) should be *open *for extension but *closed *for modification - and the more complicated concept of *multiple dispatch*. In *single** dispatch* method resolution is based on the runtime type of a single object, usually the one the method is called on. With multiple dispatch method resolution is based on the runtime types of two or more arguments. C++ supports single dispatch via virtual functions, multiple dispatch has to be simulated and is coded into this library. The main advantage of open methods is that they help prevent bugs when modifying stable code. For example, say you have a stable text processor. When a new file format becomes popular (say, a variant of markdown), your code can be extended to support the new format without modifying the existing code. In simple terms, *open methods allow for safer scaling of software*. Another specific use is you can add behavior involving multiple types, for example adding collision handling between type `A` and type `B` that is to date unsupported in your code. Say you had a simulation of watercraft, but had not supported hovercraft. You now add hovercraft, and need to add collision detection, and the effects of the collision to both parties, but would prefer to do this without modifying your existing codebase. This is where multiple dispatch is useful - both as a concept and a feature. This introduction describes two use-cases that are easy to understand and can now be referenced later in the documentation as needed to clarify details. Of course, there may be better use-cases than those I have described here. The current introduction is interesting, but perhaps should be under a secondary heading "History of Open Methods" that follows the intro. To be clear - does the library implement ALL the features of the N2216 paper - if not all, then list those implemented. It is not a good idea to require a reader reference documentation outside of the library for essential knowledge. The N2216 paper is long and heavy-going, but as it's not in our control the link could break during the lifetime of the library (say, 5 to 15 years). It is totally OK to provide references, though expect some reference links to break as time passes. *Required information should be in the library doc*. A kinda nit - this is funny "You wanted a banana but what you got was a gorilla holding the banana and the entire jungle." - but - is it really true? If you have a class Banana - how do you get the gorilla and jungle - wouldn't it be the other way around (jungle inherits animals, trees, trees inherit fruit etc)? However, if this is true, perhaps give an example to show how it is a problem? GETTING STARTED Following the introduction, there should be a *Getting Started* section which goes over 1) Requirements 2) Steps to install 3) Dependencies (Boost libs, std libs, other libs, etc.) 4) hello world tutorial. Getting up and running should come before Tutorials. PERFORMANCE Perhaps add a table of performance of some sort that readers can relate to - say, comparing an open method to a class method with both doing the same thing. TUTORIALS Great that there is a range of tutorials addressing the worth of open methods. However, they are not really tutorials unless they contain steps for the reader to follow. Step 1 - copy and paste this example. Step 2 - run it and examine the output, Step 3 - add this feature and run again. Step 4 - notice how the output has changed...etc. etc. It would be most useful if the tutorials related to the use-cases first introduced, showing how the desired results are achieved. It is not clear enough what the library does, versus what the sample source code does. Great tutorials have well commented code - ideally you can follow the code flow by reading the comments. TERMS and ACRONYMS Acronyms are introduced that I am unaware of, without an initial explanation. For example, Unlike function declarations, which can occur multiple times in a TU, an overrider declaration cannot. What is a TU? Can this be defined in full on first use? Similar for ADL, AST, CRTP etc. And for terms such as "guide function" - add a definition on first use. REFERENCE If all the components of the library are listed here, great, a reference should be *complete*. I would really like to see the Reference further divided into sections based on type: * Classes ** fields ** methods * Interfaces * Structures * Constants * Macros * Functions (if external to any class) - Currently we have to examine each entry, or guess (I don't like guessing) what each entry is. The biggest missing component though is the "why" (the use-case) - the *Description *of each entry should say in what situation you would be interested in this construct - or to put it another way - what problem does having this solve - or help with ? If references are arranged alphabetically within each section (Classes, Macros etc.) - they are easy to locate. ERRORS and EXCEPTIONS It is not clear to me what errors or exceptions might be thrown by any of the entries. All errors/exceptions thrown by the library code should be listed under the entry that might fire them. For maximum usefulness, include a table of errors and exceptions and* what you should do about it if you get such an error* could be described too - say likely causes and likely resolutions. A complete structured Reference, with descriptions, return values, use cases and errors would be great to see. ACKNOWLEDGEMENTS, REFERENCES The documentation could end with any acknowledgements (designers, testers, motivators) and References such as N2216 and no doubt others. *In Summary:* I had to refer to too much information outside of the library doc to get a basic understanding of the use-cases and problems that are being addressed here. The documentation as it stands describes what the code does but almost entirely from an inward looking perspective and almost never addresses the "when I should use this" from a use-case - or more likely a component of a use-case - perspective. Keys to necessary improvements would be: 1. an introduction explaining the "why I should be interested" with some compelling use-cases. The more relatable the use-cases, the more interest and users you will get. 2. step by step tutorials showing how the concepts of open methods solve problems 3. structured and complete reference *Bonus Points* 1. As open methods would often be added to existing software, are there *Best Practices* on how to design and implement code so that the addition of open methods at a later date is as seamless as can be? If so, add a section entitled Best Practices before the Reference. This would be a good place to reference external books or papers or articles if they are useful. 2. Are there other Boost libraries that play well with OpenMethods - even if you have limited experience of this a start would be helpful. *Having said all this - the case for open methods is quite strong, from the safer scalability of software perspective in particular, and I hope my 2c is useful.* *-* thanks *Peter Turcan* On Tue, Apr 29, 2025 at 12:49 PM Ruben Perez via Boost < boost@lists.boost.org> wrote:
On Tue, 29 Apr 2025 at 18:30, Ruben Perez <rubenperez038@gmail.com> wrote:
On Sun, 27 Apr 2025 at 15:15, Дмитрий Архипов via Boost <boost@lists.boost.org> wrote:
Dear Boost community. The peer review of the proposed Boost.OpenMethod
will
start on 28th of April and continue until May 7th. OpenMethods implements open methods in C++. Those are "virtual functions" defined outside of classes. They allow avoiding god classes, and visitors and provide a solution to the Expression Problem, and the banana-gorilla-jungle problem. They also support multiple dispatch. This library implements most of Stroustrup's multimethods proposal, with some new features, like customization points and inter-operability with smart pointers. And despite all that open-method calls are fast - on par with native virtual functions. [...] * What is your evaluation of the implementation?
I've seen that many of the macros use __COUNTER__ to generate unique identifiers. If I'm reading this correctly, this includes BOOST_OPENMETHOD_DECLARE_OVERRIDER and BOOST_OPENMETHOD_INLINE_OVERRIDE, which are supposed to be safe to be placed in headers. Is this correct?
I've had bad experiences with macros using __COUNTER__ in headers in the past. boost/asio/coroutine.hpp, which simulates coroutines using switch/cases, uses __COUNTER__. Placing such constructs in headers can inadvertently yield ODR violations. In my case, the ODR violation went like this:
// header1 void f1() { BOOST_ASIO_CORO_REENTER(...) { ... } // Internally uses __COUNTER__ }
// header2 void f2() { BOOST_ASIO_CORO_REENTER(...) { ... } // Internally uses __COUNTER__ }
// f1.cpp #include "header1.hpp" // __COUNTER__ here is 0 #include "header2.hpp" // __COUNTER__ here is 1
// f2.cpp #include "header2.hpp" // __COUNTER__ here is 0 #include "header1.hpp" // __COUNTER__ here is 1
This makes f1() and f2() have distinct bodies in f1.cpp and f2.cpp, which is an ODR violation. It caused random test failures under MSVC in Release mode only, and it took me forever to identify the root cause of the issue.
Are the macros I mention also vulnerable to this problem?
Answering my own question: no, they are not because the generated symbols have always static linkage. If used in headers as shown above, several, potentially differently named symbols will be generated, but that's okay since re-registering stuff multiple times seems to be a no-op.
Cheers, Ruben.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost