Re: Question about UDAs
On Mon, Aug 03, 2020 at 08:16:57PM -0700, Ali Çehreli via Digitalmars-d-learn wrote: [...] > UDAs were added to D by a request from Manu Evans and that's when I > learned them. In one of Manu's use cases they would put a @Tweakable > attribute to certain struct members. The effect of that attribute > would be to compile special code that would expose that member in a > dialog box where the developer would "tweak" its value to see how the > program (a game) would behave at specific values of that member. > > The awesomeness comes from the fact that once they have this > @Tweakable machinery, they don't change their code at all: They put > that attribute to certain members during development, find good values > and then remove it; perhaps in half an hour. The only addition to code > is one @Tweakable attribute and some magic produces a dialog box; then > they remove the attribute. Pretty cool. :) I've also used it for generating getopt-like code for parsing command-line parameters. You might have several subsystems in your program, each of which comes with a set of parameters that can be configured; instead of sprinkling this information across multiple places (once in the subsystem to read the values, once in the call to getopt to parse the option, once in the code for display detailed description of the setting, once in configuration file parsing code to basically do the same thing as getopt except with a config file, ad nauseaum), just create a struct that contains the parameters for each subsystem, then use UDAs to decorate each setting with command-line option name, help text, value ranges, or even custom parsing functions if you want to get fancy. Then write a generic option-parsing function that introspects the UDAs to generate help text, option names, default values, precedences, etc.. Another generic function for parsing the config file. Then the next time you want to add a setting, it's just a matter of adding another field to your struct, tag it with the appropriate UDAs, and it will "magically" appear in your command-line, config file parsing, and in-program help text without further ado. Best of all, once you build this infrastructure, you can easily reuse it across different programs: the getopt wrapper, help text generator, config file parser are all completely driven by introspection and UDAs, so there's nothing program-specific about them. Just copy-n-paste them into another project, and create your structs, and you're all set. :-) T -- "I'm not childish; I'm just in touch with the child within!" - RL
Re: Question about UDAs
On 8/2/20 8:00 PM, Cecil Ward wrote: > Ali Çehreli’s book mentions them briefly with an example > but that doesn’t seem to qualify as a realistic use-case. The XML example I chose there qualifies as serialization like H. S. Teoh mentions. UDAs on user-defined type members are for marking them for later introspection in use cases like "do this for all members but take UDAs into account." For example, the UDA in my example contributes as "serialize all members as XML but obfuscate the members that have a special UDA." UDAs were added to D by a request from Manu Evans and that's when I learned them. In one of Manu's use cases they would put a @Tweakable attribute to certain struct members. The effect of that attribute would be to compile special code that would expose that member in a dialog box where the developer would "tweak" its value to see how the program (a game) would behave at specific values of that member. The awesomeness comes from the fact that once they have this @Tweakable machinery, they don't change their code at all: They put that attribute to certain members during development, find good values and then remove it; perhaps in half an hour. The only addition to code is one @Tweakable attribute and some magic produces a dialog box; then they remove the attribute. Pretty cool. :) Manu's presentatian is available here: https://www.youtube.com/watch?v=FKceA691Wcg Slide 25 at minute 18:30 is one spot he talks about it. Ali
Re: Question about UDAs
On Mon, Aug 03, 2020 at 03:00:08AM +, Cecil Ward via Digitalmars-d-learn wrote: > When practically speaking would you use UDAs? A real-world use-case? There are probably more use cases than this, but for me, their primary usefulness is in declarative programming and compile-time introspection. Here's one specific use case: serialization. I have a bunch of structs and classes that I want to serialize, and instead of writing tons and tons of boilerplate, I use __traits(allMembers) to introspect a generic type T and generate serialization code for it. But sometimes some fields should not be serialized (e.g., they are transients like caches and stuff). Or sometimes certain fields may need special treatment, like a different serialization method depending on domain-specific information about their contents. I *could* hard-code this knowledge into the serialization code, but UDAs provide a better alternative: I tag my types with various UDAs recognized by the serialization system, so that when it encounters, say, a string tagged @hexDigits, it knows that it can use a more compact representation by parsing the string into binary and storing it as a compact blob, for example. Or if a field should not be serialized, I'd tag it @dontSerialize and the serialization code skips over it. By using UDAs instead of hard-coding into the serialization code, the serialization can be made generic and reusable across projects. Other use cases include automatically creating database schemas based on types: like a bunch of structs representing records, and UDAs to tag which fields should be indexed, which fields have constraints, etc.. Then the database backend code can just introspect these types and automatically generate schemas, query code, etc.. Since UDAs can be arbitrary types, it actually has a lot of uses. For example, you can use them to inject code for processing data, e.g., by using a struct as UDA with a method that takes the data and performs some operation on it. The generic code that reads the UDA can then pass the data to the method in a completely agnostic way that lets you separate concerns very cleanly. T -- In a world without fences, who needs Windows and Gates? -- Christian Surchi
Re: safety and auto vectorization
On 8/3/20 3:22 PM, Bruce Carneal wrote: Thanks Steve (and Chad). Summary: underspecified, varying behavior across versions, buggy. Steve, what's the best way for me to report this? Are spec issues lumped in with the other bugzilla reports? Yep. You can file under dlang.org with the spec keyword. Although this looks like it's not exactly a spec issue. I'd start it as a dmd bug (I don't know the exact interaction with the compiler and the library). It might also be a druntime bug. -Steve
Re: safety and auto vectorization
On Monday, 3 August 2020 at 18:55:36 UTC, Steven Schveighoffer wrote: On 8/2/20 1:31 PM, Bruce Carneal wrote: import std; void f0(int[] a, int[] b, int[] dst) @safe { dst[] = a[] + b[]; } [snip of auto-vectorization example] I was surprised that f0 ran just fine with a.length and b.length geq dst.length. Is that a bug or a feature? First, I think this is a bug. A regression in fact. As of 2.077 this works, and before it did not. There is nothing in the spec that says the behavior is defined for this case. Second, it's more than just that. This also runs currently: void main() { auto a = [1, 2, 3]; auto b = [4, 5, 6]; int[] dst = new int[4]; // note the extra element dst[] = a[] + b[]; writeln(dst[3]); } Prior to 2.077, this fails with array length problems. After that it prints (at the moment): 402653184 If I up the size to 5, it fails with a range violation. I strongly suspect some off-by-one errors, but this looks unsafe. -Steve Thanks Steve (and Chad). Summary: underspecified, varying behavior across versions, buggy. Steve, what's the best way for me to report this? Are spec issues lumped in with the other bugzilla reports?
Re: safety and auto vectorization
On 8/2/20 1:31 PM, Bruce Carneal wrote: import std; void f0(int[] a, int[] b, int[] dst) @safe { dst[] = a[] + b[]; } void f1(int[] a, int[] b, int[] dst) @trusted { const minLen = min(a.length, b.length, dst.length); dst[0..minLen] = a[0..minLen] + b[0..minLen]; assert(dst.length == minLen); } I was surprised that f0 ran just fine with a.length and b.length geq dst.length. Is that a bug or a feature? Assuming it's a feature, are f0 and f1 morally equivalent? I ask because f1 auto-vectorizes in ldc while f0 does not. Not sure why. As a guess I'd say that the front end doesn't hoist bounds checks in f0 or at least doesn't convey the info to the back end in a comprehensible fashion. Non-guesses welcome. First, I think this is a bug. A regression in fact. As of 2.077 this works, and before it did not. There is nothing in the spec that says the behavior is defined for this case. Second, it's more than just that. This also runs currently: void main() { auto a = [1, 2, 3]; auto b = [4, 5, 6]; int[] dst = new int[4]; // note the extra element dst[] = a[] + b[]; writeln(dst[3]); } Prior to 2.077, this fails with array length problems. After that it prints (at the moment): 402653184 If I up the size to 5, it fails with a range violation. I strongly suspect some off-by-one errors, but this looks unsafe. -Steve
Re: safety and auto vectorization
On Sunday, 2 August 2020 at 17:31:45 UTC, Bruce Carneal wrote: import std; void f0(int[] a, int[] b, int[] dst) @safe { dst[] = a[] + b[]; } void f1(int[] a, int[] b, int[] dst) @trusted { const minLen = min(a.length, b.length, dst.length); dst[0..minLen] = a[0..minLen] + b[0..minLen]; assert(dst.length == minLen); } I was surprised that f0 ran just fine with a.length and b.length geq dst.length. Is that a bug or a feature? Assuming it's a feature, are f0 and f1 morally equivalent? I ask because f1 auto-vectorizes in ldc while f0 does not. Not sure why. As a guess I'd say that the front end doesn't hoist bounds checks in f0 or at least doesn't convey the info to the back end in a comprehensible fashion. Non-guesses welcome. I don't know what's going on auto-vectorization-wise, but to address the behavioral issues, the next thing I would do if I were in your shoes is something like this: import std.stdio; int[100] a, b, dst; a[] = 2; b[] = 3; dst[] = 42; f0(a[0..$], b[0..$], dst[0..50]); // Notice: dst is a smaller slice. writefln("dst[49] == %d", dst[49]); // Should be 5. writefln("dst[50] == %d", dst[50]); // 42 or 5? On my machine (Linux 64-bit DMD v2.093.0) it prints this: dst[49] == 5 dst[50] == 42 Which suggests that it is doing the minimum-length calculation, as the dst[] values outside of the lesser-sized slice were untouched. This was DMD, so it's going to be worth trying on your compiler to see what you get.
Re: Idiomatic D code to avoid or detect devision by zero
On Monday, 3 August 2020 at 14:50:36 UTC, Steven Schveighoffer wrote: On 8/3/20 5:53 AM, Martin Tschierschke wrote: I prefer putting additional bracket around For really long expressions you could also split it on multiple lines: c = (b_expression == 0) ? (d_longer_expression) : (a_expression/b_expression);
Re: Idiomatic D code to avoid or detect devision by zero
On 8/3/20 5:53 AM, Martin Tschierschke wrote: On Friday, 31 July 2020 at 14:18:15 UTC, Steven Schveighoffer wrote: On 7/31/20 9:55 AM, Martin Tschierschke wrote: What would be the idiomatic way to write a floating point division occuring inside a loop and handle the case of division by zero. c = a/b; // b might be zero sometimes, than set c to an other value (d). (In the moment I check the divisor being zero or not, with an if-than-else structure, but I find it ugly and so I ask here.) c = b == 0 ? d : a/b; I don't think a function would be shorter or clearer... c = div(a, b, d); Alternatively, you could use a type to effect the behavior you want. Thanks, for the hints. I find the ? : - expressions sometimes hard to reed, especially when a and b are not so simple expressions. I prefer putting additional bracket around: c = (b_expression == 0) ? (d_longer_expression) : (a_expression/b_expression); Yes, that is fine, and up to your preference. You may actually need the parentheses if the expressions somehow override the precedence of the ?: operator. Even with symbol uses, I personally would do actually: c = (b == 0 ? d : a/b); Just because the ` = b == ` looks really bad to me. -Steve
Re: Are function literals deprecated?
On Monday, 3 August 2020 at 14:23:56 UTC, Victor L Porton wrote: Are function literals considered deprecated in regard of using delegates instead? No, they both work well for different purposes.
Are function literals deprecated?
I am writing a book about D (I already have 150 pages). Are function literals considered deprecated in regard of using delegates instead?
Re: dynamic array .length vs .reserve - what's the difference?
On Saturday, 1 August 2020 at 16:04:01 UTC, Steven Schveighoffer wrote: On 7/31/20 12:32 PM, wjoe wrote: On Friday, 31 July 2020 at 04:28:57 UTC, Ali Çehreli wrote: Another option, which is curiously said to be more performant in memory allocation than native arrays, is std.array.Appender. I've used function-local static Appenders to cut down on memory allocation. Here is an uncompiled pseudo code: [...] This looks like an even better way to do it. Thanks, Ali :) Just FYI, the reason this is faster is because there is no need to go through the opaque calls into druntime to figure out if appending-in-place is possible. The reserved length is stored directly in the struct. -Steve That's good to know, thanks :) By the looks of it, Appender is half duplicating the runtime :)
Re: Idiomatic D code to avoid or detect devision by zero
On Friday, 31 July 2020 at 14:18:15 UTC, Steven Schveighoffer wrote: On 7/31/20 9:55 AM, Martin Tschierschke wrote: What would be the idiomatic way to write a floating point division occuring inside a loop and handle the case of division by zero. c = a/b; // b might be zero sometimes, than set c to an other value (d). (In the moment I check the divisor being zero or not, with an if-than-else structure, but I find it ugly and so I ask here.) c = b == 0 ? d : a/b; I don't think a function would be shorter or clearer... c = div(a, b, d); Alternatively, you could use a type to effect the behavior you want. -Steve Thanks, for the hints. I find the ? : - expressions sometimes hard to reed, especially when a and b are not so simple expressions. I prefer putting additional bracket around: c = (b_expression == 0) ? (d_longer_expression) : (a_expression/b_expression); ???
Re: Idiomatic D code to avoid or detect devision by zero
On Friday, 31 July 2020 at 15:19:25 UTC, Andrea Fontana wrote: On Friday, 31 July 2020 at 13:55:18 UTC, Martin Tschierschke wrote: What would be the idiomatic way to write a floating point division occuring inside a loop and handle the case of division by zero. c = a/b; // b might be zero sometimes, than set c to an other value (d). (In the moment I check the divisor being zero or not, with an if-than-else structure, but I find it ugly and so I ask here.) You should give a look at: https://dlang.org/phobos/std_experimental_checkedint.html You can try with checked!Throw and catch exceptions, for example. Andrea Thanks, I will look at it.