August 19, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5710



--- Comment #10 from David Simcha <dsimcha@yahoo.com> 2011-08-19 07:03:02 PDT ---
(In reply to comment #9)
> 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);
> }

Sounds great if you can pull it off.  I was thinking the same thing, but I'm not familiar enough with the DMD codebase to know how easy/hard it would be to implement.  This would remove some really silly/annoying limitations from std.parallelism.

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



--- Comment #11 from David Simcha <dsimcha@yahoo.com> 2011-08-23 21:48:56 PDT ---
(In reply to comment #6)
> 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?

If it's really that much of a problem, how about we just forbid taking the address of functions with two context pointers?  It would be a heck of a lot less of an annoying limitation than this bug.

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



--- Comment #12 from David Simcha <dsimcha@yahoo.com> 2011-12-28 06:33:47 PST ---
Any chance of this getting fixed anytime soon now that we're addressing a whole bunch of lambda-related issues?  If not, I think I can use UFCS to move std.parallelism.map, reduce, etc. out of TaskPool w/o changing the call syntax, and work around this bug.  This is kind of ugly, though, so I'd rather not do so if this bug is going to get fixed.

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



--- Comment #13 from Andrei Alexandrescu <andrei@metalanguage.com> 2012-07-30 09:38:34 PDT ---
I think Kenji's design is very promising. I assume it uses static arrays, i.e. no dynamic allocation. On the other hand, we need to think this through quite carefully. One example is that some frames must be dynamically allocated, and others don't. So the array of frame pointers would contain in the general case a mix of pointers to the stack and pointers to the heap. Hopefully that doesn't impact the design.

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


klickverbot <code@klickverbot.at> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |code@klickverbot.at


--- Comment #14 from klickverbot <code@klickverbot.at> 2012-07-30 11:14:54 PDT ---
(In reply to comment #12)
> If not, I think I can use UFCS to move
> std.parallelism.map, reduce, etc. out of TaskPool w/o changing the call syntax,
> and work around this bug.

I don't think you can, because D doesn't have ADL, so if somebody just has the TaskPool type, but not the module in scope, the free functions would not be found.

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


deadalnix <deadalnix@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |deadalnix@gmail.com


--- Comment #15 from deadalnix <deadalnix@gmail.com> 2013-01-21 18:16:38 PST ---
(In reply to comment #1)
> 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().

Why there could only be one ? I see no real problem about having 2 of them.

Note that I have plenty of workaround on top of several forms of that issue.

Passing the delegate as argument instead of alias is going to make things much slower.

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


Steven Schveighoffer <schveiguy@yahoo.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |schveiguy@yahoo.com


--- Comment #16 from Steven Schveighoffer <schveiguy@yahoo.com> 2013-05-06 11:01:01 PDT ---
(In reply to comment #0)

> 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);
> }

This is definitely not good.

I don't think we need to alter the ABI for this.  The 'this' pointer of the frame isn't used inside doStuff, just inside the template instantiation.  The compiler can be smart enough to recognize that fun(a, b) is really:

fun(a, b, frameptr), and that frameptr is passed implicitly as a parameter.  It does not have to be spelled out in the parameters to doStuff.

I don't like the *spirit* of kenji's solution, that context pointers are an array.  Given that this is a template, and the compiler has the ability to pass and receive, and write code for, any hidden parameter it wishes, it's simply a matter of lowering.  Like foreach, which injects hidden code and function return handling.

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


Diggory <diggsey@googlemail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |diggsey@googlemail.com


--- Comment #17 from Diggory <diggsey@googlemail.com> 2013-05-06 11:46:02 PDT ---
Kenji's solution means two context pointer delegates are just normal delegates (still a function pointer and a context pointer) so they can still be passed around as usual.

There's no need for dynamic allocation because if the stack frame referred to by a delegate is invalid when the delegate is called, the results are already undefined.

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



--- Comment #18 from Steven Schveighoffer <schveiguy@yahoo.com> 2013-05-06 14:50:59 PDT ---
(In reply to comment #17)
> Kenji's solution means two context pointer delegates are just normal delegates (still a function pointer and a context pointer) so they can still be passed around as usual.

OK, but how does it devolve to a 'this' pointer for the class?  In other words, doesn't the compiler have to treat 'this' in a special way while inside doStuff?

Is that OK?  I guess it's not too important, but it would be a new ABI call type, no?

I wonder if it wouldn't be better to push 'foo' and then the stack frame on to the stack, and then the call to doStuff would look like:

uint doStuff(uint a, uint b, 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));
}

Would that not work?  I'd actually rather just see another parameter:

uint doStuff(uint a, uint b, void *this1, void *this)
{
   return fun(a, b, this1);
}

That is simpler for me to understand, I don't see why the compiler can't do this.

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



--- Comment #19 from Diggory <diggsey@googlemail.com> 2013-05-06 15:20:20 PDT ---
(In reply to comment #18)
> (In reply to comment #17)
> > Kenji's solution means two context pointer delegates are just normal delegates (still a function pointer and a context pointer) so they can still be passed around as usual.
> 
> OK, but how does it devolve to a 'this' pointer for the class?  In other words, doesn't the compiler have to treat 'this' in a special way while inside doStuff?
> 
> Is that OK?  I guess it's not too important, but it would be a new ABI call type, no?
> 
> I wonder if it wouldn't be better to push 'foo' and then the stack frame on to the stack, and then the call to doStuff would look like:
> 
> uint doStuff(uint a, uint b, 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));
> }
> 
> Would that not work?  I'd actually rather just see another parameter:
> 
> uint doStuff(uint a, uint b, void *this1, void *this)
> {
>    return fun(a, b, this1);
> }
> 
> That is simpler for me to understand, I don't see why the compiler can't do this.

How the parameters are actually passed is fairly irrelevant, the main problem
which needs to be solved is how to store two context pointers in a delegate,
when currently delegates look like this:
struct dg {
    void* contextPtr;
    void* funcPtr;
}

If you add an extra context pointer, you have to either make all delegates
bigger:
struct dg {
    void* contextPtr1;
    void* contextPtr2;
    void* funcPtr;
}

Or have two or more types of delegates which cannot be used interchangeably (in which case they're fairly useless as delegates!)

Kenji is suggesting something like this:
struct dg {
    void* contextPtr;
    void* funcPtr;
}
struct multiContext {
    void* contextPtr1;
    void* contextPtr2;
}

The "multiContext" struct is completely invisible to anyone using the delegate, and it doesn't affect in the slightest how the delegate is called, you're still passing in one context pointer.

The decoding into two context pointers is handled by the callee, because the callee knows how many context pointers it should have. (Think about it, how can a function not know how many context pointers it needs!)

It should be possible to call a delegate without having to know anything about the receiver other than what arguments it takes.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------