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