Re: semi-final switch?

2021-06-17 Thread jfondren via Digitalmars-d-learn

On Friday, 18 June 2021 at 04:24:19 UTC, jfondren wrote:
On Thursday, 17 June 2021 at 21:41:28 UTC, Steven Schveighoffer 
wrote:
A final switch on an enum complains if you don't handle all 
the enum's cases. I like this feature.

...
Oh, and to throw a monkey wrench in here, the value is a 
string, not an integer. So I can't use std.conv.to to verify 
the enum is valid (plus, then I'm running a switch twice).


Wanting to avoid more work than a switch means generating a 
switch.

I think that's the real monkey wrench.



Alternately, weave the check you want into your switch:

```d
import std.traits : EnumMembers;
import std.algorithm : map, canFind;
import std.conv : to;

enum C { ABC, XYZ }

alias namesEnum(E) = s => 
[EnumMembers!E].map!(to!string).canFind(s);

enum enumCount(E) = [EnumMembers!E].length;

int example(string k) {
switch (k) {
case "ABC": static assert("ABC".namesEnum!C);
return 1;
case "XYZ": static assert("XYZ".namesEnum!C);
return 2;
default: static assert(2 == enumCount!C);
return 0;
}
}

unittest {
example("force asserts");
}
```

but this repeats the keys (which could be mis-repeated), and it
requires hand-counting the cases checked (which could be 
mis-counted).

At least it's easier to check without reference to the enum.

What I wanted to do was add "ABC" to a static string[] and
confirm that it's a permutation of 
[EnumMembers!C].map!(to!string).


Re: semi-final switch?

2021-06-17 Thread Mathias LANG via Digitalmars-d-learn
On Thursday, 17 June 2021 at 21:41:28 UTC, Steven Schveighoffer 
wrote:
A final switch on an enum complains if you don't handle all the 
enum's cases. I like this feature.


However, sometimes the data I'm switching on is coming from 
elsewhere (i.e. a user), and while I want to enforce that the 
data is valid (it's one of the enum values), I don't want to 
crash the program if the incoming value is not correct. But 
final switch doesn't let me declare a default case (to throw an 
exception instead).


If I use a non-final switch, then my code might forget to 
handle one of the cases.


Oh, and to throw a monkey wrench in here, the value is a 
string, not an integer. So I can't use std.conv.to to verify 
the enum is valid (plus, then I'm running a switch twice).


Any ideas on better ways to handle this?

-Steve


Well, if you receive an `enum` that have an out of bounds value, 
your problem lies in the caller, not the callee. You're breaking 
the most fundamental promise of a type, that is, the values it 
can take. And you obviously also break any `@safe` function by 
feeding it this value.


So instead of thinking in terms of `enum`, I would say, think in 
them of the value, and generate the switch:

```D
SWITCH: switch (myRawValue)
{
static foreach (EV; NoDuplicates!(EnumMembers!MyEnum))
{
case EV:
// Handle;
break SWITCH;
}
default:
throw new Exception("Invalid value: " ~ myRawValue);
}
```

Note that this can be encapsulated in its own function, like 
`validateEnum (EnumType) (BaseType!EnumType value)` (not sure if 
we have a `BaseType` template, but you get the point).


Re: semi-final switch?

2021-06-17 Thread jfondren via Digitalmars-d-learn
On Thursday, 17 June 2021 at 21:41:28 UTC, Steven Schveighoffer 
wrote:
A final switch on an enum complains if you don't handle all the 
enum's cases. I like this feature.

...
Oh, and to throw a monkey wrench in here, the value is a 
string, not an integer. So I can't use std.conv.to to verify 
the enum is valid (plus, then I'm running a switch twice).


Wanting to avoid more work than a switch means generating a 
switch.

I think that's the real monkey wrench.

Something like:

```d
T enumCases(T, E, T[E] cases)(string x) {
import std.format : format;
import std.algorithm : map, all, joiner;
import std.array : array;
import std.traits : EnumMembers;
import std.conv : to;

mixin("switch (x) {\n" ~
[EnumMembers!E].map!(e =>
format!"case %(%s%): return %(%s%);\n"([e.to!string], 
[cases[e]]))

.joiner.array ~
"default: assert(0);\n}");
}

unittest {
enum C { ABC, XYZ }

assert("x\tb" == enumCases!(string, C, [
C.ABC: "x\tb",  // error to omit an enum value
C.XYZ: "ab",// impossible to have a bad enum value
])("ABC"));

// the first problem with this solution: the following is an 
error...

// unless the preceding usage is commented out.
/+assert(2 == enumCases!(int, C, [
C.ABC: 1,
C.XYZ: 2,
])("XYZ"));+/
}
```


Re: Vibe.d diet templates

2021-06-17 Thread JG via Digitalmars-d-learn

On Thursday, 17 June 2021 at 18:54:41 UTC, WebFreak001 wrote:

On Thursday, 17 June 2021 at 16:26:57 UTC, JG wrote:

[...]

Thanks, this works. I would have thought this would be a 
common enough use case to have support in diet. Anyone else 
wanted this?


Opened an issue here: 
https://github.com/rejectedsoftware/diet-ng/issues/91


Thanks for opening that issue.


Re: semi-final switch?

2021-06-17 Thread Dennis via Digitalmars-d-learn
On Thursday, 17 June 2021 at 21:41:28 UTC, Steven Schveighoffer 
wrote:

Any ideas on better ways to handle this?


I've had such a situation before too where I want to switch over 
enums I read from an ELF file which can't be assumed to be 
correct, but I also don't want to forget one. For a tight 
numerical enum you simply check `if (i <= EnumType.max)`, but 
when there's gaps (or strings like in your case) that doesn't 
work. I got the idea for a DIP to allow a `default` statement in 
`final switch` to allow a custom error handler instead of the 
default `__switch_error`, but never pursued it further. I'm still 
in favor of it though.




Re: semi-final switch?

2021-06-17 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Jun 17, 2021 at 05:41:28PM -0400, Steven Schveighoffer via 
Digitalmars-d-learn wrote:
[.[..]
> Oh, and to throw a monkey wrench in here, the value is a string, not
> an integer. So I can't use std.conv.to to verify the enum is valid
> (plus, then I'm running a switch twice).
> 
> Any ideas on better ways to handle this?
[...]

Why not just:

try {
MyEnum value = input.to!MyEnum;
} catch (Exception e) {
stderr.writeln("Invalid input");
}

?


T

-- 
People demand freedom of speech to make up for the freedom of thought which 
they avoid. -- Soren Aabye Kierkegaard (1813-1855)


semi-final switch?

2021-06-17 Thread Steven Schveighoffer via Digitalmars-d-learn
A final switch on an enum complains if you don't handle all the enum's 
cases. I like this feature.


However, sometimes the data I'm switching on is coming from elsewhere 
(i.e. a user), and while I want to enforce that the data is valid (it's 
one of the enum values), I don't want to crash the program if the 
incoming value is not correct. But final switch doesn't let me declare a 
default case (to throw an exception instead).


If I use a non-final switch, then my code might forget to handle one of 
the cases.


Oh, and to throw a monkey wrench in here, the value is a string, not an 
integer. So I can't use std.conv.to to verify the enum is valid (plus, 
then I'm running a switch twice).


Any ideas on better ways to handle this?

-Steve


Re: Arrays of variants, C++ vs D

2021-06-17 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/17/21 5:01 PM, Ali Çehreli wrote:



What's the difference? In both cases an int is being converted to a Foo. 
I think the "working" case is against the design of D.


Likely there is a subtlety that I am missing...


The difference might be that construction has only one set of overloads 
-- the constructor of the item being created. With your example, there's 
the set of overloads to create a Foo and the set of overloads to call foo.


Imagine this:

struct Foo
{
   int x;
   this(int y) { x = y; }
}

struct Bar
{
   int x;
   this(int y) { x = y; }
}

void foo(Foo f){}
void foo(Bar b){}

void main()
{
   foo(42); // which one?
}

But I don't know. I know that there are all kinds of subtle problems 
with C++ implicit conversions, and D is right to avoid all that. But 
this might be one case where the decision tree is easy.


-Steve


Re: Arrays of variants, C++ vs D

2021-06-17 Thread Ali Çehreli via Digitalmars-d-learn

On 6/17/21 1:46 PM, Steven Schveighoffer wrote:

> Implicit construction is supported:
>
> struct Foo
> {
> int x;
> this(int y) { x = y; }
> }
>
> Foo f = 5; // ok implicit construction

That's so unlike the rest of the language that I consider it to be a 
bug. :) Really, why? What if the expression is more complicated:


int i() {
  return 1;
}

  Foo f = i();

OK, that works as well. Wow!

But the following doesn't and is what I think Walter has been trying to 
prevent:


struct Foo
{
   int x;
   this(int y) { x = y; }
}

void foo(Foo) {
}

void main() {
  foo(42);// COMPILATION ERROR
}

What's the difference? In both cases an int is being converted to a Foo. 
I think the "working" case is against the design of D.


Likely there is a subtlety that I am missing...

Ali



Re: Vibe.d diet templates

2021-06-17 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/17/21 4:22 PM, kdevel wrote:

On Thursday, 17 June 2021 at 19:14:28 UTC, Steven Schveighoffer wrote:

On 6/17/21 12:26 PM, JG wrote:

However, what I *have* wanted is to have attribute values support 
`Nullable!T` such that they are only included if the item is non-null. 
See [here](https://github.com/rejectedsoftware/diet-ng/issues/28).


BTW: Is it possible to replace the diet generator in vibe.d with a 
template engine like moustache [1] which is agnostic wrt the code it 
produces? In the past 25 or so years I frequently encountered designed 
HTML pages where only some data had to be inserted here or there. If I 
got the vibe.d model right one would have to reimplement these HTML 
pages in the diet language first.


[1] https://github.com/repeatedly/mustache-d



Of course. Vibe's diet support is wholly based on the diet-ng project, 
and you don't have to use it. It's just there out of the box.


when you do:

```d
res.render!("sometemplate.dt", all, my, args);
```

It's just a UFCS call. You could replace this with:

res.renderMustache(...)

Where you have to write the adapter. It's possible to get a char output 
range out of HTTPServerResponse, which you then can write to and it's 
just sent back to the client.


This seems like it would do the trick, you just have to pass the output 
range in as the sink:


https://mustache-d.dpldocs.info/mustache.MustacheEngine.render.2.html

-Steve


Re: Arrays of variants, C++ vs D

2021-06-17 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/17/21 4:15 PM, H. S. Teoh wrote:

On Thu, Jun 17, 2021 at 07:44:31PM +, JN via Digitalmars-d-learn wrote:
[...]

 Foo[int] foos = [
 0: Foo("abc"),
 1: Foo(5)
 ];
}
```

Why does D need the explicit declarations whereas C++ can infer it?


Because D does not support implicit construction. The array literal is
parsed as-is, meaning string[int] is inferred rather than Foo[int]. So
the initialization fails because of a type mismatch.


Implicit construction is supported:

struct Foo
{
   int x;
   this(int y) { x = y; }
}

Foo f = 5; // ok implicit construction

What is happening here though is that the construction is being done as 
an AA literal. This works for *some* types, but not all.


e.g.:

Foo[int] f = [5 : 5]; // error
double[int] f = [5 : 5]; // ok

It really should work IMO.

-Steve


Re: Vibe.d diet templates

2021-06-17 Thread kdevel via Digitalmars-d-learn
On Thursday, 17 June 2021 at 19:14:28 UTC, Steven Schveighoffer 
wrote:

On 6/17/21 12:26 PM, JG wrote:

However, what I *have* wanted is to have attribute values 
support `Nullable!T` such that they are only included if the 
item is non-null. See 
[here](https://github.com/rejectedsoftware/diet-ng/issues/28).


BTW: Is it possible to replace the diet generator in vibe.d with 
a template engine like moustache [1] which is agnostic wrt the 
code it produces? In the past 25 or so years I frequently 
encountered designed HTML pages where only some data had to be 
inserted here or there. If I got the vibe.d model right one would 
have to reimplement these HTML pages in the diet language first.


[1] https://github.com/repeatedly/mustache-d



Re: Arrays of variants, C++ vs D

2021-06-17 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Jun 17, 2021 at 07:44:31PM +, JN via Digitalmars-d-learn wrote:
[...]
> Foo[int] foos = [
> 0: Foo("abc"),
> 1: Foo(5)
> ];
> }
> ```
> 
> Why does D need the explicit declarations whereas C++ can infer it?

Because D does not support implicit construction. The array literal is
parsed as-is, meaning string[int] is inferred rather than Foo[int]. So
the initialization fails because of a type mismatch.

Implicit construction has been asked for many times, but Walter has been
adamant about not allowing implicit construction in D.


T

-- 
Music critic: "That's an imitation fugue!"


Arrays of variants, C++ vs D

2021-06-17 Thread JN via Digitalmars-d-learn

This C++ code compiles:
```cpp
#include 
#include 
#include 

int main()
{
using Foo = std::variant;
std::map foos =  {{0, "abc"}, {1, 5}};
}

This code doesn't:

```d
import std.variant;

void main()
{
alias Foo = Algebraic!(int, string);
Foo[int] foos = [
0: "abc",
1: 5
];
}
```
but this does:

```d
import std.variant;

void main()
{
alias Foo = Algebraic!(int, string);
Foo[int] foos = [
0: Foo("abc"),
1: Foo(5)
];
}
```

Why does D need the explicit declarations whereas C++ can infer 
it?


Re: Vibe.d diet templates

2021-06-17 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/17/21 12:26 PM, JG wrote:

Thanks, this works. I would have thought this would be a common enough 
use case to have support in diet. Anyone else wanted this?


I haven't found a need for it, as I'm usually only dynamically 
configuring attribute values, not attribute names. But my web-fu is 
pretty weak.


However, what I *have* wanted is to have attribute values support 
`Nullable!T` such that they are only included if the item is non-null. 
See [here](https://github.com/rejectedsoftware/diet-ng/issues/28).


-Steve


Re: Vibe.d diet templates

2021-06-17 Thread WebFreak001 via Digitalmars-d-learn

On Thursday, 17 June 2021 at 16:26:57 UTC, JG wrote:

[...]

Thanks, this works. I would have thought this would be a common 
enough use case to have support in diet. Anyone else wanted 
this?


Opened an issue here: 
https://github.com/rejectedsoftware/diet-ng/issues/91


Re: List of Dynamic Arrays

2021-06-17 Thread Ali Çehreli via Digitalmars-d-learn

On 6/17/21 9:10 AM, Justin Choi wrote:

>> DList!(int[])() ?
>
> Thanks I've mentally slapped myself a hundred times for this mistake :D

Also, unless DList is really needed, why not:

  int[][]

Ali



Re: Vibe.d diet templates

2021-06-17 Thread JG via Digitalmars-d-learn

On Thursday, 17 June 2021 at 09:16:56 UTC, WebFreak001 wrote:

On Thursday, 17 June 2021 at 08:23:54 UTC, JG wrote:
Suppose I have an array of attributes and values v is there 
any way to apply these attributes to a tag?


So that something like

tag(#{v[0]0]}=#{v[0][1]},...})

becomes



where v[0][0]="attribute0" and v[0][1]="value0"?


I think there is nothing for this built-in in diet, so you have 
to manually emit raw HTML:


```diet
- import std.xml : encode;
- auto start = appender!string;
- start ~= "

Thanks, this works. I would have thought this would be a common 
enough use case to have support in diet. Anyone else wanted this?


Re: List of Dynamic Arrays

2021-06-17 Thread Justin Choi via Digitalmars-d-learn

On Thursday, 17 June 2021 at 15:58:40 UTC, Adam D Ruppe wrote:

On Thursday, 17 June 2021 at 15:57:46 UTC, Justin Choi wrote:

I want to write something like `DList!int[]()`


DList!(int[])() ?


Thanks I've mentally slapped myself a hundred times for this 
mistake :D


List of Dynamic Arrays

2021-06-17 Thread Justin Choi via Digitalmars-d-learn
If I wanted to create a DList (or any similar data structure) of 
multiple integers, how would I accomplish this?


I want to write something like `DList!int[]()` but the best I can 
do for now is a format such as `DList!(Tuple(int, int))()` which 
confines me to a fixed number of integers.


Re: List of Dynamic Arrays

2021-06-17 Thread Adam D Ruppe via Digitalmars-d-learn

On Thursday, 17 June 2021 at 15:57:46 UTC, Justin Choi wrote:

I want to write something like `DList!int[]()`


DList!(int[])() ?


Re: Vibe.d diet templates

2021-06-17 Thread WebFreak001 via Digitalmars-d-learn

On Thursday, 17 June 2021 at 08:23:54 UTC, JG wrote:
Suppose I have an array of attributes and values v is there any 
way to apply these attributes to a tag?


So that something like

tag(#{v[0]0]}=#{v[0][1]},...})

becomes



where v[0][0]="attribute0" and v[0][1]="value0"?


I think there is nothing for this built-in in diet, so you have 
to manually emit raw HTML:


```diet
- import std.xml : encode;
- auto start = appender!string;
- start ~= "

Vibe.d diet templates

2021-06-17 Thread JG via Digitalmars-d-learn
Suppose I have an array of attributes and values v is there any 
way to apply these attributes to a tag?


So that something like

tag(#{v[0]0]}=#{v[0][1]},...})

becomes



where v[0][0]="attribute0" and v[0][1]="value0"?





Re: Can not get struct member addresses at compile time

2021-06-17 Thread Doeme via Digitalmars-d-learn

On Wednesday, 16 June 2021 at 23:20:26 UTC, Ali Çehreli wrote:
Thank you, both. It still rules out an address at "compile 
time" in general. For example, we cannot use such an address 
when instantiating a template, or static array length, etc.


And if I understand it correctly, there must be a pointer 
*variable* for the linker to initialize. Fine then: That's how 
this usage works for C but not for D. :)


Thank you,
Ali


Yes, there must be a pointer variable, which explains why we can 
not do compile time pointer arithmetic, which is fair and square 
(although I think it might be possible with some extra compiler 
effort). It does _not_ explain why we can't take addresses of 
struct members, though, since we have a pointer variable there!


Coming back to the working part of my first example:

```d
struct Foo{
int bar;
}

__gshared Foo foo;
void *fooptr = 
```

This works! And yields very similar relocations than the C 
version (plus some overhead and name-mangling):


```

[...]

  wO 
.data._D19TypeInfo_S4test3Foo6__initZ	0091 
_D19TypeInfo_S4test3Foo6__initZ

 g O .bss   0004 _D4test3Foo6__initZ
0004 g O .bss   0004 _D4test3fooSQk3Foo
 g   .tdata.0008 _D4test6fooptrPv
 g O .rodata	000d 
_D4test12__ModuleInfoZ


[...]

RELOCATION RECORDS FOR [.tdata.]:
OFFSET   TYPE  VALUE
 R_X86_64_64   _D4test3fooSQk3Foo

[...]

```

The only difference is that the compiler will not pass down 
relocations plus an offset (i.e. relocating to a member of a 
struct) down to the linker, and I don't quite see a specific 
reason why it should not.