Thread overview
Cumbersome overloading of mixed-in functions
Aug 19, 2006
kris
Aug 20, 2006
nobody
Aug 20, 2006
Kristian
August 19, 2006
Say I want to add a bunch of (virtual) methods to a class.  All these methods do very similar things, just on different types.  Hmm, sounds like a job for a template.

So I write up a templated version of the method:

template FuncTemplate(T)
{
    void func(T val)
    {
        // do some stuff with val
    }
}

Now I can mix it into the class.  I have, no joke, about 10 or 15 types I want to mix this in as.  So I do this:

class Foo
{
    mixin FuncTemplate!(int);
    mixin FuncTemplate!(float);
}

Oh crap, I can't even go any further right now.  If I try to instantiate the class and call these methods:

Foo f = new Foo();
f.func(5);

I get the error:

function blah.Foo.FuncTemplate!(int).func conflicts with blah.Foo.FuncTemplate!(float).func at..

I look up in the spec, and find that it's possible to overload these functions, but it has to be done manually, using dummy mixin names and then aliasing them:

class Foo
{
    mixin FuncTemplate!(int) intFunc;
    mixin FuncTemplate!(float) floatFunc;

    alias intFunc.func func;
    alias floatFunc.func func;
}

Foo f = new Foo();
f.func(5); // yay, works

Now for the other 12 or 13 types, which means lots of namespace pollution in my class for all the dummy mixin names, and a matching alias for each mixin. And -- oh yeah, I've got 4 or 5 other methods which I want to be templated for the same set of types!

At which point my class degenerates into four pages of mixins and aliases. I might as well just copy-and-paste the functions and change the parameter type; it'd be a lot clearer.

What a mess.  There has to be a better way to do this.  I'm thinking something like

mixin func = FuncTemplate!(int).func;
mixin func = FuncTemplate!(float).func;

Kind of an all-in-one mixin/alias without any dummy names, and with a syntax similar to import renaming (and, in effect, a sort of similar effect).

Or, maybe mixin scoping could be changed so that unnamed mixins have their symbols imported into the local namespace.  After all, if you write:

mixin FuncTemplate!(int);
mixin FuncTemplate!(float);

..

f.func(4); // error, ambiguous - in both !(int) and !(float)

There is _no way_ to disambiguate it unless you use a named mixin - so why bother making it ambiguous with unnamed mixins?

Although I see this second proposal as a problem with:

template Temp(T)
{
    T x;
}

mixin Temp!(int);
mixin Temp!(float);

..

writefln(x); // ? ambiguous

Although in this case, I would imagine the normal variable declaration semantics would kick in and say that you were redefining x with the !(float) mixin.


August 19, 2006
Jarrett Billingsley wrote:
> Say I want to add a bunch of (virtual) methods to a class.  All these methods do very similar things, just on different types.  Hmm, sounds like a job for a template.
> 
> So I write up a templated version of the method:
> 
> template FuncTemplate(T)
> {
>     void func(T val)
>     {
>         // do some stuff with val
>     }
> }
> 
> Now I can mix it into the class.  I have, no joke, about 10 or 15 types I want to mix this in as.  So I do this:
> 
> class Foo
> {
>     mixin FuncTemplate!(int);
>     mixin FuncTemplate!(float);
> }
> 
> Oh crap, I can't even go any further right now.  If I try to instantiate the class and call these methods:
> 
> Foo f = new Foo();
> f.func(5);
> 
> I get the error:
> 
> function blah.Foo.FuncTemplate!(int).func conflicts with blah.Foo.FuncTemplate!(float).func at..
> 
> I look up in the spec, and find that it's possible to overload these functions, but it has to be done manually, using dummy mixin names and then aliasing them:
> 
> class Foo
> {
>     mixin FuncTemplate!(int) intFunc;
>     mixin FuncTemplate!(float) floatFunc;
> 
>     alias intFunc.func func;
>     alias floatFunc.func func;
> }
> 
> Foo f = new Foo();
> f.func(5); // yay, works
> 
> Now for the other 12 or 13 types, which means lots of namespace pollution in my class for all the dummy mixin names, and a matching alias for each mixin. And -- oh yeah, I've got 4 or 5 other methods which I want to be templated for the same set of types!
> 
> At which point my class degenerates into four pages of mixins and aliases. I might as well just copy-and-paste the functions and change the parameter type; it'd be a lot clearer.
> 
> What a mess.  There has to be a better way to do this.  I'm thinking something like
> 
> mixin func = FuncTemplate!(int).func;
> mixin func = FuncTemplate!(float).func;
> 
> Kind of an all-in-one mixin/alias without any dummy names, and with a syntax similar to import renaming (and, in effect, a sort of similar effect).
> 
> Or, maybe mixin scoping could be changed so that unnamed mixins have their symbols imported into the local namespace.  After all, if you write:
> 
> mixin FuncTemplate!(int);
> mixin FuncTemplate!(float);
> 
> ..
> 
> f.func(4); // error, ambiguous - in both !(int) and !(float)
> 
> There is _no way_ to disambiguate it unless you use a named mixin - so why bother making it ambiguous with unnamed mixins?
> 
> Although I see this second proposal as a problem with:
> 
> template Temp(T)
> {
>     T x;
> }
> 
> mixin Temp!(int);
> mixin Temp!(float);
> 
> ..
> 
> writefln(x); // ? ambiguous
> 
> Although in this case, I would imagine the normal variable declaration semantics would kick in and say that you were redefining x with the !(float) mixin. 
> 
> 


Better to do it all manually and save yourself the grief. Mixin should perhaps be removed from the language until such time that it works in a reasonable manner :(
August 20, 2006
kris wrote:
> Jarrett Billingsley wrote:
>> Say I want to add a bunch of (virtual) methods to a class.  All these methods do very similar things, just on different types.  Hmm, sounds like a job for a template.
> 
> Better to do it all manually and save yourself the grief. Mixin should perhaps be removed from the language until such time that it works in a reasonable manner :(

Just a little while ago I posed a question to D.learn about implementing all the permutations possible of RGB, HSL, RGBA and HSLA. The numbers from that post:

    3! + 3! + 4! + 4! = 60 types
   (3! + 3! + 4! + 4!)^2 = 3600 opAssigns

Certainly manually is not really an option here.
August 20, 2006
nobody wrote:
> kris wrote:
> 
>> Jarrett Billingsley wrote:
>>
>>> Say I want to add a bunch of (virtual) methods to a class.  All these methods do very similar things, just on different types.  Hmm, sounds like a job for a template.
>>
>>
>> Better to do it all manually and save yourself the grief. Mixin should perhaps be removed from the language until such time that it works in a reasonable manner :(
> 
> 
> Just a little while ago I posed a question to D.learn about implementing all the permutations possible of RGB, HSL, RGBA and HSLA. The numbers from that post:
> 
>     3! + 3! + 4! + 4! = 60 types
>    (3! + 3! + 4! + 4!)^2 = 3600 opAssigns
> 
> Certainly manually is not really an option here.

Right now, in cases such as this, the best option seems to be writing a simple source generator to cough up the code into a file.  Usually the time/energy spent writing the generator program is reasonably less than manually typing them all out.

-- Chris Nicholson-Sauls
August 20, 2006
On Sun, 20 Aug 2006 11:40:24 +0300, Chris Nicholson-Sauls <ibisbasenji@gmail.com> wrote:

> nobody wrote:
>> kris wrote:
>>
>>> Jarrett Billingsley wrote:
>>>
>>>> Say I want to add a bunch of (virtual) methods to a class.  All these methods do very similar things, just on different types.  Hmm, sounds like a job for a template.
>>>
>>>
>>> Better to do it all manually and save yourself the grief. Mixin should perhaps be removed from the language until such time that it works in a reasonable manner :(
>>   Just a little while ago I posed a question to D.learn about implementing all the permutations possible of RGB, HSL, RGBA and HSLA. The numbers from that post:
>>      3! + 3! + 4! + 4! = 60 types
>>    (3! + 3! + 4! + 4!)^2 = 3600 opAssigns
>>  Certainly manually is not really an option here.
>
> Right now, in cases such as this, the best option seems to be writing a simple source generator to cough up the code into a file.  Usually the time/energy spent writing the generator program is reasonably less than manually typing them all out.
>
> -- Chris Nicholson-Sauls


Hmm, why the mixin does not simply generate/add the code, which is then compiled normally with the original code? Similarly like macros work in C/C++. This way there would be no naming conficts with function overloads as Jarrett described earlier, for instance. The compiler knows when it compiles the mixin code so the corresponging error messages can be generated, etc.

I would very much like to see mixins working properly. It would be a great asset for D if there were a good code generator ability!