foo => "bar" key/value literals in D!

Jacob Carlborg via Digitalmars-d-announce digitalmars-d-announce at puremagic.com
Mon May 23 23:49:52 PDT 2016


On 2016-05-23 21:00, Adam D. Ruppe wrote:
> Have I gone completely mad?!?!
>
> ---
> void main() {
>          import std.stdio;
>          writeln(obj!(
>                  foo => "bar",
>                  baz => 12
>          ));
> }
> ---
>
> Prints out:
>
> {
>          foo: bar
>          baz: 12
> }
>
>
>
> A few tweaks would make a whole loose typed hash thing more akin to Ruby
> or PHP than D. What's obj? Behold:
>
>
> string obj(T...)() {
>          import std.conv, std.traits;
>          string jsonResult = "{";
>          foreach(arg; T) {
>                  jsonResult ~= "\n\t";
>
>                  // I don't know why the usual is(__parameters) trick
>                  // won't work here, but a stringof hack will!
>                  string hack = typeof(arg!string).stringof;
>                  import std.string;
>                  hack = hack[hack.indexOf("function(string ") +
> "function(string ".length .. $];
>                  hack = hack[0 .. hack.indexOf(")")];
>
>                  jsonResult ~= hack;
>                  jsonResult ~= ": ";
>                  jsonResult ~= to!string(arg(""));
>
>          }
>          jsonResult ~= "\n}";
>          return jsonResult;
> }

That's pretty cool and pretty ugly :).

> As you probably know, D has a couple lambda literal syntaxes. One of
> these is the fat arrow, with a valid form of argument => return_expression.
>
> The compiler makes templates out of these when you pass them around....
> and those templates contain the parameters, including the name, and are
> callable code (if instantiated with a concrete type).
>
> I was disappointed to see the ordinary reflection tools didn't work here
> - I know, I'm abusing the language - but the trusty old .stringof hack
> did! Combined with the magic knowledge that these things are templates,
> I instantiated them (tbh I was a bit surprised it actually let me!) and
> extracted the name of the argument.

__parameters doesn't work because an "untyped" lambda is a template and 
__parameters works with functions, but I guess you already know that. 
Instantiating the lambda and then using __parameters should work.

There's a PR for DMD which adds support for inspecting template 
parameters [1] that would help. Unfortunately it's closed.

Here's a version building an associative array mapping strings to variants:

import std.stdio : println = writeln;
import std.variant;

Variant[string] hash(T...)() {
     import std.conv, std.traits;
     Variant[string] aa;
     foreach(arg; T) {
         // I don't know why the usual is(__parameters) trick
         // won't work here, but a stringof hack will!
         string hack = typeof(arg!string).stringof;
         import std.string;
         hack = hack[hack.indexOf("function(string ") + "function(string 
".length .. $];
         hack = hack[0 .. hack.indexOf(")")];

         aa[hack] = Variant(arg(""));

     }
     return aa;
}

void main() {
     auto h = hash!(
         foo => 3,
         bar => "asd"
     );
     writeln(h);
}

[1] https://github.com/dlang/dmd/pull/5201

-- 
/Jacob Carlborg


More information about the Digitalmars-d-announce mailing list