New library: open multi-methods

Jean-Louis Leroy via Digitalmars-d-announce digitalmars-d-announce at puremagic.com
Tue Jul 18 11:34:39 PDT 2017


On Tuesday, 18 July 2017 at 16:57:30 UTC, Ali Çehreli wrote:
> > As for performance, I have a first result:
> > 
> https://github.com/jll63/methods.d/blob/master/benchmarks/source/benchmarks.d#L122
> > but I still have to implement the "first argument
> optimization". I am
> > working on it.
>
> I could use some explanation for the results but I can for the 
> blog article. ;)

I pit a method-based call against its equivalent using virtual 
functions. First calling a virtual function via a base class is 
pitted against a method with one virtual parameter. Then the same 
but calling via an interface. Lastly, I compare double dispatch 
with a method with two virtual arguments. I use 
std.datetime.comparingBenchmark, which reports the result as 
time(base)/time(target). So open methods are a bit slower than 
ordinary virtual function calls but not that much. In the 
meantime I have applied a second optimization for unary methods 
and this brings them within 33% of an ordinary, compiler 
implemented vfunc call. Which is OK because the situation is 
highly artificial. If the function does anything, the difference 
will be imperceptible.

I am more annoyed by double dispatch beating binary methods. I 
will have to look at the assembler, but it may be that the index 
pointer is too far from the object. To begin the real work, I 
need to fetch that pointer form an object. Currently it is stored 
in ClassInfo.deallocator, so I have to 1/ fetch the vptr 2/ fetch 
the ClassInfo* 3/ fetch 'deallocator'. What happens next depends 
on the arity.

Any chance of Walter giving me a pointer in the vtable? Aside the 
ClassInfo*? Or at least a pointer in ClassInfo, or reassign the 
deallocator when it is eventually retired?

> It's not surprising that ldc (and gdc) can be much better than 
> dmd in optimization.

I would like to try gdc but it conflicts with ldc2 - you know, 
the "alias __va_list = __va_list_tag;" issue. I found suggestions 
via google but nothing worked for me so far.

>
> By the way, I'm in awe of your D skills in such a short time!

Thanks :) I found out that D was much more natural, "predictable" 
than C++. The most cryptic error messages happened when I forgot 
the "!", IIRC.

> I'm sure there are parts of the code that can be cleaned up but 
> it's taking advantage of many powerful features of the 
> language. I still think the usage can be made easier but I'm 
> not sure yet. I hope others will take a look at the code and 
> come up with an easier interface. Perhaps they are all needed 
> but I'm thinking about the need for forward declaration, the 
> need for the underscore prefix, etc.

(in reverse order)

Regarding the prefix, it is needed to prevent overload resolution 
from trumping dynamic dispatch - see here: 
https://github.com/jll63/methods.d/blob/master/examples/whytheunderscore/source/app.d Allowing the same name would necessitate compiler support.

As for the the forward declaration - I don't think it is possible 
to dispense with it. All open methods systems I know of have it 
(defgeneric in CLOS, defmulti in Clojure, Stroustrup's 
proposal...). Consider:

class A { }
class B : A { }
class X : B { }
class Y : B { }

@method void _foo(virtual!X x) { ... }
@method void _foo(virtual!Y x) { ... }

What is the base method? foo(B)? foo(A)? It may well be the 
latter. Also don't forget that the complete specialization set is 
known, at the earliest, at link time. If you (arbitrarily) pick 
foo(B), another module may introduce a B or an A specialization.

As for suggestions and advise, they are very welcome :) already 
got a couple of PRs. Here are the remaining questions on my mind:

- the module/package name: I am pretty much set on openmethods 
though...

- throw an exception if a method is not define for the argument 
set, or ambiguous: having big doubts about this. We want the 
possibility of @nothrow methods, don't we? So I will probably 
call a delegate via a pointer (a la C++) which, by default, will 
abort().

- the method prefix: hesitating between just _ or maybe m_ ???

- replace version(explain) with debug levels?


More information about the Digitalmars-d-announce mailing list