4 ms·
Gave myself a quick D lesson just to understand the approach to flags here (Yes.keepTerminator rather than just a meaningless bool). Turns out D lets you define
by thom 7y ago
Gave myself a quick D lesson just to understand the approach to flags here (Yes.keepTerminator rather than just a meaningless bool). Turns out D lets you define a template with any args you like, in this case taking a string for a name of a Flag type, which in turn contains an enum with 'yes' and 'no' boolean values. This means that you can only use the right type of Flag, with a matching name, and its yes/no value. But the syntax is a bit icky (Flag!"keepTerminator) and so _another_ nice feature of D appears to be that you can intercept field dispatch in a struct. And so the 'Yes' struct does this, captures the 'keepTerminator' as a string, and creates the correct type of flag.
For whatever reason I found all this rather cute (and apologies to any actual D programmers if I've misread this whole situation).
- acehreli 7y agoSpot on! :) With the help of opDispatch (the catch-all member function temlate), it's possible to drop the string from the use site. (I don't know a way of dropping it from the type name.) import std.stdio; import std.typecons; import std.string; // This type's opDispatch removes the need for string in the flag name. struct FlagFromBool { auto opDispatch(string flagName)(bool value) { mixin (format!q{ return value ? Yes.%s : No.%s; }(flagName, flagName)); } } // A convenience function to remove the need for empty struct construction parenthesis. auto flagFromBool() { return FlagFromBool(); } // Unfortunately, the type name still requires string flag names: void bar(Flag!"foo" flag) { writeln("called with ", flag); } void main() { // However, the expressions don't need a string: bar(flagFromBool.foo(false)); bar(flagFromBool.foo(true)); }
- biotronic 7y agoBoth your convenience function and the quotes in the type name can be removed via the use of static opDispatch: struct FlagImpl(string name) { bool value; alias value this; } struct Flag { alias opDispatch(string name) = FlagImpl!name; } struct Yes { static auto opDispatch(string name)() { return FlagImpl!name(true); } } struct No { static auto opDispatch(string name)() { return FlagImpl!name(false); } } void fun(Flag.foo a) {} // Look ma, no quotes! unittest { fun(Yes.foo); fun(Flag.foo(true)); }
- WalterBright 7y agoD is getting named function arguments, which will make the "meaningless bool" a bit more meaningful.
- VHRanger 7y agoHow will that work with c compatibility?
- WalterBright 7y agoThat's a very good question! When connecting with C code, the C functions being called will need to conform to O/B principles as far as the interface to the function is concerned. It's the same issue as calling unsafe code - the compiler can't check it, the programmer has to. But if you use D as a BetterC compiler, then the D compiler can check the O/B rules in the code. Functions that are O/B checked are marked with the `@live` attribute, meaning that you'll be able to incrementally use O/B in the code. This is much like how you can use the `pure` attribute to incrementally write functionally pure code.
- MaxBarraclough 7y agoWhat's O/B? Google took me right back to your comment.
- biotronic 7y agoWalter got a bit confused here - what he's describing is the owner/borrow system he's proposed to compete with Rust. This is unrelated to named parameters.
- MaxBarraclough 7y agoGot it, thanks.