<div dir="ltr">Manu, is this that you want?<div><br></div><div><div><div>class C</div><div>{</div><div>    int foo() { printf("invoke C.foo()\n"); return 1; }</div><div>    int bar() { printf("invoke C.bar()\n"); return 2; }</div>
<div>    int bar(string s) { printf("invoke C.bar(string)\n"); return s.length; }</div><div>}</div><div>class D : C</div><div>{</div><div>    override int foo() { printf("invoke D.func\n"); return 4; }</div>
<div>}</div><div><br></div><div>void main()</div><div>{</div><div>    D d = new D();</div><div><br></div><div>    MemFunPtr!C.foo!() fpFoo = d;</div><div>    MemFunPtr!C.bar!() fpBar = d;</div><div>    MemFunPtr!C.bar!(string) fpBar2 = d;</div>
<div><br></div><div>    assert(fpFoo() == 4);</div><div>    assert(fpBar() == 2);</div><div>    assert(fpBar2("hello") == 5);</div><div><br></div><div>    static assert(fpFoo.sizeof == (void*).sizeof);</div><div>
}</div><div><br></div><div>// ---------------------</div><div>// Implementation</div><div>// ---------------------</div><div><br></div><div>import std.traits, std.typetuple;</div><div><br></div><div>template MemFunPtr(C) if (is(C == class))</div>
<div>{</div><div>    mixin GenName!C;</div><div>}</div><div>mixin template GenName(C, size_t i = 0)</div><div>{</div><div>    alias names = allMembers!C;</div><div>    static if (i >= names.length)</div><div>    {</div>
<div>        /* do nothing */</div><div>    }</div><div>    else</div><div>    {</div><div>        enum name = names[i];</div><div>        alias vfuncs = TypeTuple!(__traits(getVirtualFunctions, C, name));</div><div>        static if (vfuncs.length > 0)</div>
<div>        {</div><div>            struct _Impl(Params...)</div><div>            {</div><div>            private:</div><div>                C obj;</div><div>                alias VtblEntry = GetVtblEntry!(C, name, Params);</div>
<div>            private:</div><div>                this(C obj) { this.obj = obj; }</div><div><br></div><div>                auto ref opCall(Params args)</div><div>                {</div><div>                    alias R = ReturnType!(VtblEntry.func);</div>
<div><br></div><div>                    R delegate(Params) dg;</div><div>                    dg.ptr = *cast(void**)&obj;</div><div>                    dg.funcptr = cast(R function(Params))obj.__vptr[VtblEntry.vindex];</div>
<div>                    return dg(args);</div><div>                }</div><div>            }</div><div>            mixin("alias _Impl "~name~";");</div><div>        }</div><div>        mixin .GenName!(C, i + 1);</div>
<div>    }</div><div>}</div><div>template GetVtblEntry(C, string name, Params...)</div><div>{</div><div>    alias names = allMembers!C;</div><div>    template Impl(size_t ofs, size_t i)</div><div>    {</div><div>        alias vfuncs = TypeTuple!(__traits(getVirtualFunctions, C, names[i]));</div>
<div>        static if (names[i] != name)</div><div>        {</div><div>            alias Impl = Impl!(ofs + vfuncs.length, i + 1);</div><div>        }</div><div>        else</div><div>        {</div><div>            static assert(vfuncs.length > 0);</div>
<div>            template Impl2(size_t j)</div><div>            {</div><div>                static if (is(ParameterTypeTuple!(vfuncs[j]) == Params))</div><div>                {</div><div>                    enum vindex = ofs + j;</div>
<div>                    alias func = vfuncs[j];</div><div>                }</div><div>                else</div><div>                    alias Impl2 = Impl2!(j + 1);</div><div>            }</div><div>            alias Impl = Impl2!(0);</div>
<div>        }</div><div>    }</div><div>    alias GetVtblEntry = Impl!(1/*vtbl[0] == TypeInfo*/, 0);</div><div>}</div><div><br></div><div>template baseMembers(BC...)</div><div>{</div><div>    static if (BC.length > 1)</div>
<div>    {</div><div>        alias baseMembers =</div><div>            TypeTuple!( allMembers!(BC[0]),</div><div>                        baseMembers!(BC[1 .. $]) );</div><div>    }</div><div>    else static if (BC.length == 1)</div>
<div>    {</div><div>        alias baseMembers = allMembers!(BC[0]);</div><div>    }</div><div>    else</div><div>        alias baseMembers = TypeTuple!();</div><div>}</div><div>template derivedMembers(C)</div><div>{</div>
<div>    alias derivedMembers =</div><div>        TypeTuple!( __traits(derivedMembers, C) );</div><div>}</div><div>template allMembers(C)</div><div>{</div><div>    alias allMembers =</div><div>        TypeTuple!( baseMembers!(BaseClassesTuple!C),</div>
<div>                    __traits(derivedMembers, C) );</div><div>}</div></div></div><div><br></div><div>Kenji Hara</div><div class="gmail_extra"><br><br><div class="gmail_quote">2013/6/8 Manu <span dir="ltr"><<a href="mailto:turkeyman@gmail.com" target="_blank">turkeyman@gmail.com</a>></span><br>
<blockquote class="gmail_quote" style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr">
So from my dconf talk, I detailed a nasty hack to handle member function pointers in D.<div>My approach is not portable, so I'd like to see an expression formalised in D, so this sort of interaction with C++ is possible, and also it may be useful in D code directly.<div>

<br></div><div>I'm thinking something like this... Keen to hear thoughts.</div></div><div><br></div><div>My approach was this:</div><div>  void function(T _this, ...args...);<br></div><div>
<br></div><div>Explicit 'this' pointer; only works with ABI's that pass 'this' as the first integer argument.<br></div><div><br></div><div>What I suggest is:<br></div><div>  void function(T this, ...args...);<br>

</div><div><br></div><div>Note, I use keyword 'this' as the first argument. This is the key that distinguishes the expression as a member-function pointer rather than a typical function pointer. Calls through this function pointer would know to use the method calling convention rather than the static function calling convention.</div>

<div><br></div><div>For 'extern(C++) void function(T this)', that would be to use the C++ 'thiscall' convention.</div><div><br></div><div>I think this makes good sense, because other than the choice of calling convention, it really is just a 'function' in every other way.<br>

</div><div><br></div><div>Now taken this as a declaration syntax, I think calls would be made via UFCS.</div><div><br></div><div>T x;</div><div>void function(T this) mp;<br></div><div><br></div>
<div>mp(x); // I guess this is fine<br></div><div><a href="http://x.mp" target="_blank">x.mp</a>(); // but UFCS really makes this concept nice!</div><div><br></div><div>So the final detail, is how to capture one of these member function pointers from within D...</div>

<div>I initially thought about a syntax, but this is so niche, I don't think it warrants a syntax.</div><div>So my current best idea is to introduce 2 properties to delegates, so that the function pointer (of this type) can be accessed via the delegate syntax.</div>

<div><br></div><div>delegate d = &x.f;</div><div>void function(T this) mp = d.funcPtr;</div><div><br></div><div>An interesting side effect, is that 'delegate' could actually be understood as a strongly-typed small struct, whereas currently, it's just a magic thing:</div>

<div><br></div><div>Given: RT delegate(A x, B y) d = &c.m;</div><div><br></div><div>It would look like:</div><div>struct delegate(C)</div><div>{</div><div>  C thisPointer;</div>
<div>  RT function(C this, A x, B, y) funcPointer;</div><div>}</div><div><br></div><div>Currently, to get the instance or function pointers from a delegate, you need to do something like:</div><div>
delegate d;</div><div>void** pd = cast(void**)&d;</div><div>T instancePointer = cast(T)pd[0];</div><div>void function(T this) functionPointer = cast(RT function(T this))pd[1];</div><div><br></div>
<div>Casting through a void array like that is pretty horrible.</div><div>Adding 2 properties to delegate to get either of those things can makes sense once it is possible to express the type of the function pointer, which would now be possible with the syntax above.</div>

<div><br></div><div>So, I quite like the transparency introduced when a delegate can be explicitly described in the language. But there is one loose detail...</div><div><br></div><div>void f()</div>
<div>{</div><div>  void g() {}</div><div>  void delegate() d = &g; // delegate 'this' is a closure<br></div><div>}</div><div><br></div><div>I don't know a syntax to describe the type of a closure, so when a delegate is typed with a closure instead of a struct/class, what is 'C' in the struct template above?</div>

<div><br></div><div><br></div><div>Thoughts?</div><div>Is there reason to outright ban this sort of expression?</div><div>I think this actually clarifies some details of the language, and reduces a currently 'magic' thing into a well-defined, strongly-typed concept.</div>
<span class=""><font color="#888888">
<div><br></div><div>- Manu</div></font></span></div>
</blockquote></div><br></div></div>