skinny delegates
Jonathan Marler
johnnymarler at gmail.com
Thu Aug 2 16:37:29 UTC 2018
On Thursday, 2 August 2018 at 16:21:58 UTC, Jonathan Marler wrote:
> On Monday, 30 July 2018 at 21:02:56 UTC, Steven Schveighoffer
> wrote:
>> Would it be a valid optimization to have D remove the
>> requirement for allocation when it can determine that the
>> entire data structure of the item in question is an rvalue,
>> and would fit into the data pointer part of the delegate?
>>
>> Here's what I'm looking at:
>>
>> auto foo(int x)
>> {
>> return { return x + 10; };
>> }
>>
>> In this case, D allocates a pointer on the heap to hold "x",
>> and then return a delegate which uses the pointer to read x,
>> and then return that plus 10.
>>
>> However, we could store x itself in the storage of the pointer
>> of the delegate. This removes an indirection, and also saves
>> the heap allocation.
>>
>> Think of it like "automatic functors".
>>
>> Does it make sense? Would it be feasible for the language to
>> do this? The type system already casts the delegate pointer to
>> a void *, so it can't make any assumptions, but this is a
>> slight break of the type system.
>>
>> The two requirements I can think of are:
>> 1. The data in question must fit into a word
>> 2. It must be guaranteed that the data is not going to be
>> mutated (either via the function or any other function). Maybe
>> it's best to require the state to be const/immutable.
>>
>> I've had several cases where I was tempted to not use
>> delegates because of the allocation cost, and simply return a
>> specialized struct, but it's so annoying to do this compared
>> to making a delegate. Plus something like this would be
>> seamless with normal delegates as well (in case you do need a
>> real delegate).
>>
>> -Steve
>
> I think the number of cases where you could optimize this is
> very small. And the complexity of getting the compiler to
> analyze cases to determine when this is possible would be very
> large.
>
> In addition, a developer can already do this explicitly if they
> want, i.e.
>
> auto foo(int x)
> {
> static struct DummyStructToMakeFunctionWithDelegateAbi
> {
> int passthru() const { return cast(int)&this; }
> }
> DummyStructToMakeFunctionWithDelegateAbi dummyStruct;
> auto dg = &dummyStruct.passthru;
> dg.ptr = cast(void*)(x + 10); // treat the void* pointer as
> an int value
> return dg;
> }
>
> void main(string[] args)
> {
> auto dg = foo(32);
> import std.stdio;
> writefln("dg() = %s", dg());
> }
>
> It's definitely ugly but it works. This will print the number
> "42" as expected.
>
> This would be a case where DIP1011 extern(delegate) would come
> in handy :) i.e.
>
> extern(delegate) int passthru(void* ptr) { return cast(int)ptr;
> }
> int delegate() foo2(int x)
> {
> return &(cast(void*)(x + 10)).passthru;
> }
Actually, I'll do you one better. Here's a potential library
function for it. I'm calling these types of delegates "value
pointer delegates".
// Assume this is in a library somewhere
auto makeValuePtrDelegate(string valueName, string funcBody, T)(T
value)
{
static struct DummyStruct
{
auto method() const
{
mixin("auto " ~ valueName ~ " = cast(T)&this;");
mixin (funcBody);
}
}
DummyStruct dummy;
auto dg = &dummy.method;
dg.ptr = cast(void*)value;
return dg;
}
auto foo(int x)
{
return makeValuePtrDelegate!("val", q{ return val + 10; })(x);
}
void main(string[] args)
{
auto dg = foo(32);
import std.stdio;
writefln("dg() = %s", dg());
}
More information about the Digitalmars-d
mailing list