Search code examples
typescastingdalias

Adding a user-defined property to all types in D


I'm using Derelict for my OpenGL work, and I'm tired of having to cast(GLvoid*) Vec3.sizeof all the time for funclions like glVertexAttribPointer. So I thought I'd make a function, glsizeof

import std.stdio;

alias void GLvoid;

struct Vec3 {
    float x, y, z;
}

GLvoid* glsizeof(T)(T t) {
    return cast(GLvoid*) t.sizeof;
}

void main() {

    Vec3 vec = { x: 2.5, y: 4.8, z: 3.2 };

    writeln(cast(GLvoid*) vec.sizeof);  // prints 'C'
    writeln(cast(GLvoid*) Vec3.sizeof); // prints 'C'
    writeln(cast(GLvoid*) int.sizeof);  // prints '4'


    // Now to try using glsizeof :)

    GLvoid* size_vec  = vec.glsizeof;   // call glsizeof using a uniform function call
    GLvoid* size_vec3 = Vec3.glsizeof;
    GLvoid* size_int  = int.glsizeof;

    writeln(size_vec);  // should print 'C'
    writeln(size_vec3); // should print 'C'
    writeln(size_int);  // should print '4'
}

I get this error:

test.d(25): Error: no property 'glsizeof' for type 'Vec3'
test.d(26): Error: no property 'glsizeof' for type 'int'

Is there a way to add properties to types? Or can I do this another way, for example with an alias? Or is what I'm trying to do impossible?

Here's the code on DPaste.

Edit: added some more detail on my expected output.


Solution

  • Short answer: no. You can't pass types to functions, only templates, and if you want to add a property to something, you need to declare a property function.

    However, since you can pass a type to a template, you can declare

    template glsizeof(T)
    {
        enum glsizeof = cast(GLvoid*)T.sizeof;
    }
    

    and then you can do

    GLvoid* size_vec3 = glsizeof!Vec3;
    GLvoid* size_int  = glsizeof!int;
    

    So, as long as you're not picky about using the syntax Type.glsizeof, you have a solution. If you are picky about it, then sorry, but you're out of luck. You could define glsizeof for every type that you define. e.g.

    struct S
    {
        enum glsizeof = cast(GLvoid*)S.sizeof;
    }
    

    but that won't work for any types that you don't define, including the built-in types.