Forcing inlining of delegates and lazy

limepoutine ztang013 at foxmail.com
Tue Sep 1 15:03:54 UTC 2026


On Monday, 31 August 2026 at 20:08:28 UTC, ABrightLight wrote:
> On Monday, 31 August 2026 at 17:36:55 UTC, ABrightLight wrote:
>> Hello. I am trying to figure out some way to get delegates or 
>> lazy parameters to get inlined into the function they are 
>> called with. For example, if we take this starting code:
>>
>> ```d
>> void foo () {
>>   bar.blah(args);
>>   bar.otherBlah;
>>
>>   foreach (item; bar.collection) {
>>     item.action;
>>   }
>>
>>   bar.moreBlah;
>> }
>> ```
>> I like to rewrite this as:
>> ```d
>> void withBoilerplate (lazy void expr) {
>>   bar.blah(args);
>>   bar.otherBlah;
>>
>>   expr;
>>
>>   bar.moreBlah;
>> }
>>
>> void foo () {
>>   withBoilerplate(
>>     foreach (item; bar.collection) {
>>       item.action;
>>     }
>>   );
>> }
>> ```
>> You may notice that these sorts of rewrites are very common in 
>> languages with AST macros, such as lisp. For example the 
>> equivalent would be:
>> ```lisp
>> (defmacro with-boilerplate (expr)
>>   `(progn
>>      (blah bar args)
>>      (other-blah bar)
>>
>>      ,expr
>>
>>      (more-blah bar)))
>>
>> (defun foo ()
>>   (with-boilerplate
>>     (loop for item across (collection bar) do
>>       (action item))))
>> ```
>> These sorts of macros greatly aid in readability and 
>> maintainability.
>>
>> The drawback to the lazy/delegate approach so far is the extra 
>> indirection of the function call. And the use of 
>> `pragma(inline)` hasn't helped. Is there some way to get it to 
>> inline so that I can use this sort of pattern in hot-code 
>> paths without the worry that I'm introducing slowdowns in the 
>> name of better readability and maintainability?
>
> To clarify in case the code isn't clear - there is a lot of 
> code I have that essentially does some boilerplate prior to 
> some expression and then there is more more after the 
> expression. To avoid having to keep inserting the same code 
> around the actual expression, I place the boilerplate into a 
> function that accepts the body/expression to "insert" between 
> the boilerplate.
>
> I don't think any mixin will be able to do this as cleanly or 
> as clearly.

Lisp macros do really translate well to template mixins. That 
being said, D has no `(gensym)`, no unit types, nor many of lisp 
conveniences we're familiar with, so the implementation would be 
a bit awkward.

```
import std.stdio;
import std.traits;

bool inUse;

mixin template withBoilerplate(alias dg) if (isCallable!dg)
{
     static if (is(typeof(dg()) ReturnType == void))
     {
         typeof(null) withBoilerplateResult = {
             inUse = true;
             dg();
             inUse = false;
             return null;
         }();
     }
     else
     {
         ReturnType withBoilerplateResult = {
             inUse = true;
             ReturnType value = dg();
             inUse = false;
             return value;
         }();
     }
}

void main() {
   mixin withBoilerplate!({
     writeln("Hello, world");
   });
   mixin withBoilerplate!({
     writeln("Goodbye, world");
   });
}
```


More information about the Digitalmars-d mailing list