Does D-mini use an anti-pattern to reuse code?

For those of you who are new to D mix mixins, they are mostly compile-time estimates. You can take any string of compilation time (whether it is literal or metaprogrammed by a template or compilation of a time function) and compile it as code. If you use a simple string literal, it is basically a compiler-auto copy-paste compiler.

Don't you consider the use of literal string mixins as a means of simple code reuse when other factoring methods are not quite suitable? On the one hand, it is mainly a compiler-automatic literal copy and paste, which means that once mixed instances have nothing to do with each other. Bad things will happen (although at compile time, not at runtime) if the character in the mixin string collides with the character in the mixed scope. It is relatively unstructured in that it is possible, for example, to mix a string in the middle of a function that will work if and only if the variables in the field are named according to a certain convention. Mixins can also declare variables that external regions can then use as they wish.

On the other hand, since automatic copying and pasting is automated, there is only one truth point for this code at the source level, and if you need to change it, you need to change it only in one place, and everything remains in sync. String mixins also greatly simplify code reuse, which is very difficult to influence in any other way and would otherwise have a very high chance of manual and manual manual copying.

+6
design d anti-patterns
source share
3 answers

All the criticisms you raised are true.

Despite this, it still surpasses the manual copy.

Actually, I have something similar in my tool library, table row extension. Sample code from the implementation of the dynamic value of the path tracer:

T to(T)() { static if (!is(T == Scope)) { T value; if (flatType == FlatType.ScopeValue) value = sr.value().to!(T); } const string Table = ` | bool | int | string | float | Scope -----------+---------------+-------------+----------------------+---------+---------- Boolean | b | b | b?q{true}p:q{false}p | ø | ø Integer | i != 0 | i | Format(i) | i | ø String | s == q{true}p | atoi(s) | s | atof(s) | ø Float | ø | cast(int) f | Format(f) | f | ø ScopeRef | !!sr | ø | (sr?sr.fqn:q{(null:r)}p) | ø | sr ScopeValue | value | value | value | value | sr`; mixin(ctTableUnrollColMajor(Table, `static if (is(T == $COL)) switch (flatType) { $BODY default: throw new Exception(Format("Invalid type: ", flatType)); } else `, `case FlatType.$ROW: static if (q{$CELL}p == "ø") throw new Exception(q{Cannot convert $ROW to $COL: }p~to!(string)~q{! }p); else return $CELL; ` ).litstring_expand() ~ `static assert(false, "Unsupported type: "~T.stringof); `); } 

I'm sure it’s easy to see what a terrible excess mess of nested ifs and case statements that would be without mixins lines - thus, all the ugliness is concentrated below, and the actual behavior of the function is easy to read at a glance.

+9
source share

While other, more elegant solutions can be better used, if you can, string mixins can be extremely useful. They allow you to use both code reuse and code generation. They are checked at compile time. The code that is the result is exactly the same as if you yourself wrote it yourself, so it is no less secure than if you yourself wrote it.

The problem with string mixins is that they are harder to control than manually written code in the sense that it is not physically placed in your source identically with line numbers that are clearly traceable to errors, and can be harder to debug. For example, take the hello world with a string mixin:

 import std.stdio; void main() { mixin(hello()); } string hello() { return " writeln(\"hello world\"); "; } 

If we removed the semicolon after writeln() , then the resulting error would be

 dd(7): found 'EOF' when expecting ';' following statement 

The mixin is executed on line 5. Line 7 is an empty line. So the line number has limited utility here. Now this mixin is short enough so that we can put it on one line and get it to say that the error was on the same line as mixin, but with more complex mixins, which obviously will not work. Thus, using a combination of strings, your ability to determine where the error is broken. If the code was generated using CTFE, then it would be much harder to figure out what exactly the code looks like to figure out what is wrong with it. This is very similar to what code turns into a C-style macro, except that it can be worse because they can be generated rather than a direct replacement. However, they do not replace, unless you explicitly specify them, so they are much safer than C-style macros.

String mixins are absolutely safe and nothing really bad with them, but they make maintenance more difficult in some way. Corresponding handwritten code will be easier to debug. However, streaming mixins are powerful enough that they can do a lot of code generation for you and save you a lot of support costs in this sense, and they allow you to reuse the code, which can also be a big boost.

Thus, regardless of whether the string uses mixin, a good idea in a particular situation depends on that situation. I don’t see anything special in them, and of course I would not call them an anti-pattern, but there are pros and cons to using them so that they are a good idea, it depends on what you do, In many cases there are more elegant, cleaner solutions that would be better. In others, this is exactly what the doctor ordered.

Personally, I think that they are fantastic if you want to generate code, eliminating the need to write this code manually and, possibly, simplify the creation of the correct code for various situations and avoid the risk of creating new errors, as, for example, you wrote it yourself in each from the places where you used mixin. It is also one way to simply reuse code without having to worry about the cost of a function call or problems with unidirectional constraints or anything else that makes code reuse more difficult to call functions or inheritance. You simply copy and paste the code in each place so that when you change the code, the changes are correctly inserted everywhere, without the need to worry about tracking them all, as if you had a manual copy and pasted.

So, use string mixins if necessary, and it's probably best not to use them if you don't need them, but there is nothing wrong with using them.

+2
source share

String mixin is similar to goto: it should be avoided where possible and should be used wherever necessary.

+1
source share

All Articles