Thread overview
Populating nested AAs; "This wouldn't be so verbose in Ada 2020"
Dec 08, 2019
mipri
Dec 08, 2019
Paul Backus
Dec 08, 2019
mipri
December 08, 2019
Hello,

I've got this code:

  struct UserStats {
    int ok, evil;
  }

  // module-level variable
  UserStats[string][string] userHistory;

and this code that populates it:

  // loop over DB query

  if (host !in userHistory)
      userHistory[host] = typeof(userHistory[host]).init;

  if (user !in userHistory[host])
      userHistory[host][user] = typeof(userHistory[host][user]).init;

  if (ok) ++userHistory[host][user].ok;
  else ++userHistory[host][user].evil;

The joke of the thread title is that in pseudo-Ada2020, those
assignments would look like

  User_History (host) = typeof (@).init;
  User_History (host) (user) = typeof (@).init;

as @ is a shortcut for the left hand side of an assignment.
It's what Ada has instead of += and friends.

Of course, I don't propose that @ be added to D; I just want to
know if there's a good idiom for new assignments to nested AAs
like this. A nice alternative for my specific use is

  struct UserStats {
    static int[Tuple!(string, string)] ok, evil;
  }

and

  // loop over DB query
  if (ok) ++UserStats.ok[tuple(host, user)];
  else ++UserStats.evil[tuple(host, user)];

But of course this would be less convenient if f.e. I wanted to
pattern my data structures after a JSON production result.

December 08, 2019
On Sunday, 8 December 2019 at 04:17:45 UTC, mipri wrote:
> Hello,
>
> I've got this code:
>
>   struct UserStats {
>     int ok, evil;
>   }
>
>   // module-level variable
>   UserStats[string][string] userHistory;
>
> and this code that populates it:
>
>   // loop over DB query
>
>   if (host !in userHistory)
>       userHistory[host] = typeof(userHistory[host]).init;
>
>   if (user !in userHistory[host])
>       userHistory[host][user] = typeof(userHistory[host][user]).init;
>
>   if (ok) ++userHistory[host][user].ok;
>   else ++userHistory[host][user].evil;

You can use the `require` function [1] for this:

with (userHistory.require(host).require(user)) {
    if (isOk) ++ok; // renamed to avoid shadowing
    else ++evil;
}

Many "methods" for built-in AAs are located in the `object` module. It makes them a bit tricky to find in the documentation, if you don't already know they're there.

https://dlang.org/phobos/object.html#.require
December 08, 2019
On Sunday, 8 December 2019 at 06:42:22 UTC, Paul Backus wrote:
> You can use the `require` function [1] for this:
>
> with (userHistory.require(host).require(user)) {
>     if (isOk) ++ok; // renamed to avoid shadowing
>     else ++evil;
> }
>
> Many "methods" for built-in AAs are located in the `object` module. It makes them a bit tricky to find in the documentation, if you don't already know they're there.
>
> https://dlang.org/phobos/object.html#.require

Thanks! I wasn't aware of the 'object' doc. Looks like the
language documentation does mention require() in "Inserting if
not present", but combining it with 'with' is a neat trick.