www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 7897] New: Problem with alias template parameter

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7897

           Summary: Problem with alias template parameter
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: turkeyman gmail.com



I've boiled this down as much as I can. My use case isn't clearly reflected
here (significantly more complex).



import std.traits;

struct ExternFunction
{
    string name;
    void* pFunction;
}


// loose function
extern(C) void function() globalFunction;

// functions contained in a struct
struct Debug
{
    extern(C) void function( const char* format, ... ) outputDebug;
}
__gshared Debug d;


void main()
{
    const(ExternFunction)* pImports = null;

    // register loose function is okay
    HookupEngineFunction!( globalFunction )( pImports );

    // register function in struct (doesn't work, won't take alias for some
reason?)
    HookupEngineFunction!( d.outputDebug )( pImports );

    // register whole struct (fails via internal call to the function above,
but with a different complaint)
    HookupEngineModule!( d )( pImports );
}

private:

// hook up a struct full of callback pointers
void HookupEngineModule( alias s )( const(ExternFunction)* pImports )
{
    // iterate struct members
    foreach( m; __traits( allMembers, typeof( s ) ) )
    {
        // !!! getMember doesn't work here...
        HookupEngineFunction!( __traits( getMember, s, m ) )( pImports );
    }
}


void HookupEngineFunction( alias funcptr )( const(ExternFunction)* pImports )
{
    alias typeof( funcptr ) Type;

    static if( isFunctionPointer!Type )
    {
        const(ExternFunction)* pExtern = pImports; // FindImport(...);

        funcptr = cast(Type)pExtern.pFunction;
    }
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Apr 13 2012
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7897


Walter Bright <bugzilla digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bugzilla digitalmars.com



11:44:45 PDT ---
======
    // register function in struct (doesn't work, won't take alias for some
reason?)
    HookupEngineFunction!( d.outputDebug )( pImports );
======

This is failing to compile because outputDebug is a non-static member function
of struct Debug. This means that a 'this' pointer is required. The parameter
'alias funcptr' to HookupEngineFunction requires an argument that is a symbolic
alias. But you're supplying a runtime value, d.outputDebug, that cannot be
evaluated at compile time.

In other words, d.outputDebug would be a delegate, and delegates can only be
constructed at runtime because they consist of a pair: a 'this' pointer and the
address of the function. The 'this' pointer cannot be determined at compile
time.

If you make Debug.outputDebug a static member function, it will compile.

This is not a compiler bug.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Apr 20 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7897


Walter Bright <bugzilla digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |INVALID



11:52:56 PDT ---
========
 // !!! getMember doesn't work here...
 HookupEngineFunction!( __traits( getMember, s, m ) )( pImports );
========

This is a similar issue. s here is a variable, and getMember is expecting a
type. Rewriting as:

 HookupEngineFunction!( __traits( getMember, typeof(s), m ) )( pImports );

gets past that. But then we're back to the previous issue, no 'this' pointer at
compile time.

This is not a compiler bug, either.

I suspect what you are doing is trying to do C++ "pointers to members". Perhaps
this will help:

http://www.drdobbs.com/blogs/cpp/231600610

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Apr 20 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7897




Actually no, I'm not trying to do pointer to member type stuff.

As I saw it, this is just a single function pointer (surely that is strictly
defined by the 'function' keyword?) in a struct.

I'm addressing a static (well, __gshared) instance, 'd'.
Shouldn't d be a singular instance, allocated in the data block, and thereby
accessible at compile time? I figure this should effectively be no different
than a __gshared void*.

Have I misunderstood something rather fundamental about __gshared? This should
make it effectively identical to a C global right? Ie, singular instance,
allocated in the data block, and address known at compile time.
Under that assumption, there's no technical reason the compiler shouldn't be
able to alias that variable at compile time and generate appropriate code.

If I'm mistaken about that, how do I produce a variable effectively identical
to a C global?

Like I say, this is a very boiled down case, and infact, this particular case
is no longer directly relevant in my code, but the same scenario is coming up
frequently. That is, I have a global instance of a structure, which I expect
should be accessible at compile time...

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Apr 20 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7897


Manu <turkeyman gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|INVALID                     |



Here, I've simplified it some more. This is functionally identical to the first
example, I just rephrased it to 'int' to remove any confusion about function
pointers and intent.


// member contained in a struct
struct Thing
{
    int x;
}

Thing thing; // this is effectively identical to declaring 'int x;' globally,
it's just wrapped in a thin struct

int x; // i'll also do it directly, to prove it works.

void main()
{
    // these 3 statements should be effectively identical
    thing.x = 10;               // this works, obviously
    AliasTheStruct!( thing )(); // this works
    AliasTheInt!( thing.x )();  // this is the problem

    AliasTheInt!( x )();        // of course, this works fine
}

void AliasTheStruct( alias a )()
{
    a.x = 10;
}

void AliasTheInt( alias a )()
{
    a = 10;
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Apr 20 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7897




16:43:49 PDT ---

 As I saw it, this is just a single function pointer (surely that is strictly
 defined by the 'function' keyword?) in a struct.
It isn't a function pointer. Non-static member methods are never a simple function pointer, they always require a 'this' pointer as well, as they are delegates. This is not like C++ member function pointers. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Apr 20 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7897


Walter Bright <bugzilla digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|REOPENED                    |RESOLVED
         Resolution|                            |INVALID



16:49:40 PDT ---
 AliasTheInt!( thing.x )();  // this is the problem
Right. It's a problem because thing.x is being passed as an *alias* parameter. An alias must be symbol, not a computation on a symbol. thing.x is semantically equivalent to: *(&thing + x.offsetof) which is not a symbol. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Apr 20 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7897






 As I saw it, this is just a single function pointer (surely that is strictly
 defined by the 'function' keyword?) in a struct.
It isn't a function pointer. Non-static member methods are never a simple function pointer, they always require a 'this' pointer as well, as they are delegates. This is not like C++ member function pointers.
extern(C) void function( const char* format, ... ) outputDebug; <- this is a function pointer. It's not a method, or a delegate. I have no idea why you're introducing methods and delegates into the conversation. But it doesn't matter, it's irrelevant to the problem here...
 AliasTheInt!( thing.x )();  // this is the problem
Right. It's a problem because thing.x is being passed as an *alias* parameter. An alias must be symbol, not a computation on a symbol. thing.x is semantically equivalent to: *(&thing + x.offsetof) which is not a symbol.
Oooohkay, so now we get to the bottom of it. Right, well I didn't realise that restriction. I just assumed any statically addressable variable was alias-able. So this is a feature request then, not a bug. There's still technically no reason it shouldn't work, it's just not quite how alias is written? How much trouble would it be to extend 'alias' to include an offset value? This restriction makes it very difficult to drill down into structures via recursive enumeration. The workaround I've had to use is to use strings instead of aliases that can mixin an absolute reference, but it's really untidy, and again, messes with the editor a lot (syntax hilighting, auto-complete, etc). It also requires mixin(a) everywhere, and there are lots of cases where mixin() is invalid in the middle of an expression. This requires a further workaround to build the whole expression into a string and mix the whole thing in. I wonder if you could use lowering here to produce the same result via lowered mixin? Although it sounds much cleaner to simply add an offset to aliases. Another alternative could be to just invent the appropriate symbol when a reference like this appears. Symbol names follow the d scoping patterns right? In this case, the symbol would just be my.module.thing.x (or with whatever mangling happens to appear in D symbols). -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Apr 20 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7897




18:00:42 PDT ---

 Oooohkay, so now we get to the bottom of it.
 Right, well I didn't realise that restriction. I just assumed any statically
 addressable variable was alias-able.
Any *symbol* is aliasable. It isn't about addresses.
 So this is a feature request then, not a bug.
 There's still technically no reason it shouldn't work, it's just not quite how
 alias is written?
 How much trouble would it be to extend 'alias' to include an offset value?
This is a significant redesign of what alias is.
 This restriction makes it very difficult to drill down into structures via
 recursive enumeration. The workaround I've had to use is to use strings instead
 of aliases that can mixin an absolute reference, but it's really untidy, and
 again, messes with the editor a lot (syntax hilighting, auto-complete, etc).
 It also requires mixin(a) everywhere, and there are lots of cases where mixin()
 is invalid in the middle of an expression. This requires a further workaround
 to build the whole expression into a string and mix the whole thing in.
 
 I wonder if you could use lowering here to produce the same result via lowered
 mixin? Although it sounds much cleaner to simply add an offset to aliases.
It isn't simple, because having an offset makes it an expression, not a symbol. It's a substantial redesign.
 Another alternative could be to just invent the appropriate symbol when a
 reference like this appears. Symbol names follow the d scoping patterns right?
 In this case, the symbol would just be my.module.thing.x (or with whatever
 mangling happens to appear in D symbols).
Can't you just pass a pointer around? -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Apr 20 2012
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7897






 Oooohkay, so now we get to the bottom of it.
 Right, well I didn't realise that restriction. I just assumed any statically
 addressable variable was alias-able.
Any *symbol* is aliasable. It isn't about addresses.
Yeah I see now, but I don't think that's what people intuitively expect. I've asked for help on various manifestations of this matter on IRC quite a few times, and so far, zero out of all the people who have helped me seem to understand that either. They almost all just said something like "yeah it seems to be a bit finicky, have you tried this, try passing a this kind of thing, try changing it this way", etc .. suggesting that nobody had any understanding of what they were trying to do, just fiddling with it until it stopped complaining. Perhaps it would be a good idea to add some informative error message stating the limitation. The whinge about 'this' certainly lost all meaning to me at least, I was absolutely convinced 'this' was perfectly calculable at compile time, and it should work. There was no mention of symbols.
 So this is a feature request then, not a bug.
 There's still technically no reason it shouldn't work, it's just not quite how
 alias is written?
 How much trouble would it be to extend 'alias' to include an offset value?
This is a significant redesign of what alias is.
:/ .. I think though that the mistake I made is what most people expect should be possible. At least all those that have tried to help me with it so far.
 Another alternative could be to just invent the appropriate symbol when a
 reference like this appears. Symbol names follow the d scoping patterns right?
 In this case, the symbol would just be my.module.thing.x (or with whatever
 mangling happens to appear in D symbols).
Can't you just pass a pointer around?
I don't think I can get a pointer to TLS data at compile time can I? Using the alias still allows the compiler to generate the correct TLS dereferencing code. In the cases where I use __gshared I suppose I could, but I'm not sure this would simplify the code at all. I can imagine it being more difficult to follow than the mixin version. Carrying a pointer interferes with typeof(), it also interferes with the ability to do allMemers, getMember on the instance (as opposed to the type). getMember only works on aliases(?), so I think I would need to generate mixin code that uses the strings produced by allMembers to generate expressions that reference the data I'm interested in anyway. I'll have a go at it, see how far I get. But I can imagine the result being very similar to the mixin approach, and probably no simpler for a 3rd person to follow. A direct alias is certainly be the most clear and concise way to go. Is it impossible to invent a new symbol when this case is encountered like I suggest? That could be a simple solution that fits the existing model. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Apr 21 2012