How Nested Functions Work, part 1

Jarrett Billingsley jarrett.billingsley at gmail.com
Wed Sep 2 09:30:05 PDT 2009


On Wed, Sep 2, 2009 at 9:49 AM, Daniel Keep<daniel.keep.lists at gmail.com> wrote:
>
> Jarrett Billingsley wrote:
>> Well repeat should probably always take a delegate since most likely,
>> you're going to be passing it a lambda. However I agree that it would
>> be very, very nice to be able to make APIs take just delegates and
>> allow functions to be implicitly cast to them. You can already make
>> your own thunks, but they're not going to be as efficient as something
>> that actually works on an ABI level.
>
> The problem is that function pointers and delegates have different
> calling conventions.  You *might* be able to rig up an asm stub that
> compensated for the difference... not sure.

Which is why I suggest that the ABI be changed ;) I suppose one method
of making their calling conventions compatible would be to pass the
delegate's context in what would normally be a scratch register.
Delegates/member funcs would store that immediately upon entry, and
normal functions wouldn't care if anything were passed.

> As it stands, you can just use a function to create the delegate stub
> for you; doesn't even require a heap allocation!
>
> http://gist.github.com/140507

Wow. What a horrible mess of code to do something that should be
straightforward. If this is what Andrei is thinking of when he says
"introspection", well heh, I'll have no part of it.

The comment about tuples not being allowed to contain out and ref is
actually not entirely true. Internally type tuples are represented as
parameter type tuples, which include the refness, and you can even get
.stringofs that include the ref qualifiers. It instead seems that the
compiler is buggy and _whether or not the refness of the params in a
param tuple is preserved depends on the code using it_. Consider this
gem:

void foob(T: Ret function(Args), Ret, Args...)(T func)
{
	pragma(msg, ParameterTupleOf!(T).stringof);
	static void wtf(ParameterTupleOf!(T) args) {}
	pragma(msg, ParameterTupleOf!(T).stringof);
}

void blah(int, ref float) {}

void aojkjas()
{
	foob(&blah);
}

Okay, look at foob's body. Both pragmas should print out the same thing, no?

They don't.

They print:

(int, ref float)
(int _param_0, float _param_1)

WHAT. For one, where did the 'ref' go? For two, where did the names
come from? Also, if you look at typeof(&wtf), it's also missing the
ref.

I'd really, really like to replace your entire module with this:

Ret delegate(Args) toDg(T: Ret function(Args), Ret, Args...)(T func)
{
	struct Wrap
	{
		T mFunc;

		Ret call(Args args)
		{
			return (cast(T)this)(args);
		}
	}

	Ret delegate(Args) dg;
	Wrap wrap;
	dg.ptr = func;
	dg.funcptr = &wrap.call;
	return dg;
}

But I can't. :C



More information about the Digitalmars-d mailing list