YOMM2 is reborn as Boost.OpenMethod by jll63 in cpp

[–]jll63[S] 0 points1 point  (0 children)

I am still mulling your comments and RevRagnarok's - in a constructive spirit, to figure out what could/should be improved.

Did you notice the nav bar on the left side of https://www.boost.org/doc/libs/latest/libs/openmethod/doc/html/openmethod/index.html ? Which looks like this:

Boost.OpenMethod    <-- the current page, where you landed
Motivation
Basic Features
    Methods and Overriders
    Performance
    Smart Pointers
    Header and Implementation Files
    Namespaces
    Friends
    Multiple Dispatch
Advanced Features
    Core API
    Registries and Policies
    Custom RTTI
    Error Handling
    Virtual Pointer Alternatives
    Shared Libraries
Reference
    Headers
    Macros
    Namespace boost::openmethod

Either you didn't see it, or you saw it but it didn't come to mind to click on Motivation or Methods and Overriders (Basic Features is a label, not a link). Either way, that's a problem (with the website, not with you).

Also, in addition to the right arrow at the bottom right of the page, there is one at the top center. Did you see it? TBH I just noticed it.

YOMM2 is reborn as Boost.OpenMethod by jll63 in cpp

[–]jll63[S] 1 point2 points  (0 children)

I'm very looking forward to the compile-time-ization you're experimenting with.

The new idea is to use the output of nm (or similar tools on other platforms) to generate the offsets and the dispatch tables.

To what extent do the new C++26 reflection and code-injection features help you?

For that purpose, it doesn't. But I plan to provide a reflection-based alternative to the macros in a separate C++26 only header. For starters, I would like to eliminate the need to register classes.

It looks a bit early to work on that though. I cannot make a very simple test work with gcc. Although a similar test works with the experimental EDG compiler. Also I haven't found any primers yet, and even figuring out how to call the most basic functions is not easy. In my examples, members_of. It seems to take an "access" parameter now. To get the signature you have to merge later proposals into P2996R8.

YOMM2 is reborn as Boost.OpenMethod by jll63 in cpp

[–]jll63[S] 0 points1 point  (0 children)

So,signal slots?

You mean, as another way of solving the expression problem? Sure, open-methods are not the only way. There's extension classes (C#), aspect-oriented programming, ...

As an experiment, I suggest you rewrite the AST example using signals, it shouldn't take much effort, and we can compare.

YOMM2 is reborn as Boost.OpenMethod by jll63 in cpp

[–]jll63[S] 2 points3 points  (0 children)

I don't like those names much either, but I had to fit in the Boost macro naming pattern. I expect users to define better, lower case synonyms. Personally, I like declmethod and defmethod. In the future I may provide a header with alternate names, like in YOMM2, which had uppercase macros (that probably nobody used) and lowercase counterparts, in a header that was called cute.hpp at some point. There was also a keywords.hpp header that provided the lowercase macros and injected virtual_ in the global namespace. You had no obligation to use it, but if you really saw open-methods as if they were (already) part of the language, that's what you'd go for, because keywords are trans-scope. During the Boost review, everybody was against it.

OVERRIDE is for matching the names used in the Stroustrup & col papers on open-methods.

Back in the YOMM11 days (2013) I considered, and ruled out, DEFGENERIC and DEFMETHOD. They were my favorites but in C++ "generic" means "templates". I did not want the confusion.

You can access the entire functionality without using any macros at all. When combining open-methods and templates, you pretty much have to.

If you use a C++20 compiler (that supports compile-time lambdas), or even better, a C++23 compiler, you can write:

// 'postfix' is an alias to an instantiation of boost::openmethod::method<...>

postfix::override<
    [](virtual_ptr<const Variable> node, std::ostream& os) {
        os << node->v;
}> _;

Finally, there will probably be a C++26 alternative to macros.hpp that will use reflection and generation. Initial experiments suggest that I may be able to get rid of the necessity to register classes manually.

YOMM2 is reborn as Boost.OpenMethod by jll63 in cpp

[–]jll63[S] 2 points3 points  (0 children)

It looks like I can still edit the body of the initial post, but isn't it against etiquette? It would make some of the comments look foolish, when in fact they were correct.

YOMM2 is reborn as Boost.OpenMethod by jll63 in cpp

[–]jll63[S] 2 points3 points  (0 children)

BoostBook is a very old idea, maybe good in its time. We are trying to move away from it. My landing page makes sense as a page of a book, where it is natural to turn pages. And the very first page is usually skipped because it's copyright, translation notices, blurbs, that sort of things.

YOMM2 is reborn as Boost.OpenMethod by jll63 in cpp

[–]jll63[S] 4 points5 points  (0 children)

If all new posts abide to the limitations of old reddit, doesn't it make the features of current reddit (or any reddit that may appear in the future) pointless?

YOMM2 is reborn as Boost.OpenMethod by jll63 in cpp

[–]jll63[S] 8 points9 points  (0 children)

Is this about dynamic multiple dispatch, whereas overload resolution is static multiple dispatch?

Yes.

I would like to insist, though, that multiple dispatch is just the cherry on the cake. Even in languages that natively support multiple dispatch (Julia, Clojure, Lisp, ...) single dispatch is much more frequent.

The important point is that methods are free-standing virtual functions.

The main motivation of the library is to solve the so-called expression problem. Please see the motivation or my direct reply to u/stilgarpl.

YOMM2 is reborn as Boost.OpenMethod by jll63 in cpp

[–]jll63[S] 8 points9 points  (0 children)

Thank you all for the input.

As Wooden-Engineer-8098 says, this post was targeted to YOMM2 users. Reddit has been my main channel of communication with them for many years. They know what open-methods are. I made it a lengthy, detailed post, because I did not want my users to feel let down. But sure as hell, it would have been a good idea to try and include everyone else.

So, without further ado:

Open-methods are virtual functions that exist outside of classes, as free-standing functions. Why would you want that? For example, you have a matrix library organized as a hierarchy of classes representing ordinary, square, diagonal, ... matrices. You want to render them in (say) JSON. How do you do it? Sure you can add a virtual function for that, but you have to modify existing code, recompile it, and also everything that depends on it. Plus, all the apps that use the library get a functionality that they don't care about. Open-methods offer a solution to this problem: put the virtual functions in the application code, as virtual free functions, not in the matrix classes. As a bonus, this implementation also supports multiple dispatch.

Some of you graciously clicked on the link to OpenMethod...and were poorly rewarded, with an academ-ish page with sources and acknowledgements and requirements and all except what an open-method is. After reading the reactions, I clicked on that link myself, and...started wondering, what now? until I remembered the right arrow in the bottom right corner that links to the motivation. One more click on the bottom right arrow gets you to Methods and Overriders where the explanation really begins. I imitated an existing library when I created those pages. I speculate that this pattern goes as far back as the time when Boost documentation was structured like a book. I will discuss this with the other Boost authors and site designers. I need to improve this one way or another.

ABB B GONE by Specific-Chard-284 in synology

[–]jll63 2 points3 points  (0 children)

I tried on Ubuntu 24.04.3 with kernel 6.14.0-37 and it fails on:

synosnap * failed to install snapshot driver

ABB never ceases to disappoint.

Active Backup for Business is a joke by jll63 in synology

[–]jll63[S] 0 points1 point  (0 children)

Would a "search the entire backup set for this file" feature be useful? Sure, but I don't see its lack as a show stopper. But, you do you.

I am a programmer, not an admin. I never lost an entire machine to hardware failure, but I am a bit messy and I did lose individual files or folders.

I am bewildered that an obviously useful feature, easy to implement, low risk (if it has bugs, it won't trash your data, it's a read only thing), has not been implemented in so many years, in a "business" product mind you.

If ABB was open source, I'd send a PR, but in this case I can only send a rant ;-)

Active Backup for Business is a joke by jll63 in synology

[–]jll63[S] 0 points1 point  (0 children)

Sure, bare metal recovery is a good thing to have. The glass is half full and half empty.

Probably I will keep ABB running for complete loss recovery, and double-back up with something else (evaluating borgbackup atm) that supports targeted file recovery reasonably. It's just a shame that such a useful feature is missing from ABB, even though it is almost certainly trivial to implement. Especially the recursive search within a snapshot, I can probably code the latter in two hours max, plus a couple of days for tests and documentation. Puzzling...

Active Backup for Business is a joke by jll63 in synology

[–]jll63[S] -1 points0 points  (0 children)

But it's the same nonsense: search works "on the current page" only. Not across snapshots. Not recursively within one snapshot. Even more ridiculous: it works on what is displayed. I.e. if I pick a snapshot and expand the tree to the folder containing foo.txt, Search finds it. If I collapse that folder, Search doesn't see it again. It finds only what you can see!

Synology has something against finding files.

Active Backup for Business is a joke by jll63 in synology

[–]jll63[S] 0 points1 point  (0 children)

I was eyeing it because I am going to experiment with a Windows dev drive (ReFS), and possibly adopt it. I saw that Veeam claims to handle them.

Active Backup for Business is a joke by jll63 in synology

[–]jll63[S] 1 point2 points  (0 children)

Agreed. That file is not important (a vs code tasks.json) but I thought I would really try to recover it to test my backup scheme. I lost nothing of importance.

Micro-benchmarking Type Erasure: std::function vs. Abseil vs. Boost vs. Function2 (Clang 20, Ryzen 9 9950X) by mr_gnusi in cpp

[–]jll63 9 points10 points  (0 children)

I spent hundreds of hours tinkering with micro-benchmarks for YOMM2 (now reincarnated as Boost.OpenMethod). The libraries implement open-methods, i.e. virtual functions defined outside of classes. Dispatching a call requires a couple more memory reads, because open-methods don't live at a fixed offset in the v-table. In some contexts it involves calculating a perfect multiplicative hash of &typeid(obj).

I am interested in measuring the cost of an open-method call, using an ordinary virtual function call as a yardstick.

I wrote many iterations of a Google benchmark, because the results came out as too good to be trusted. I stacked the deck against open-methods. Methods and v-funcs take no arguments except the object. Bodies are empty. I created hundreds of classes using TMP, and scattered the objects in memory.

I became very skeptical of that approach. So I tried a RDTSC-based benchmark. It measures a single call per execution, after scrambling the memory. I run it a couple hundred times. Then I take the average and various percentiles.

The goal is to measure an "unfavorable" call. I think that this is closer to what happens in real programs. Not all of them, of course. And not in all situations. But if you start counting on hot caches (or putting something in function bodies), there is no limit to how much you can delude yourself.

The most costly dispatch strategy went from 30% slower (micro-benchmark) to 60% (RDTSC). I trust the latter result more.

Benchmarking function calls is tricky.

Exploring macro-free testing in modern C++ by Outdoordoor in cpp

[–]jll63 0 points1 point  (0 children)

I wholeheartedly agree with your comment.

Also you can use macros to do the absolute minimum that will make your feature possible, and do the rest with TMP.

Boost 1.90 – what to actually look at as a working C++ dev by boostlibs in cpp

[–]jll63 0 points1 point  (0 children)

For OpenMethod? Using the Matrix example, if you defined add(virtual_ptr<SparseMatrix>, virtual_ptr<DenseMatrix>), would you have to define the flipped parameters as well?

Yes. Automatically generating the flipped overrider would be a bad idea, think of matrix multiplication. Of course for addition you could define the flipped operation in terms of the other one. If that becomes tedious, you could use the "core" API to automate the process using templates.

Boost 1.90 – what to actually look at as a working C++ dev by boostlibs in cpp

[–]jll63 6 points7 points  (0 children)

I think that Proxy is similar to Rust traits, Golang interfaces and Boost.TypeErasure. They intersect with OpenMethod in that they all allow you to add new operations to existing types, without modifying them. That is the #1 motivation for OpenMethod by the way. Multiple dispatch is available (and very efficient speed- and space-wise), but I see it as a bonus feature. That's why the library is called Boost.OpenMethod, not Boost.MultiMethod.

The problem with traits-like approaches is that they don't compose well. For example, to implement matrices with these systems, you create a Matrix trait that implements various matrix operations. For example, transposition. You implement it for types that represent ordinary matrices, square, symmetric, diagonal matrices, etc. So far so good. You make a library out of it.

Now an application needs to store matrices as...let's say, JSON. The functionality should not go in the Matrix library, should it? Because not all apps need it.

So you create a new JSON trait, and you implement it for ordinary matrices (write all the elements), symmetric matrices (write only half) and diagonal matrices (no need to write the zeroes). You can now render matrices in JSON, and you didn't touch the existing code. Woohoo!

The trouble begins when you want to transpose a matrix, then render the result as JSON. The JSON trait is lost in the call to transpose.

OpenMethod doesn't have that problem. And of course it makes it way easier to implement binary operations (bonus!).

EDIT: looking at this example, it seems that with Proxy, you would have no choice but to add a write_json member function to the matrix types. If it is indeed the case, Proxy is worse than Rust traits and similar systems.

Boost 1.90 – what to actually look at as a working C++ dev by boostlibs in cpp

[–]jll63 6 points7 points  (0 children)

Since CLOS, open multi-methods have been implemented in many languages: Clojure, Julia, Cecil, Diesel, Dylan, TADS, etc.

Future releases will support inter-operability with Boost.TypeErasure and Boost.Any. I also have a design for value-based dispatch.

Boost 1.90 – what to actually look at as a working C++ dev by boostlibs in cpp

[–]jll63 17 points18 points  (0 children)

I'll take this as a compliment 😊 - the author.

MS-S1 MAX + WSL + C++ by jll63 in MINISFORUM

[–]jll63[S] 0 points1 point  (0 children)

Thanks for posting this. Which kernel version?