D Mixin Templates

Moderator: GZDoom Developers

Post Reply
User avatar
Major Cooke
Posts: 8175
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

D Mixin Templates

Post by Major Cooke »

There was discussion on discord about potential ability to have mixin templates.

In D they look like this:

Code: Select all

mixin template Foo()
{
    void func() { writeln("Foo.func()"); }
}

class Bar
{
    mixin Foo;
}

class Code : Bar
{
    override void func() { writeln("Code.func()"); }
}
And in ZScript they'd probably be like this (example by phantombeta):

Code: Select all

template mixin Foo {
    int phoo;
    Actor bar;
}

extend class Actor {
    mixin Foo;
}

extend class PSprite {
    mixin Foo;
}

extend class BaseStatusBar {
    mixin Foo;
}
Phantombeta said it's possible.
Last edited by Major Cooke on Thu Oct 24, 2019 12:21 pm, edited 2 times in total.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49067
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: D Mixin Templates

Post by Graf Zahl »

Possible, sure - but don't exer expect those mixin blocks to be accessible through generic object pointers. The only way this could possibly work would be to call a lookup function for each access to such a variable. You also need to find someone willing to code this...
User avatar
phantombeta
Posts: 2088
Joined: Thu May 02, 2013 1:27 am
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: Brazil

Re: D Mixin Templates

Post by phantombeta »

Graf Zahl wrote:Possible, sure - but don't exer expect those mixin blocks to be accessible through generic object pointers. The only way this could possibly work would be to call a lookup function for each access to such a variable. You also need to find someone willing to code this...
I'm the one who started discussion of such a feature in the Discord, and I'd be very much willing to code it :P (just as I would be very much willing to add a lot of stuff from D 👀)
Do note that the point of it is just to avoid code duplication. The actual replacement would be lexical/AST-level. Basically, kinda like a macro, but without the gross issues caused by macros being textual/token-level replacement.
User avatar
Major Cooke
Posts: 8175
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

Re: D Mixin Templates

Post by Major Cooke »

Graf Zahl wrote:don't exer expect those mixin blocks to be accessible through generic object pointers.
If you mean like foo.phoo and foo.bar, yeah, I would expect it just to be phoo and bar by themselves.
User avatar
phantombeta
Posts: 2088
Joined: Thu May 02, 2013 1:27 am
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: Brazil

Re: D Mixin Templates

Post by phantombeta »

Oh yeah: Graf, would you be opposed to adding templates? Even just class templates would be quite useful. Wouldn't be too useful for arrays and maps, unfortunately (since those have to map to the internal TArray template), but still pretty useful for mods and libraries.
I have some idea on how they could be added (I think it'd be somewhat similar to how mixins would be done), and I would be very much willing to add them too.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49067
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: D Mixin Templates

Post by Graf Zahl »

If you think you can pull it off, go ahead.
Gez
 
 
Posts: 17835
Joined: Fri Jul 06, 2007 3:22 pm

Re: D Mixin Templates

Post by Gez »

Major Cooke wrote:There was discussion on discord about potential ability to have mixin templates.

In D they look like this:

Code: Select all

mixin template Foo()
{
    void func() { writeln("Foo.func()"); }
}

class Bar
{
    mixin Foo;
}

class Code : Bar
{
    override void func() { writeln("Code.func()"); }
}
What if:

Code: Select all

mixin template Foo()
{
    void func() { writeln("Foo.func()"); }
}

mixin template Bar()
{
    void func() { writeln("Bar.func()"); }
}

class Baz
{
    mixin Foo;
    mixin Bar;
}
:?:
User avatar
Major Cooke
Posts: 8175
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

Re: D Mixin Templates

Post by Major Cooke »

That would also be the point of it.
User avatar
phantombeta
Posts: 2088
Joined: Thu May 02, 2013 1:27 am
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: Brazil

Re: D Mixin Templates

Post by phantombeta »

No, that's a compile-time error. Remember, you'd access them as "Baz.func()", so it can't work like that.
Thst reminds me, ZScript (correctly) errors out if you redefine something in the same class it was defined in, but if you try it from inheriting classes, it silently lets you redefine things. This seems to be a quirk of how the compiler resolves inheritance, and IIRC there's a bug report of this that shows it working in some very specific cases
User avatar
phantombeta
Posts: 2088
Joined: Thu May 02, 2013 1:27 am
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: Brazil

Re: D Mixin Templates

Post by phantombeta »

Ugh, I may have severely underestimated how much of a pain it'd be to add this to the Lemon file. Ughhhhhhh.
*headdesks*

Also, one thing I forgot is that, unlike D, there's lots of things you can put into class bodies that you can't put into function bodies and vice versa. So this needs slightly different syntax.
The syntax should be something like this:

Code: Select all

// Can be present in classes, structs and functions, less specialized, only allows things all three of those can do.
mixin Foo {
    int foo;
    int bar = 1; // Syntax error. Classes and structs can't initialize things like this.
    void func () { [...] } // Syntax error. Methods can't be nested.
}

// Can be present in classes and structs. More specialized, allows everything both structs and classes can do.
mixin type Bar {
    // Allowed:
    int foo;
    void func () { [...] }
    enum blah { fuck = 1 }
    const A_Number = 1337;
}

// Can only be used in class bodies
mixin class Bar {
    int foo;
    int bar = 0; // Syntax error. Classes can't initialize variables like this.
}
and so on.
Or we could do something like checking if the mixin can be used in that context, but that basically requires manually checking for syntax errors after the parsing is already done.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49067
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: D Mixin Templates

Post by Graf Zahl »

What do you want to do with mixins in functions? Those are ten times more complicated than structs or classes. You also cannot initialize class members in the class body, there is no backing implementation for that. Keep it simple at first, if you want too much at once it won't end well.
User avatar
phantombeta
Posts: 2088
Joined: Thu May 02, 2013 1:27 am
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: Brazil

Re: D Mixin Templates

Post by phantombeta »

Added for classes. Can be easily extended to structs with just some copy-paste work, but I can't be bothered - ZScript structs are so janky and full of bugs that I'd say they're not that useful in 99% of the cases where you'd want to use a struct.
Example code:

Code: Select all

version "4.2"

class TestActor1 : Actor {
    int foo;
    mixin ItBeAMixin;
    int bar;

    override void Tick () {
        foo++;
        bar = EnumConst_C;
        Console.Printf ("foo: %d, margarine: %d, bar: %d, actorPtr: %d", foo, ICantBelieveItsNotButter, bar, !!actorPtr);
    }
}

class TestActor2 : Actor {
    int foo;
    int bar;
    mixin ItBeAMixin;

    default {
        +TestActor2.FLAGGY
    }

    states {
    Spawn:
        BAL1 A 1;
        loop;
    }

    override void PostBeginPlay () {
        Super.PostBeginPlay ();
        bar = 1;
        actorPtr = self;
    }

    override void Tick () {
        foo = EnumConst_B;
        bar *= 2;
        Console.Printf ("foo: %d, margarine: %d, bar: %d, actorPtr: %d", foo, ICantBelieveItsNotButter, bar, !!actorPtr);
    }
}

mixin class ItBeAMixin {
    enum ItsAnEnum {
        EnumConst_A,
        EnumConst_B,
        EnumConst_C,
    };

    Actor actorPtr;
    int ICantBelieveItsNotButter;

    flagdef FLAGGY: ICantBelieveItsNotButter, 0;

    default {
        +SOLID
        +ISMONSTER
        // Can't set FLAGGY here, as it'll have the class' identifier and we can't know that in advance.
    }

    states {
    Spawn:
        TROO A 1;
        loop;
    }
}
Graf Zahl wrote:What do you want to do with mixins in functions? Those are ten times more complicated than structs or classes.
Mixins could be useful for functions too. For example, if you have a long loop that's the same in two different functions, but can't be moved to a third function for some reason.
Graf Zahl wrote:You also cannot initialize class members in the class body, there is no backing implementation for that. Keep it simple at first, if you want too much at once it won't end well.
Hm? As the comments in the example code say, that would be a syntax error if used for anything other than a "mixin function" block.

By the way... Wow. There's a TON of places to change if you want to add new tokens to the parser. I feel like stuff like that should be documented somewhere...
Post Reply

Return to “Closed Feature Suggestions [GZDoom]”