Re: Question about UDAs

2020-08-03 Thread H. S. Teoh via Digitalmars-d-learn
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

2020-08-03 Thread Ali Çehreli via Digitalmars-d-learn

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

2020-08-03 Thread H. S. Teoh via Digitalmars-d-learn
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

2020-08-03 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2020-08-03 Thread Bruce Carneal via Digitalmars-d-learn
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

2020-08-03 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2020-08-03 Thread Chad Joan via Digitalmars-d-learn

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

2020-08-03 Thread Dominikus Dittes Scherkl via Digitalmars-d-learn
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

2020-08-03 Thread Steven Schveighoffer via Digitalmars-d-learn

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?

2020-08-03 Thread Adam D. Ruppe via Digitalmars-d-learn

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?

2020-08-03 Thread Victor L Porton via Digitalmars-d-learn

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?

2020-08-03 Thread wjoe via Digitalmars-d-learn
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

2020-08-03 Thread Martin Tschierschke via Digitalmars-d-learn
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

2020-08-03 Thread Martin Tschierschke via Digitalmars-d-learn

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.