Martin Nowak is officially MIA

sfp sfp at hush.ai
Thu Mar 27 22:04:53 UTC 2025


On Thursday, 27 March 2025 at 20:25:52 UTC, Walter Bright wrote:
> On 3/18/2025 11:05 PM, Manu wrote:
>> I can't imagine any good reason his experiment should have 
>> failed.
>
> My experience with C++ and Koenig lookup heavily influenced 
> this.
>
> It looks nice in simple examples, but nobody stops with simple 
> examples. Impenetrable code is the result.
>
> Operator overloading should be part of the type, not standalone 
> coming from somewhere else.

I'd like to understand what impediment there is to having "free" 
operator overloading.

It seems like once the code has been parsed/whatever, you should 
have "canonicalized" the operator syntax into some function call. 
At that point what difference does it make whether the operator 
was defined as a free function or member function? Basically, why 
would "UFCS" not also work for the canonicalized names for 
overloaded operators?

I write mathematical software for a living and forcing operators 
to be member functions sucks for me. This feature is important to 
me, so I'll try to spell this out a little bit. I realize that my 
opinion on its own doesn't carry a ton of weight; but, on the off 
chance that the main reason this feature hasn't been implemented 
is aesthetic rather than technical, I'd like to say my bit. ;-)

Main problem is that in mathematical software you want to be able 
to implement symmetric operations, and oftentimes doing this 
correctly requires double or multiple dispatch. The classic 
example is a small linear algebra with specialized types for 
different kinds of matrices.

Let's say I have a `DenseMatrix` type and a `SparseMatrix` type; 
and, who knows, maybe an `IdentityMatrix` type. If I want to 
implement a binary operation like matrix multiplication, it 
really is nice to use operator overloading for this. Maybe the 
best case scenario for the prospecting D user is doing something 
like what Eigen (a C++ template linear algebra library) does and 
lean on static polymorphism. But now I need to stick a separate 
`opBinary!"*"` on each type. As the number of types grows this 
gets significantly less maintainable. If I could define an 
operator as a free function I could lean on D's amazing 
metaprogramming capabilities and simplify my code, make it 
shorter, more maintainable, etc, etc. And, speaking from my own 
experience at least, this is not an insignificant or imagined 
benefit.

Actually, whether static polymorphism and the whole Eigen concept 
makes sense is totally debatable (at least for Eigen, the runtime 
efficiency gained by expression templates is completely obviated 
by the insane compile times... but this is a C++ library...). In 
many cases runtime polymorphism may be preferable. Unfortunately, 
D's `class` is straight out since it doesn't support multiple 
dispatch. And, anyway, the same issue discussed in the previous 
paragraph persists. A way to get around this is to use 
metaprogramming and `struct` to build up bespoke "interface" 
types that *do* support multiple dispatch (which is what I'm 
doing... -_-), but... well, I'll just say this also runs into 
trouble with non-free operator definitions.

A way around this problem that does work but isn't particularly 
satisfying is to kiss operator overloading goodbye. Just use 
`mul` for matrix multiplication. There's a good chance this is 
what I'll end up having to do.

And, in fact, I've already done it for other mathematical 
operations. I have a `ccomb(x, y, t)` function which computes the 
convex combination `(1 - t)*x + t*y` for a wide variety of types 
(standard types, arbitrary precision rationals, intervals, 
vectors, whatever). Initially, I had this function defined in the 
module of each type I wanted it defined for, but it ended up 
being simpler and more natural to just define a new module 
`ccomb.d` containing all those definitions... not unlike what is 
done in MATLAB! The function `ccomb` is symmetric in `x` and `y` 
and a good implementation of it also *wants* to be symmetric. 
This symmetry would be extremely difficult to obtain if `ccomb` 
were forced to be a member function.

Maybe you can see where I'm going with this... I don't see why 
the functions defining operators should be treated any 
differently!


More information about the Digitalmars-d mailing list