Jump to page: 1 2 3
Thread overview
[Issue 5710] New: cannot use delegates as parameters to non-global template
Mar 06, 2011
David Simcha
Mar 06, 2011
Walter Bright
Mar 06, 2011
David Simcha
Mar 06, 2011
Walter Bright
Mar 07, 2011
David Simcha
Mar 07, 2011
Walter Bright
Mar 07, 2011
Rainer Schuetze
Mar 07, 2011
Brad Roberts
Jun 10, 2011
Kenji Hara
Aug 19, 2011
David Simcha
Aug 24, 2011
David Simcha
Dec 28, 2011
David Simcha
Jul 30, 2012
klickverbot
Jan 22, 2013
deadalnix
May 06, 2013
Diggory
May 06, 2013
Diggory
May 07, 2013
Diggory
May 07, 2013
Diggory
March 06, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5710

           Summary: cannot use delegates as parameters to non-global
                    template
           Product: D
           Version: D2
          Platform: Other
        OS/Version: Windows
            Status: NEW
          Keywords: rejects-valid
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: dsimcha@yahoo.com


--- Comment #0 from David Simcha <dsimcha@yahoo.com> 2011-03-06 06:26:40 PST ---
This pretty severely impacts the usability of template alias parameters for lambda functions.

class Foo {
    uint doStuff(alias fun)(uint a, uint b) { return fun(a, b); }
}

void main() {
    auto foo = new Foo;

    uint add(uint a, uint b) { return a + b; }

    foo.doStuff!add(1, 2);
}

test9.d(10): Error: template instance cannot use local 'add' as parameter to
non-global template doStuff(alias fun)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 06, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5710


Walter Bright <bugzilla@digitalmars.com> changed:

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


--- Comment #1 from Walter Bright <bugzilla@digitalmars.com> 2011-03-06 10:16:43 PST ---
The reason this does not work is because the instantiation of the doStuff() function would require *two* context pointers:

1. a 'this' pointer to the object Foo
2. a 'this' pointer to the stack frame of main()

and there can be only one.

It will work if you declare add() as being static, because then you're saying
that it does not need a context pointer to main().

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 06, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5710



--- Comment #2 from David Simcha <dsimcha@yahoo.com> 2011-03-06 11:05:37 PST ---
So is this an WONTFIX, then?  Unfortunately it severely hurts my std.parallelism design in some use cases, and a workaround for it would be a significant PITA to implement, make the API uglier, and possibly be inefficient.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 06, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5710



--- Comment #3 from Walter Bright <bugzilla@digitalmars.com> 2011-03-06 15:19:12 PST ---
(In reply to comment #2)
> So is this an WONTFIX, then?

Unless there's an epiphany somewhere, yes. How would you suggest two hidden context pointers be handled? Is it clear that two context pointers are required (at least for this example)?

> Unfortunately it severely hurts my
> std.parallelism design in some use cases, and a workaround for it would be a
> significant PITA to implement, make the API uglier, and possibly be
> inefficient.

I don't know enough about your design to offer help with that. Perhaps instead of an alias parameter, make fun explicitly a delegate?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 06, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5710


Andrei Alexandrescu <andrei@metalanguage.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |andrei@metalanguage.com


--- Comment #4 from Andrei Alexandrescu <andrei@metalanguage.com> 2011-03-06 15:31:45 PST ---
(In reply to comment #3)
> (In reply to comment #2)
> > So is this an WONTFIX, then?
> 
> Unless there's an epiphany somewhere, yes. How would you suggest two hidden context pointers be handled? Is it clear that two context pointers are required (at least for this example)?
> 
> > Unfortunately it severely hurts my
> > std.parallelism design in some use cases, and a workaround for it would be a
> > significant PITA to implement, make the API uglier, and possibly be
> > inefficient.
> 
> I don't know enough about your design to offer help with that. Perhaps instead of an alias parameter, make fun explicitly a delegate?

There are several things here.

First, the compiler should figure out that add does not need a frame pointer and consider it a static inner function, not a delegate.

Second, we need to agree that the reason you invoke is tied to the implementation - you use the same pointer for the class and for the hidden frame pointer, whereas of course there's no imposition to do so. The hidden "this" parameter could go pretty much anywhere else.

One way or another we must fix this. Oddly, a number of similar uses do work "by mistake", so at this moment we don't have a clear grasp on what distinguishes cases that work from cases that don't.

We need to pursue this like a bloodhound and aggressively make as many cases as possible work transparently. This is a major asset of D over virtually all other languages.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 07, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5710



--- Comment #5 from David Simcha <dsimcha@yahoo.com> 2011-03-06 16:29:07 PST ---
(In reply to comment #3)
> (In reply to comment #2)
> > So is this an WONTFIX, then?
> 
> Unless there's an epiphany somewhere, yes. How would you suggest two hidden context pointers be handled? Is it clear that two context pointers are required (at least for this example)?

Honestly, I don't know enough about the details of how DMD works under the hood to come up with a good answer, but my completely naive answer would be to pass the delegate context pointer in as a hidden argument between the explicit arguments and the hidden class instance pointer.  The class instance pointer is still passed last (no special casing) and the delegate context pointer lives on the stack somewhere as a regular stack variable and gets passed in when needed.

> 
> > Unfortunately it severely hurts my
> > std.parallelism design in some use cases, and a workaround for it would be a
> > significant PITA to implement, make the API uglier, and possibly be
> > inefficient.
> 
> I don't know enough about your design to offer help with that. Perhaps instead of an alias parameter, make fun explicitly a delegate?

This would be the workaround, but I probably won't implement it because:

1.  If I still keep alias parameters, I'll have to have two implementations of
map(), reduce() and friends.  This is ugly from both an API and an
implementation perspective.

2.  Delegates can't be inlined. Aliases can.

3.  Delegates can only be instantiations of templates.  Aliases can be templates.  This means that a nested template function would have to be explicitly instantiated.  This is ugly.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 07, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5710



--- Comment #6 from Walter Bright <bugzilla@digitalmars.com> 2011-03-06 22:18:04 PST ---
(In reply to comment #4)
> First, the compiler should figure out that add does not need a frame pointer and consider it a static inner function, not a delegate.

Delegates and functions are different types. Deciding, based on the contents of a function body, whether it is a function or a delegate makes for non-obvious changes in type. Secondly, people are going to access outer variables from a nested function, and will not expect it to break their code.

> Second, we need to agree that the reason you invoke is tied to the implementation - you use the same pointer for the class and for the hidden frame pointer, whereas of course there's no imposition to do so.

Making them use the same ABI means that they have the same type and are interchangeable. This is a big deal. I don't think this will survive "a class member function pointer is a different type than a nested function pointer".

> The hidden "this" parameter could go pretty much anywhere else.
> One way or another we must fix this. Oddly, a number of similar uses do work
> "by mistake", so at this moment we don't have a clear grasp on what
> distinguishes cases that work from cases that don't.
> We need to pursue this like a bloodhound and aggressively make as many cases as
> possible work transparently. This is a major asset of D over virtually all
> other languages.

Consider if we add another type - a function pointer with two context pointers. Now we have quite a menagerie:

1. function pointer
2. function pointer with context pointer (delegate)
3. function pointer with two context pointers

Is that really where we want to go?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 07, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5710


Rainer Schuetze <r.sagitario@gmx.de> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |r.sagitario@gmx.de


--- Comment #7 from Rainer Schuetze <r.sagitario@gmx.de> 2011-03-07 00:35:26 PST ---
This could be implemented with a single context pointer, if the this pointer of the Foo instance can be found through the stack frame pointer. In the example the pointer to foo is already there, but in the more general case, a hidden stack/closure variable needs to be used.

I'm not sure how much it would complicate code generation, though. It could end up as a can of worms, e.g. having to deal with multiple aliases to different kind of context pointers.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 07, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5710


Brad Roberts <braddr@puremagic.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |braddr@puremagic.com


--- Comment #8 from Brad Roberts <braddr@puremagic.com> 2011-03-07 01:19:35 PST ---
(In reply to comment #6)
> Consider if we add another type - a function pointer with two context pointers. Now we have quite a menagerie:
> 
> 1. function pointer
> 2. function pointer with context pointer (delegate)
> 3. function pointer with two context pointers
> 
> Is that really where we want to go?

Yes.  They're just function parameters.  Define how they're passed and pass 'em.  It doesn't need to be fancy or tricky.  It's not particularly different from passing dynamic arrays having a well defined parameter layout.  Just considered it just a tuple of two pointers.  It's not rocket science.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 10, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5710


Kenji Hara <k.hara.pg@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |k.hara.pg@gmail.com


--- Comment #9 from Kenji Hara <k.hara.pg@gmail.com> 2011-06-10 06:44:19 PDT ---
My idea:
doStuff receives a context pointer that points 'an array of context pointers'.
Backend receives code like follows...

uint doStuff(uint a, uint b, void** this)  // not void* this
{
    // (*this + 0) points the object Foo
    // (*this + 1) points the stack frame of main()

    //return fun(a, b);
    return fun(a, b, (*this + 1));
}

Caller of doStuff have to create array of context pointers.

void main(){
    ...
    //foo.doStuff!add(1, 2);
    void*[2] thisarray = [(stack frame of main), foo];
    doStuff(a, b, thisarray.ptr);
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
« First   ‹ Prev
1 2 3