www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - byKeyValue is not available at compilation-time right ?

reply someone <someone somewhere.com> writes:
As you can see in the following code I cannot avoid to type the 
IDs twice in the structureExchanges enum:

```d
public struct structureExchange { /// solely‐intended to help 
build code at compilation‐time; for client‐code classExchanges 
should be used instead

    public typeLocation location;
    public dstring ID;
    public dstring name;
    public dstring currencyID;

}

/// implementation: exchange properties are «almost» immutable; 
eg: NYSE is (and will always be) on NY, USA trading in USD
/// implementation: from the app perspective (think integrity) 
giving the user read‐only exchange data is a plus … ie: don't 
mess with this
/// implementation: however, would it be possible to 
dynamically‐load the following enums from a file at 
compilation‐time ?

public immutable enum structureLocations = [
    r"BUE"d : typeLocation(r"arg"d, r"Buenos Aires"d, r"ART"d),
    r"GRU"d : typeLocation(r"bra"d, r"São Paulo"d, r"BRT"d),
    r"HHN"d : typeLocation(r"deu"d, r"Frankfurt am Main"d, 
r"CET"d),
    r"LHR"d : typeLocation(r"gbr"d, r"London"d, r"UTC"d),
    r"NYC"d : typeLocation(r"usa"d, r"New York"d, r"EST"d)
    ];

public immutable enum structureExchanges = [
    r"B3"d     : structureExchange(structureLocations[r"GRU"d], 
r"B3"d, r"B3 formerly Bolsa de Valores de São Paulo (aka 
BOVESPA)"d, r"BRL"d),
    r"BCBA"d   : structureExchange(structureLocations[r"BUE"d], 
r"BCBA"d, r"Bolsa de Comercio de Buenos Aires"d, r"ARS"d),
    r"LSE"d    : structureExchange(structureLocations[r"LHR"d], 
r"LSE"d, r"London Stock Exchange"d, r"GBP"d),
    r"NASDAQ"d : structureExchange(structureLocations[r"NYC"d], 
r"NASDAQ"d, r"National Association of Securities Dealers 
Automated Quotations"d, r"USD"d),
    r"NYSE"d   : structureExchange(structureLocations[r"NYC"d], 
r"NYSE"d, r"New York Stock Exchange"d, r"USD"d),
    r"XETRA"d  : structureExchange(structureLocations[r"HHN"d], 
r"XETRA"d, r"Deutsche Börse"d, r"EUR"d)
    ]; /// byKeyValue is not available at compile‐time; hence the 
redundancy of IDs
```

I attempted to use byKeyValue to get rid of the second set of IDs 
to no avail; eg:

```d
static foreach(
    structureExchange sudtExchange;
    structureExchanges.byKeyValue
    ) {

    ...  sudtExchange.key
    ...  sudtExchange.value

}
```
Jul 24 2021
next sibling parent reply jfondren <julian.fondren gmail.com> writes:
On Sunday, 25 July 2021 at 05:10:32 UTC, someone wrote:
 /// implementation: however, would it be possible to 
 dynamically‐load the following enums from a file at 
 compilation‐time ?

 public immutable enum structureLocations = [
    r"BUE"d : typeLocation(r"arg"d, r"Buenos Aires"d, r"ART"d),
    r"GRU"d : typeLocation(r"bra"d, r"São Paulo"d, r"BRT"d),
    r"HHN"d : typeLocation(r"deu"d, r"Frankfurt am Main"d, 
 r"CET"d),
    r"LHR"d : typeLocation(r"gbr"d, r"London"d, r"UTC"d),
    r"NYC"d : typeLocation(r"usa"d, r"New York"d, r"EST"d)
    ];
``` Error: `_aaRange` cannot be interpreted at compile time, because it has no available source code ``` Yep, seems that's not available. What you're doing with `immutable enum structureLocations` is creating a manifest constant, i.e. your AA initialization is copy-pasted into each use of it, which means your program is rebuilding this AA at runtime every time it comes up. You probably got to this point as a bare `immutable structureLocations` errored out to the non-constant expression. You should be able to use a shared static module initializer to initialize an immutable AA, https://dlang.org/spec/module.html#staticorder , but although I've seen examples of simple string[string] initialization, it seems to be very hard to get more complex AAs past the std.array/std.exception tools. So here's something you can do: ```d __gshared const dstring[][dstring] structureExchanges; __gshared const dstring[dstring] exchangeStructures; shared static this() { import std.string, std.algorithm; dstring[][dstring] exchanges; // could easily load this from a file " B3: B3 formerly Bolsa de Valores de São Paulo (aka BOVESPA) BCBA: Bolsa de Comercio de Buenos Aires LSE: London Stock Exchange NASDAQ: National Association of Securities Dealers Automated Quotations NYSE: New York Stock Exchange XETRA: Deutsche Börse "d.strip.splitLines.map!strip.each!((dstring exch) { const pair = exch.split(": "); exchanges[pair[0]] = [pair[1], "some other values"d]; }); structureExchanges = exchanges; dstring[dstring] structures; foreach (k, v; exchanges) structures[v[0]] = k; exchangeStructures = structures; } ``` std.array.assocArray might also come in handy.
Jul 25 2021
parent reply someone <someone somewhere.com> writes:
On Sunday, 25 July 2021 at 07:22:54 UTC, jfondren wrote:
 On Sunday, 25 July 2021 at 05:10:32 UTC, someone wrote:
 /// implementation: however, would it be possible to 
 dynamically‐load the following enums from a file at 
 compilation‐time ?

 public immutable enum structureLocations = [
    r"BUE"d : typeLocation(r"arg"d, r"Buenos Aires"d, r"ART"d),
    r"GRU"d : typeLocation(r"bra"d, r"São Paulo"d, r"BRT"d),
    r"HHN"d : typeLocation(r"deu"d, r"Frankfurt am Main"d, 
 r"CET"d),
    r"LHR"d : typeLocation(r"gbr"d, r"London"d, r"UTC"d),
    r"NYC"d : typeLocation(r"usa"d, r"New York"d, r"EST"d)
    ];
``` Error: `_aaRange` cannot be interpreted at compile time, because it has no available source code ``` Yep, seems that's not available. What you're doing with `immutable enum structureLocations` is creating a manifest constant
Right.
 i.e. your AA initialization is copy-pasted into each use of it, 
 which means your program is rebuilding this AA at runtime every 
 time it comes up. You probably got to this point as a bare 
 `immutable structureLocations` errored out to the non-constant 
 expression.
Sounds bad, inefficient at least :( I refactored this little chunk of code many times and I thought this was the best one that I came across.
 You should be able to use a shared static module initializer to 
 initialize an immutable AA, 
 https://dlang.org/spec/module.html#staticorder , but although 
 I've seen examples of simple string[string] initialization, it 
 seems to be very hard to get more complex AAs past the 
 std.array/std.exception tools.
So I am seeking free trouble then :(
 So here's something you can do:

 ```d
 __gshared const dstring[][dstring] structureExchanges;
 __gshared const dstring[dstring] exchangeStructures;
ahhh, the __gshared attribute, I remember it while trying to understand the differences for all the attributes: multi‐tasking related: to share (non‐immutable global declarations) across all threads vs local‐storage (default) ... right ?
 shared static this() {
     import std.string, std.algorithm;

     dstring[][dstring] exchanges;
     // could easily load this from a file
     "   B3: B3 formerly Bolsa de Valores de São Paulo (aka 
 BOVESPA)
         BCBA: Bolsa de Comercio de Buenos Aires
         LSE: London Stock Exchange
         NASDAQ: National Association of Securities Dealers 
 Automated Quotations
         NYSE: New York Stock Exchange
         XETRA: Deutsche Börse
     "d.strip.splitLines.map!strip.each!((dstring exch) {
         const pair = exch.split(": ");
         exchanges[pair[0]] = [pair[1], "some other values"d];
     });
     structureExchanges = exchanges;

     dstring[dstring] structures;
     foreach (k, v; exchanges)
         structures[v[0]] = k;
     exchangeStructures = structures;
 }
 ```

 std.array.assocArray might also come in handy.
I suppose I should rethink this matter once again then; I do not want to introduce things that make debugging harder than needed. I'll try to analyze and to implement what you showed me and see how it unrolls.
Jul 25 2021
parent Mike Parker <aldacron gmail.com> writes:
On Sunday, 25 July 2021 at 17:38:23 UTC, someone wrote:
 i.e. your AA initialization is copy-pasted into each use of 
 it, which means your program is rebuilding this AA at runtime 
 every time it comes up. You probably got to this point as a 
 bare `immutable structureLocations` errored out to the 
 non-constant expression.
Sounds bad, inefficient at least :(
The whole point of a manifest constant is that it is purely a compile-time entity that does not exist at runtime. It has no address. In other words, `enum a = 10` can be seen as an alias to the integer literal `10`. That means anywhere you use `a`, it's just like you typed in `10` instead. It is *not* the same as a `const` or `immutable` value. Think of them as a way to avoid "magic literals". Instead of typing `10` or `[1, 2, 3]` in multiple initializers or function calls, you use an alias instead, then when you decide to use `20` or `[2, 4, 6]` instead, you can simply change the declaration of the manifest constant instead of at multiple locations. But you're *still* effectively passing a literal. So if at certain points in your code you want to avoid any allocations a literal would trigger, then you shouldn't be using manifest constants at those points either.
Jul 26 2021
prev sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Sunday, 25 July 2021 at 05:10:32 UTC, someone wrote:
 As you can see in the following code I cannot avoid to type the 
 public immutable enum structureLocations = [
    r"BUE"d : typeLocation(r"arg"d, r"Buenos Aires"d, r"ART"d),
    r"GRU"d : typeLocation(r"bra"d, r"São Paulo"d, r"BRT"d),
Coudln't you instead just do like enum structureLoctations = { BUE = typeLocation......, GRU = typeLiocation.... } ? Then you can build a runtime hash map if you need it in a static constructor or use a binary search switch to convert from strings and look up the id from reflection. It depends on the usage.
 static foreach(
    structureExchange sudtExchange;
    structureExchanges.byKeyValue
    ) {
You can also try a normal foreach foreach(k, v; structureExchanges) { // use k and v } static foreach might work too but assocative arrays are weird beasts that needs to exist all at run time or all at compile time; they cannot cross the barrier and use one item for both. But the built-in k,v instead of byKeyValue might help anyway.
Jul 25 2021
parent reply someone <someone somewhere.com> writes:
On Sunday, 25 July 2021 at 10:30:47 UTC, Adam D Ruppe wrote:
 On Sunday, 25 July 2021 at 05:10:32 UTC, someone wrote:
 As you can see in the following code I cannot avoid to type 
 the public immutable enum structureLocations = [
    r"BUE"d : typeLocation(r"arg"d, r"Buenos Aires"d, r"ART"d),
    r"GRU"d : typeLocation(r"bra"d, r"São Paulo"d, r"BRT"d),
Coudln't you instead just do like enum structureLoctations = { BUE = typeLocation......, GRU = typeLiocation.... } ?
What I was attempting to implement is a manifest constant as described in "enum values that are not of an enum type" http://ddili.org/ders/d.en/enum.html specifically where it says: - Such constants are rvalues and they are called manifest constants. - It is possible to create manifest constants of arrays and associative arrays as well. However, as we will see later in the Immutability chapter, enum arrays and associative arrays may have hidden costs. Since there is no example there the syntax that first occurred to me was what you've already seen: ```d enum structureLocations = [r"XXX"d : ...] ``` What is the proper syntax to use manifest-constants with associative arrays then ? The one you showed me ?
 Then you can build a runtime hash map if you need it in a 
 static constructor or use a binary search switch to convert 
 from strings and look up the id from reflection. It depends on 
 the usage.
I am not following you :(
 static foreach(
    structureExchange sudtExchange;
    structureExchanges.byKeyValue
    ) {
You can also try a normal foreach foreach(k, v; structureExchanges) { // use k and v }
You say a normal foreach ... to be used at compilation-time ... huh ?
 static foreach might work too but assocative arrays are weird 
 beasts that needs to exist all at run time or all at compile 
 time; they cannot cross the barrier and use one item for both.
ACK. How should I've known LoL !
 But the built-in k,v instead of byKeyValue might help anyway.
Jul 25 2021
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Sunday, 25 July 2021 at 17:29:46 UTC, someone wrote:
 What is the proper syntax to use manifest-constants with 
 associative arrays then ? The one you showed me ?
You have the right syntax for that. What I'm saying is you might not need the associative array at all. Why do you want to use that specifically?
 You say a normal foreach ... to be used at compilation-time ... 
 huh ?
Normal foreach is evaluated at compile time if it is looping over an aliasseq tuple or if it is run in a compile time context. Part of the magic of D is ordinary code might be compile time or run time depending on how you use it. But even static foreach I think can do the static foreach(k, v; your_assoc_array) {} in some cases.
Jul 25 2021
parent reply someone <someone somewhere.com> writes:
On Sunday, 25 July 2021 at 17:45:18 UTC, Adam D Ruppe wrote:
 On Sunday, 25 July 2021 at 17:29:46 UTC, someone wrote:
 What is the proper syntax to use manifest-constants with 
 associative arrays then ? The one you showed me ?
You have the right syntax for that. What I'm saying is you might not need the associative array at all. Why do you want to use that specifically?
Good question. I re-analyzed the code then. Because I need code like the following: ```d ... pstrExchangeID = structureExchanges[r"NYSE"d].ID; ... ``` ... and/or (please, see the constructor): ```d template classExchangeCustom( alias dstring lstrExchangeID, typeTickerCustom ) { public class classExchangeCustom : classExchange, interfaceExchangeCustom { /// (1) given exchange ID; eg: NYSE /// (2) given custom‐ticker type; eg: classTickerCustomNYSE private typeTickerCustom[dstring] pobjTickers; safe property public typeTickerCustom[dstring] tickers() { return pobjTickers; } safe this() { pudtLocation = structureExchanges[lstrExchangeID].location; pstrExchangeID = structureExchanges[lstrExchangeID].ID; pstrExchangeName = structureExchanges[lstrExchangeID].name; pstrCurrencyID = structureExchanges[lstrExchangeID].currencyID; } safe public bool add(typeTickerCustom robjTickerCustom) { /// (1) reference to an already-created object for a custom‐ticker bool lbolAdded = false; if (robjTickerCustom ! is null) { lbolAdded = pobjTickers.require( robjTickerCustom.IDsymbolCommon, robjTickerCustom ) ! is null; } return lbolAdded; } safe public bool add(const dstring lstrSymbolID) { /// (1) given symbol ID bool lbolAdded = false; typeTickerCustom lobjTickerCustom = new typeTickerCustom(lstrSymbolID); if (lobjTickerCustom ! is null) { lbolAdded = this.add(lobjTickerCustom); } return lbolAdded; } } } ```
 You say a normal foreach ... to be used at compilation-time 
 ... huh ?
Normal foreach is evaluated at compile time if it is looping over an aliasseq tuple or if it is run in a compile time context. Part of the magic of D is ordinary code might be compile time or run time depending on how you use it.
Amazing :)
 But even static foreach I think can do the

 static foreach(k, v; your_assoc_array) {}

 in some cases.
I'll look into it. All in all, and besides these minor issues, I am getting tons of totally unexpected flexibility with OOP on D. Some things I am doing right now like what I showed you, that probably to you all are nothing out-of-the-ordinary to me are ... fantastic features :)
Jul 25 2021
parent Adam D Ruppe <destructionator gmail.com> writes:
On Sunday, 25 July 2021 at 18:03:05 UTC, someone wrote:
 pstrExchangeID = structureExchanges[r"NYSE"d].ID;
wellllll that's a compile time constant
 structureExchanges[lstrExchangeID].location;
And that's a compile time constant. So you could just pass the data directly as a variable. So instead of looking up the exchanges[id], just pass the exchange. AA's are good for runtime but if it is all compiled in you can just do static data. i'll be back later gotta run
Jul 25 2021