digitalmars.D.bugs - [Issue 7897] New: Problem with alias template parameter
- d-bugmail puremagic.com (64/64) Apr 13 2012 http://d.puremagic.com/issues/show_bug.cgi?id=7897
- d-bugmail puremagic.com (25/25) Apr 20 2012 http://d.puremagic.com/issues/show_bug.cgi?id=7897
- d-bugmail puremagic.com (23/23) Apr 20 2012 http://d.puremagic.com/issues/show_bug.cgi?id=7897
- d-bugmail puremagic.com (23/23) Apr 20 2012 http://d.puremagic.com/issues/show_bug.cgi?id=7897
- d-bugmail puremagic.com (37/37) Apr 20 2012 http://d.puremagic.com/issues/show_bug.cgi?id=7897
- d-bugmail puremagic.com (9/11) Apr 20 2012 http://d.puremagic.com/issues/show_bug.cgi?id=7897
- d-bugmail puremagic.com (15/16) Apr 20 2012 http://d.puremagic.com/issues/show_bug.cgi?id=7897
- d-bugmail puremagic.com (30/46) Apr 20 2012 http://d.puremagic.com/issues/show_bug.cgi?id=7897
- d-bugmail puremagic.com (11/32) Apr 20 2012 http://d.puremagic.com/issues/show_bug.cgi?id=7897
- d-bugmail puremagic.com (35/53) Apr 21 2012 http://d.puremagic.com/issues/show_bug.cgi?id=7897
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
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
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
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
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
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
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
http://d.puremagic.com/issues/show_bug.cgi?id=7897extern(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...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.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: -------AliasTheInt!( thing.x )(); // this is the problemRight. 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.
Apr 20 2012
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
http://d.puremagic.com/issues/show_bug.cgi?id=7897Yeah 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.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.:/ .. 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.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 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: -------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?
Apr 21 2012









d-bugmail puremagic.com 