digitalmars.D.learn - Do string mixins work under -betterC?
- DLearner (8/8) Dec 16 2025 I have a rather complicated string mixin defined and invoked from
- Richard (Rikki) Andrew Cattermole (15/25) Dec 16 2025 Yes it does.
- DLearner (9/30) Dec 16 2025 [...]
- Richard (Rikki) Andrew Cattermole (4/34) Dec 16 2025 No, this is something that should've been done a while back.
- DLearner (13/30) Dec 17 2025 On Wednesday, 17 December 2025 at 00:13:42 UTC, Richard (Rikki)
- Richard (Rikki) Andrew Cattermole (4/35) Dec 17 2025 genStuff will still compile into the binary.
- DLearner (7/44) Dec 17 2025 And a suitably placed 'if (__ctfe) {...} else {}' within genStuff
- Adam D. Ruppe (15/16) Dec 17 2025 In OpenD you can
- DLearner (6/22) Dec 17 2025 This idea worked with DMD64 D Compiler v2.111.0.
- abc (9/10) Dec 18 2025 If your function is a lambda assigned to an anonymous enum then
- Kapendev (14/22) Dec 17 2025 My solution to this is something like:
- IchorDev (30/38) Jan 10 There are two better options in terms of compile speed:
I have a rather complicated string mixin defined and invoked from within the same source file. Which seems to work. But when I move the mixin definition to a separate module, and import that module into the original source file, the compilation collapses complaining that array concatenation requires the GC, which is not available with -betterC. DLearner
Dec 16 2025
On 17/12/2025 9:48 AM, DLearner wrote:I have a rather complicated string mixin defined and invoked from within the same source file. Which seems to work. But when I move the mixin definition to a separate module, and import that module into the original source file, the compilation collapses complaining that array concatenation requires the GC, which is not available with -betterC. DLearnerYes it does. Are you trying to extract the string mixin argument out into a function? ```d string genStuff(string val) { return val ~ ";"; } void myFunc() { mixin(genStuff("this")); } ``` This won't work without a way to mark `genStuff` as CTFE only. Which doesn't exist currently. Compiler has to know that a given execution context is CTFE only otherwise disallowed.
Dec 16 2025
On Tuesday, 16 December 2025 at 20:56:06 UTC, Richard (Rikki) Andrew Cattermole wrote:On 17/12/2025 9:48 AM, DLearner wrote:[...]I have a rather complicated string mixin defined and invoked from within the same source file. Which seems to work. But when I move the mixin definition to a separate module, and import that module into the original source file, the compilation collapses complaining that array concatenation requires the GC, which is not available with -betterC.string genStuff(string val) { return val ~ ";"; } void myFunc() { mixin(genStuff("this")); } ``` This won't work without a way to mark `genStuff` as CTFE only. Which doesn't exist currently. Compiler has to know that a given execution context is CTFE only otherwise disallowed.1. Any proposals to mark a function as CTFE only? 2. Why (and I've now got this down to a cut-and-paste) is there no problem if the mixin definition is in the main function, but problem appears if the definition is moved to a separate module (which is imported into the main function)? DL
Dec 16 2025
On 17/12/2025 12:25 PM, DLearner wrote:On Tuesday, 16 December 2025 at 20:56:06 UTC, Richard (Rikki) Andrew Cattermole wrote:No, this is something that should've been done a while back. The main concern is that you can get a linker error if you don't emit a function that was called.On 17/12/2025 9:48 AM, DLearner wrote:[...]I have a rather complicated string mixin defined and invoked from within the same source file. Which seems to work. But when I move the mixin definition to a separate module, and import that module into the original source file, the compilation collapses complaining that array concatenation requires the GC, which is not available with -betterC.string genStuff(string val) { return val ~ ";"; } void myFunc() { mixin(genStuff("this")); } ``` This won't work without a way to mark `genStuff` as CTFE only. Which doesn't exist currently. Compiler has to know that a given execution context is CTFE only otherwise disallowed.1. Any proposals to mark a function as CTFE only?
Dec 16 2025
On Wednesday, 17 December 2025 at 00:13:42 UTC, Richard (Rikki) Andrew Cattermole wrote: [...][...]string genStuff(string val) { return val ~ ";"; } void myFunc() { mixin(genStuff("this")); }Actually, in your example, don't see the problem. 'mixin' operates to provide text to the compiler _prior to_ run time. Therefore, even if 'genStuff()' has a run-time (as well as) compile-time meaning, the use of mixin should force the compile-time meaning to be taken. So no ambiguity? DLNo, this is something that should've been done a while back. The main concern is that you can get a linker error if you don't emit a function that was called.This won't work without a way to mark `genStuff` as CTFE only. Which doesn't exist currently. Compiler has to know that a given execution context is CTFE only otherwise disallowed.1. Any proposals to mark a function as CTFE only?
Dec 17 2025
On 18/12/2025 3:15 AM, DLearner wrote:On Wednesday, 17 December 2025 at 00:13:42 UTC, Richard (Rikki) Andrew Cattermole wrote: [...]genStuff will still compile into the binary. The error happens when it tries to do that, not when it tries to run it for the string mixin.[...]string genStuff(string val) { return val ~ ";"; } void myFunc() { mixin(genStuff("this")); }Actually, in your example, don't see the problem. 'mixin' operates to provide text to the compiler _prior to_ run time. Therefore, even if 'genStuff()' has a run-time (as well as) compile-time meaning, the use of mixin should force the compile-time meaning to be taken. So no ambiguity? DLNo, this is something that should've been done a while back. The main concern is that you can get a linker error if you don't emit a function that was called.This won't work without a way to mark `genStuff` as CTFE only. Which doesn't exist currently. Compiler has to know that a given execution context is CTFE only otherwise disallowed.1. Any proposals to mark a function as CTFE only?
Dec 17 2025
On Wednesday, 17 December 2025 at 14:18:22 UTC, Richard (Rikki) Andrew Cattermole wrote:On 18/12/2025 3:15 AM, DLearner wrote:And a suitably placed 'if (__ctfe) {...} else {}' within genStuff doesn't help? Idea is to tell the compiler that compilation for execution is entirely redundant. DLOn Wednesday, 17 December 2025 at 00:13:42 UTC, Richard (Rikki) Andrew Cattermole wrote: [...]genStuff will still compile into the binary. The error happens when it tries to do that, not when it tries to run it for the string mixin.[...]string genStuff(string val) { return val ~ ";"; } void myFunc() { mixin(genStuff("this")); }Actually, in your example, don't see the problem. 'mixin' operates to provide text to the compiler _prior to_ run time. Therefore, even if 'genStuff()' has a run-time (as well as) compile-time meaning, the use of mixin should force the compile-time meaning to be taken. So no ambiguity? DLNo, this is something that should've been done a while back. The main concern is that you can get a linker error if you don't emit a function that was called.This won't work without a way to mark `genStuff` as CTFE only. Which doesn't exist currently. Compiler has to know that a given execution context is CTFE only otherwise disallowed.1. Any proposals to mark a function as CTFE only?
Dec 17 2025
On Tuesday, 16 December 2025 at 23:25:18 UTC, DLearner wrote:1. Any proposals to mark a function as CTFE only?In OpenD you can ``` string genStuff(string val) { if(__ctfe) { return val ~ ";"; } else { assert(0); } } ``` That is, wrap the whole function in `if(__ctfe) {}` and it passes this test since the gc use is now provably only in ctfe. I don't know about the other dmd release but it might work there too, worth trying it.
Dec 17 2025
On Wednesday, 17 December 2025 at 14:29:21 UTC, Adam D. Ruppe wrote:On Tuesday, 16 December 2025 at 23:25:18 UTC, DLearner wrote:This idea worked with DMD64 D Compiler v2.111.0. In particular, it worked even when the equivalent of 'genStuff()' was defined in a different module and imported into main. Thanks!1. Any proposals to mark a function as CTFE only?In OpenD you can ``` string genStuff(string val) { if(__ctfe) { return val ~ ";"; } else { assert(0); } } ``` That is, wrap the whole function in `if(__ctfe) {}` and it passes this test since the gc use is now provably only in ctfe. I don't know about the other dmd release but it might work there too, worth trying it.
Dec 17 2025
On Tuesday, 16 December 2025 at 23:25:18 UTC, DLearner wrote:1. Any proposals to mark a function as CTFE only?If your function is a lambda assigned to an anonymous enum then it will not generate runtime code and it will not error. ``` enum genStuff = (string val){ return val ~ ";"; }; mixin(genStuff("int abc")); ```
Dec 18 2025
On Tuesday, 16 December 2025 at 20:48:25 UTC, DLearner wrote:I have a rather complicated string mixin defined and invoked from within the same source file. Which seems to work. But when I move the mixin definition to a separate module, and import that module into the original source file, the compilation collapses complaining that array concatenation requires the GC, which is not available with -betterC. DLearnerMy solution to this is something like: ```d import core.stdc.stdio; string genStuff(string val)() { return val ~ ";\n"; } extern(C) void main() { printf(genStuff!("Hello").ptr); } ``` This is **in my opinion** the best way to do things if you use the `betterC` flag.
Dec 17 2025
On Wednesday, 17 December 2025 at 15:12:59 UTC, Kapendev wrote:
My solution to this is something like:
```d
string genStuff(string val)() {
return val ~ ";\n";
}
```
This is **in my opinion** the best way to do things if you use
the `betterC` flag.
There are two better options in terms of compile speed:
First, if you will be using the exact same parameters in many
places, you can utilise template caching by assigning the result
of your function to an enum (so that the function isn't re-run by
the CTFE engine in every place that you use it):
```d
enum genStuff(string val) = (){
return val ~ ";\n";
}();
mixin(genStuff("int a"));
void foo(){
genStuff("int a");
}
void bar(){
genStuff("int a"));
}
```
Second, if you anticipate that you will use different parameters
every time, then you don't want to be generating a template for
every set of parameters because it's somewhat expensive. So we
can alleviate the template while making the function compile-time
only by just assigning it to an enum:
```d
enum genStuff = (string val){
return val ~ ";\n";
};
mixin(genStuff("int a") ~ genStuff("string b") ~
genStuff("void[0][size_t] c"));
```
Jan 10









DLearner <bmqazwsx123 gmail.com> 