Re: foreach iterator with closure

2020-06-28 Thread Denis via Digitalmars-d-learn

To keep this reply brief, I'll just summarize:

Lots of great takeaways from both of your posts, and a handful of 
topics you mentioned that I need to dig into further now. This is 
great (I too like D :)


I very much appreciate the extra insight into how things work and 
why certain design decisions were made: for me, this is essential 
for gaining fluency in a language.


Thanks again for all your help!
Denis


Re: foreach iterator with closure

2020-06-28 Thread Denis via Digitalmars-d-learn
Many thanks: your post has helped me get past the initial 
stumbling blocks I was struggling with. I do have a followup 
question.


First, here are my conclusions up to this point, based on your 
post above, some additional experimentation, and further research 
(for future reference, and for any other readers).


* foreach is the actual iterator, the instantiation of a struct 
is the range.
* When a constructor is not used, the arguments in the call to 
instantiate the range (in this case, `hello` in letters(`hello`)) 
are mapped sequentially to the member variables in the struct 
definition (i.e. to letters.str).
* When a constructor is used, the member variables in the struct 
definition are in essence private. The arguments in the call to 
instantiate the range are now mapped directly to the parameters 
in the definition of the "this" function.
* The syntax and conventions for constructors is difficult and 
non-intuitive for anyone who hasn't learned Java (or a 
derivative). The linked document provides a simplified 
explanation for the "this" keyword, which is helpful for the 
first read: 
https://docs.oracle.com/javase/tutorial/java/javaOO/thiskey.html.
* In some respects, the Java syntax is not very D-like. (For 
example, it breaks the well-established convention of "Do not use 
the same name to mean two different things".) However, it does 
need to be learned, because it is common in D source code.


Here is the complete revised code for the example (in condensed 
form):


  import std.stdio;

  struct letters {

string str;
int pos = 1;// Assign here or in this())

this(string param1) {   // cf. shadow str
  str = param1; // cf. this.str = param1 / this.str = str
  writeln(`BEGIN`); }

char front() { return str[pos]; }
void popFront() { pos ++; }
bool empty() { return pos == str.length; }

~this() { writeln("\nEND"); }}

  void main() {
foreach (letter; letters(`hello`)) {
  write(letter, ' '); }}

At this point, I do have one followup question:

Why is the shadow str + "this.str = str" the more widely used 
syntax in D, when the syntax in the code above is unambiguous?


One possible reason that occurred to me is that "str = param1" 
might require additional GC, because they are different names. 
But I wouldn't think it'd make any difference to the compiler.


Denis


foreach iterator with closure

2020-06-27 Thread Denis via Digitalmars-d-learn
Is it possible to write an iterator that does the following, 
using a struct and some functions?


 - Operates in a foreach loop
 - Has BEGIN-like and END-like blocks or functions that are 
executed automatically, before and after the iterations
 - Initializes variables in the BEGIN block that are used in the 
other two. These variables are for internal use only, i.e. must 
not be accessible to the user of the foreach loop


I'd like to use the simplest solution while keeping the code 
clean. As a starting point, here's a contrived example using a 
struct with a range-style iterarator:


  import std.stdio;

  struct letters {
string str;
int pos = 0;
char front() { return str[pos]; }
void popFront() { pos ++; }
bool empty() {
  if (pos == 0) writeln(`BEGIN`);
  else if (pos == str.length) writeln("\nEND");
  return pos == str.length; }}

  void main() {
foreach (letter; letters(`hello`)) {
  write(letter, ' '); }
writeln(); }

The obvious problems with this code include:

(1) The user can pass a second argument, which will set the 
initial value of pos. This must not be allowed. (The real code 
will need to initialize a half dozen internal-only variables, and 
do some additional work, before the looping starts.)


(2) Sticking the code for the BEGIN and END blocks into the 
empty() function is ugly.


Can this iterator be written using a range-style struct? Or is 
something more complicated needed, like an OO solution?


I should add that the final version of this will be put in a 
separate module, possibly in a library, so I can call it from 
many programs. Not sure if that might help simplify things.


Thanks for your guidance.


Re: Calling C functions

2020-06-26 Thread Denis via Digitalmars-d-learn

On Friday, 26 June 2020 at 08:15:27 UTC, Jacob Carlborg wrote:

On Friday, 26 June 2020 at 00:30:22 UTC, Denis wrote:



  extern(C) void cfunc(void function(int));
  extern(C) void dcallback(int x) {...} <-- Why extern(C)?
  cfunc();

Can this be rewritten, dropping the prefix from the second 
line? If not, it would be helpful to know why "extern(C)" is 
needed here too.


No, it cannot be dropped. `extern(C)` is required because C and 
D are using different calling conventions (D functions are also 
mangled). For example, D (at least DMD and LDC) are passing the 
arguments to the function in reverse.


OK, now this makes sense.

I tested calling the same callback function directly from D: it 
compiled and worked correctly. So at least prefixing the callback 
function with `extern(C)` doesn't prevent the rest of the D 
program from calling it too.


(2) Is there a way to restrict the invocation of a linked C 
function to one specific D function?


[...]

For functions nested in a D language construct (class, struct, 
function) the compiler will always use the D mangling, instead 
of the C mangling. In theory it would be possible to workaround 
that by forcing the mangled name using `pragma(mangle)`, but 
for some reason the compiler doesn't allow `pragma(mangle)` 
inside a function body, on a nested function declaration.


You can wrap up everything in a struct, as follows:


I see.

Thank you very much for these explanations and code -- the 
insights are very helpful.


Denis


Calling C functions

2020-06-25 Thread Denis via Digitalmars-d-learn

I have a two questions about calling C functions from D.

(1) When passing a D callback to a C function, is there a way to 
write the code without having to prefix the callback declaration 
with "extern(C)"?


It's not a big deal adding the prefix to the D function 
declaration. It just seems odd to me to prefix D code with 
"extern(C)". For example, the following code works:


  extern(C) void cfunc(void function(int));
  extern(C) void dcallback(int x) {...} <-- Why extern(C)?
  cfunc();

Can this be rewritten, dropping the prefix from the second line? 
If not, it would be helpful to know why "extern(C)" is needed 
here too.


(2) Is there a way to restrict the invocation of a linked C 
function to one specific D function?


If the C header is defined in one of the core.stdc libraries, the 
import statement can either be global or inside a specific D 
function -- both work. In contrast, when the C function prototype 
is written directly into the D program (as above), the linker 
complains unless this declaration is made global. If it's 
possible to restrict the scope of the C function to just one D 
function, I'll take advantage.


(I'm using dmd, if that makes a difference.)

Thanks


Re: Flagging special conditions on return from a function call

2020-06-23 Thread Denis via Digitalmars-d-learn

On Tuesday, 23 June 2020 at 21:34:25 UTC, Paul Backus wrote:


If you're open to using Dub packages [...]


Because this is going to be used in almost every program I write, 
I need to eliminate outside dependencies as an option. 
Nonetheless, thanks for this suggestion.


[2] 
https://pbackus.github.io/blog/beating-stdvisit-without-really-trying.html


I did read your blog post: that's an impressive result. Good to 
know that well-written D code can be competitive with C.


Denis


Re: Flagging special conditions on return from a function call

2020-06-23 Thread Denis via Digitalmars-d-learn
Perhaps this thread would have been better titled "Returning a 
value and a status", and the question phrased as "What are your 
preferred techniques?".


I'm planning to port some of my programs to D, so I'd like to 
standardize on one or two techniques for handling this very 
common situation, in a way that suits the language. I'd 
appreciate hearing from others about what you do.


---

On Tuesday, 23 June 2020 at 06:52:29 UTC, Simen Kjærås wrote:

On Tuesday, 23 June 2020 at 04:01:45 UTC, Denis wrote:


[...]

(4) Set the function return value normally, and put the flag 
in an "out" variable passed as an argument to the function
(5) Return the flag, and put the value in an "out" variable 
passed to the function (i.e. the reverse of #4)


Both of these happen. I don't know which is more common. In C# 
these are probably the most common way (except for exceptions) 
to signal these cases.


Good to know. Both of these techniques (or something similar) are 
used in Perl too. The choice seemed to depend on which one the 
author thought would be more useful as the return.


[...]

by presenting an interface that only compiles when both cases 
are covered, like fun().match((T t) => t, () => Error()).


A complete solution wrapped in a tidy package -- I like it.

Thanks for sharing.


Flagging special conditions on return from a function call

2020-06-22 Thread Denis via Digitalmars-d-learn
Is there a preferred idiom in D for flagging special conditions 
when returning from a function call? Here "special conditions" 
refers to expected situations (e.g. reaching the end of 
something, like EOF) rather than outright errors (so 
exception-try-catch is inappropriate).


I've come across many ways for a function to return both a value 
and flag, including:


(1) Assign an unused value for the flag (e.g. -1 when the 
function returns an int), and return the combined value/flag.

(2) Return a tuple with the value and the flag
(3) Return a struct or tuple with named value and flag members
(4) Set the function return value normally, and put the flag in 
an "out" variable passed as an argument to the function
(5) Return the flag, and put the value in an "out" variable 
passed to the function (i.e. the reverse of #4)
(6) Use two separate functions, one that returns the value, and 
another that can be called afterwards to check the flag (like 
eof(), for example)

(7) Use a side effect and set a designated global variable

I'm sure there are others.

* Is there a preferred approach?
* Which ones are discouraged?
* General recommendations or guidelines?

If there is a best practice, I'd rather learn it sooner than many 
lines of code later.


(In the interest of brevity, I'll limit my own comments in this 
post to the following: In the past, I've tried to adhere to KISS. 
This means that I would generally prefer #1. But often it isn't 
possible to combine the value and flag that way, in which case 
one of the other methods must be used.)


Re: Some questions about strings

2020-06-22 Thread Denis via Digitalmars-d-learn

On Monday, 22 June 2020 at 09:06:35 UTC, Jacob Carlborg wrote:

String **literals** have a terminating null character, to help 
with integrating with C functions. But this null character will 
disappear when manipulating strings.


You cannot assume that a function parameter of type `string` 
will have a terminating null character, but calling `printf` 
with a string literal is fine:


printf("foobar\n"); // this will work since string literals 
have have a terminating null character


OK, it makes sense that the null terminator would be added where 
compatability with C is required.


Good to know.


Re: Some questions about strings

2020-06-21 Thread Denis via Digitalmars-d-learn

On Monday, 22 June 2020 at 04:32:32 UTC, Mike Parker wrote:

On Monday, 22 June 2020 at 04:08:10 UTC, Denis wrote:

On Monday, 22 June 2020 at 03:31:17 UTC, Ali Çehreli wrote:
:

string is char[]
wstring is wchar[]
dstring is dchar[]


Got it now. This is the critical piece I missed: I understand 
the relations between the char types and the UTF encodings 
(thanks to your book). But I mistakenly thought that the 
string types were different.




They're aliases in object.d:

https://github.com/dlang/druntime/blob/master/src/object.d#L35


Right at the top and plain as day too... ;)

I appreciate the link to the source -- thanks!


Re: Some questions about strings

2020-06-21 Thread Denis via Digitalmars-d-learn

On Monday, 22 June 2020 at 03:31:17 UTC, Ali Çehreli wrote:
:

string is char[]
wstring is wchar[]
dstring is dchar[]


Got it now. This is the critical piece I missed: I understand the 
relations between the char types and the UTF encodings (thanks to 
your book). But I mistakenly thought that the string types were 
different.


You can reveal some of the mystery by looking at their .length 
property. Additionally, foreach will visit these types 
element-by-element: char, wchar, and dchar, respectively.


I did not try this test -- my bad.


null character is not required but may be a part of the strings.


The terminating null character was one of the reasons I thought 
strings were different from char arrays. Now I know better.


Thank you for these clarifications.
Denis


Re: Some questions about strings

2020-06-21 Thread Denis via Digitalmars-d-learn

On Monday, 22 June 2020 at 03:49:01 UTC, Adam D. Ruppe wrote:

On Monday, 22 June 2020 at 03:43:58 UTC, Denis wrote:
My code reads a UTF-8 encoded file into a buffer and 
validates, byte by byte, the UTF-8 encoding along with some 
additional validation. If I simply return the UTF-8 encoded 
string, there won't be another decoding/encoding done -- 
correct?


Yeah D doesn't do extra work when you are just passing stuff 
around, only when you specifically ask for it by calling a 
function or maybe doing foreach (depends on if you ask for char 
or dchar in the foreach type)


Excellent. I'm trying to make this efficient, so I'm doing all of 
the validation together, without using any external functions 
(apart from the buffer reads).


Thanks!


Re: Some questions about strings

2020-06-21 Thread Denis via Digitalmars-d-learn

On Monday, 22 June 2020 at 03:24:37 UTC, Adam D. Ruppe wrote:

On Monday, 22 June 2020 at 03:17:54 UTC, Denis wrote:
- First, is there any difference between string, wstring and 
dstring?


Yes, they encode the same content differently in the bytes. If 
you cast it to ubyte[] and print that out you can see the 
difference.


- Are the characters of a string stored in memory by their 
Unicode codepoint(s), as opposed to some other encoding?


no, they are encoded in utf-8, 16, or 32 for string, wstring, 
and dstring respectively.


- Can a series of codepoints, appropriately padded to the 
required width, and terminated by a null character, be 
directly assigned to a string WITHOUT GOING THROUGH A DECODING 
/ ENCODING TRANSLATION?


no, they must be encoded. Unicode code points are an abstract 
concept that must be encoded somehow to exist in memory 
(similar to the idea of a number).


OK, then that actually simplifies what's needed, because I won't 
need to decode the UTF-8, only validate it.


My code reads a UTF-8 encoded file into a buffer and validates, 
byte by byte, the UTF-8 encoding along with some additional 
validation. If I simply return the UTF-8 encoded string, there 
won't be another decoding/encoding done -- correct?


Some questions about strings

2020-06-21 Thread Denis via Digitalmars-d-learn

I have a few questions about how strings are stored.

- First, is there any difference between string, wstring and 
dstring? For example, a 3-byte Unicode character literal can be 
assigned to a variable of any of these types, then printed, etc, 
without errors.


- Are the characters of a string stored in memory by their 
Unicode codepoint(s), as opposed to some other encoding?


- Assuming that the answer to the first question is "no 
difference", do strings always allocate 4 bytes per codepoint?


- Can a series of codepoints, appropriately padded to the 
required width, and terminated by a null character, be directly 
assigned to a string WITHOUT GOING THROUGH A DECODING / ENCODING 
TRANSLATION?


The last question gets to the heart of what I'd ultimately like 
to accomplish and avoid.


Thanks for your help.


Re: Reading text (I mean "real" text...)

2020-06-20 Thread Denis via Digitalmars-d-learn

Digging into this a bit further --

POSIX defines a "print" class, which I believe is an exact fit. 
The Unicode spec doesn't define this class, which I presume is 
why D's std.uni library also omits it. But there is an isprint() 
function in libc, which I should be able to use (POSIX here). 
This function refers to the system locale, so it isn't limited to 
ASCII characters (unlike std.ascii:isPrintable).


So that's one down, two to go:

  Loop until newline or EOF
   (1) Read bytes or character } Possibly
   (2) Decode UTF-8, exception if invalid  } together
   (3) Call isprint(), exception if invalid
  Return line

(This simplified outline obviously doesn't show how to deal with 
the complications arising from using buffers, handling codepoints 
that straddle the end of the buffer, etc.)


Where I'm still stuck is the read or read-and-auto-decode: this 
is where the waters get really muddy for me. Three different 
techniques for reading characters are suggested in this thread 
(iopipe, ranges, rawRead): 
https://forum.dlang.org/thread/cgteipqqfxejngtpg...@forum.dlang.org


I'd like to stick with standard D or C libraries initially, so 
that rules out iopipe for now. What would really help is some 
details about what one read technique does particularly well vs. 
another. And is there a technique that seems more suited to this 
use case than the rest?


Thanks again


Re: Reading text (I mean "real" text...)

2020-06-19 Thread Denis via Digitalmars-d-learn

On Saturday, 20 June 2020 at 01:41:50 UTC, Paul Backus wrote:
It sounds like maybe what you are looking for is Unicode 
character categories:


https://en.wikipedia.org/wiki/Unicode_character_property#General_Category


The character validation step could indeed be expressed using 
Unicode properties:


  Allow Unicode White_Space
  Reject Unicode Control
  Allow everything else



Reading text (I mean "real" text...)

2020-06-19 Thread Denis via Digitalmars-d-learn

THE PROBLEM

UTF-8 validation alone is insufficient for ensuring that a file 
contains only human-readable text, because control characters are 
UTF-8 valid. Apart from tab, newline, carriage return, and a few 
less commonly used others considered to be whitespace, 
human-readable text files should not normally contain embedded 
control characters.


In the standard library, the read functions for "text" files (as 
opposed to binary files) that I looked at are not actually based 
on "human readable text", but on "characters". For example:


 - In std.stdio, readln accepts everything. Lines are simply 
separated by the occurrence of a newline or user-designated 
character.

 - In std.file, readText accepts all valid UTF-8 characters.

This means, for example, that all of these functions will happily 
try to read an enormous file of zeroes in its entirety (something 
that should not even be considered "text") into a string 
variable, on the very first call to the read function. Not 
good... Whereas a function that reads only "human-readable text" 
should instead generate an exception immediately upon 
encountering an invalid control character or invalid UTF-8 
character.


THE OBJECTIVE

The objective is to read a file one line at a time (reading each 
line into a string), while checking for human-readable text 
character by character. Invalid characters (control and UTF-8) 
should generate an exception.


Unless there's already an existing function that works as 
described, I'd like to write one. I expect that this will require 
combining an existing read-by-UTF8-char or read-by-byte function 
with the additional validation.


Q1: Which existing functions (D or C) would you suggest 
leveraging? For example, there are quite a few variants of "read" 
and in different libraries too. For a newcomer, it can be 
difficult to intuit which one is best suited for what.


Q2: Any source code (D or C) you might suggest I look at, to get 
ideas for how parts of this could be written?


Thanks for your help.


Re: "if not" condition check (for data validation)

2020-06-18 Thread Denis via Digitalmars-d-learn

On Thursday, 18 June 2020 at 17:57:49 UTC, Ali Çehreli wrote:
Here is an earlier experiment of nested templates, which may be 
useful in this case.

:
I think you should be able to pass callables as 'alias' 
template arguments


Sounds good. This gives me an opportunity to learn how nested 
templates can be used. `alias` in this context is also new, so 
I'll dig into that too.


Thanks!



Re: "if not" condition check (for data validation)

2020-06-18 Thread Denis via Digitalmars-d-learn

On Thursday, 18 June 2020 at 12:50:35 UTC, Stanislav Blinov wrote:

No, there isn't a way to write an operator.


OK, first choice eliminated.

On Thursday, 18 June 2020 at 13:57:39 UTC, Dukc wrote:

No reason to use templates here

pragma(inline, true) auto not(bool cond) { return !cond(); }


I like it. The inline pragma eliminates the extra overhead of the 
function call, which was another objective. (And it introduces me 
to D's pragmas too.)


Personally, I find this:

  if ( not( abra && cadabra )) ...

to be more clear than:

  if ( !( abra && cadabra )) ...

I guess it depends on what one is used to. I do recognize that 
this would be non-standard for D, but I'm still going to use it 
because I find it more readabile.


I should add that this one made me laugh though, giving 
flashbacks to that horrible "not speak" of the early 90s:


  if ( configfile.isFile.not ) ...

LOL

I've learned multiple things from this posting. Thank you all for 
sharing your suggestions.


Denis


Re: "if not" condition check (for data validation)

2020-06-18 Thread Denis via Digitalmars-d-learn

Let me clarify the requirements and rephrase the question --

REQUIREMENTS

`assert`, `enforce` and the `unless` function I wrote (above) all 
allow the condition to be expressed in an affirmative sense, and 
they also achieve the goal of readability. These are the initial 
requirements.


`unless` improves on `assert` and `enforce` by allowing a custom 
action to be specified. This might be to write an error message 
and exit (like `assert` and `enforce`). But it could also be to 
write a warning message (to console or a log file) but not exit. 
So the next requirement is to be able to specify a custom action.


Unfortunately a function, like the one I wrote, doesn't work 
because it doesn't allow actions that would skip or repeat some 
code (`continue`, `goto`, etc) to be specified as the second 
argument. It also doesn't allow code to be skipped or repeated 
after executing the function in the second argument. (That is, 
after writing a warning message or log notice, continue 
processing at some point.) A conditional operator like `if` is 
needed, not a function.


THE ESSENTIAL QUESTION

Is there a way to write an `unless` operator that would allow the 
condition to be expressed in an affirmative sense? It would be 
used like `if`, i.e. something like:


   unless (  ) {
 ; // Or even: 
 continue; }

Templates offer a clean syntax, but I can't come up with a way to 
use them for a conditional operator. Mixins are flexibile, but I 
suspect the result would not be very readabile (that is, less 
readable even than "if ( ! (..." ). I was hoping that some 
feature, or combination of features, in D might allow this to be 
achieved.


Re: "if not" condition check (for data validation)

2020-06-17 Thread Denis via Digitalmars-d-learn

On Thursday, 18 June 2020 at 00:43:40 UTC, Stanislav Blinov wrote:


if( ! (configfile.isFile && configfile.extension == ".conf") )

?


That does indeed clean up the compound logic. One is still left 
with:


  if( !(
  if( !
  if( !(
  if( !
   :

I was hoping to get away from all the `not`s too.


"if not" condition check (for data validation)

2020-06-17 Thread Denis via Digitalmars-d-learn

Is there a cleaner way to implement an "if not" condition check?

WHY NOT JUST USE "IF"?

For data validation, code is cleaner and more intelligible if the 
condition being checked is written in an affirmative sense; that 
is, in the same way that `assert` is written. This is especially 
true when `and` and `or` logic is involved. `if` is not a good 
substitute, because it works in the opposite sense, often 
requiring lots of `not`s. As a trivial example:


  assert( configfile.isFile && configfile.extension == ".conf" )
-vs-
  if ( !configfile.isFile || configfile.extension != ".conf" ) 



An `if` statement can be written in the affirmative sense, by 
using an empty `then` statement + an `else` statement:


  if ( configfile.isFile && configfile.extension == ".conf", 
message ) { }

  else 

But then the logic intuitively feels wrong for an `if`, because 
the handler is always in the `else`. When there are only a few 
such checks, it might not matter. But when there are a lot of 
checks, the code gets ugly (lots of `else`s) and the clutter adds 
up.


ORIGINAL SOLUTION

The following solution works and the code is very readable. 
However, it has a couple of notable deficiencies.


  void unless(T)(T condition, lazy void func ) {
  if ( !condition ) func(); }
   :
  unless( configfile.isFile && configfile.extension == ".conf", 
handleIt( _ _ ));


The most obvious shortcomings are:
  1. It only works with a handler function. So `continue` and the 
like can't be used, for example.
  2. It is inefficient, adding an extra function call to every 
condition check. Inside a loop, this is cumulative.


A BETTER SOLUTION ???

I haven't been able to come up with another option that is more 
efficient yet doesn't sacrifice readability. I would welcome 
suggestions.


Thanks in advance.
Denis


Re: Initializing an associative array of struct

2020-06-14 Thread Denis via Digitalmars-d-learn

On Sunday, 14 June 2020 at 15:44:04 UTC, Ali Çehreli wrote:

On 6/14/20 7:43 AM, Denis wrote:> @Kagamin:
>
> On Sunday, 14 June 2020 at 07:16:18 UTC, Kagamin wrote:
>> parameters[param]=Parameter();
>
> I did not realize that you can use a type on the RHS of an
assignment,

Note that it's not just the type but with parenthesis after it. 
For example, Foo() default-constructs an object of Foo.


Got it.


> There does not appear to be a way to loop over the elements
of an enum,

There is std.traits.EnumMembers:

import std.traits;

enum Foo { abc, xyz }

void main() {
  foreach (foo; EnumMembers!Foo) {
// ...
  }
}


Excellent. Because all of the keys are immutable strings and are 
known at compile time, enum seems like it should be well suited 
for the job. I will try this too.


On a side note: I am working my way through your book, Ali. It 
really is very helpful for learning D, and for pointing out 
things that are not always clear from reading the documentation 
alone. I will admit, however, that I am not able to absorb all of 
the more subtle aspects yet. So this is an iterative process 
(read some, write code, re-read and read some more, write code, 
...)


Thank you for your help.


Re: Initializing an associative array of struct

2020-06-14 Thread Denis via Digitalmars-d-learn

@Kagamin:

On Sunday, 14 June 2020 at 07:16:18 UTC, Kagamin wrote:

parameters[param]=Parameter();


I did not realize that you can use a type on the RHS of an 
assignment, but it is clear and succinct. This syntax will be 
very useful going forward -- thank you.


@Stanislav B:

On Sunday, 14 June 2020 at 09:34:08 UTC, Stanislav Blinov wrote:

string[] keys =
[
"huh", "buh", "hrm", "pff", "err", "ack", "ugh",
/* ... */
"zzz"
];
foreach (k; keys)
parameters.require(k);


This solves the problem of initializing the keys perfectly -- 
thank you. There does not appear to be a way to loop over the 
elements of an enum, so a string array does make the most sense 
as the initial container for the keys.


I should add that your explanation for using `require` to perform 
the init is much more clear than the documentation!


The `require` function, when called only with key, will insert 
default (.init) value for that key.


I am just starting to learn D, and am missing so many pieces of 
the puzzle that I'm not yet able to always put "two and two" 
together myself. This kind of help really goes a long way. Again, 
my thanks to you both.


Denis


Initializing an associative array of struct

2020-06-13 Thread Denis via Digitalmars-d-learn

Hi,

I'm trying to combine a couple of general types (associative 
array, struct) in a compound data structure, but without success. 
Here is what I'm trying to achieve:


"param" is a string variable
"parameters[param].id" is an integer value
"parameters[param].value" is a string value

param can be any of a fixed set of string values, all literals 
known at compile time.


parameters needs to be pre-populated with all of its keys during 
initialization, because they will be used to validate the param 
values that are read from a file (by checking if "param in 
parameters" is true).


I started with the following declarations:

struct Parameter {
int id;
string value; }

Parameter[string] parameters;
string param;

But then I simply could not come up with a way to initialize the 
keys of parameters. I tried using assignments as well as enum, 
but always received either a compile or a runtime error. 
(Unfortunately the error messages did not enable me to find a 
solution.)


Note also that the defaults for id and value are fine (int and 
string defaults). But is it even possible to add the keys alone 
to parameters, without assigning something?


I would welcome a suggestion for how to initialize the keys of 
parameters. As there will be a couple dozen of the param string 
keys, a more succinct method would be preferable over a verbose 
one.


I realize that this is a very basic question, but I'm stumped!

Thank you in advance for your help.