Thread overview
Source expression passed to a lazy parameter
Apr 09, 2018
Per Nordlöw
Apr 09, 2018
Basile B.
Apr 09, 2018
Jonathan M Davis
Apr 09, 2018
Simen Kjærås
Apr 09, 2018
Alex
Apr 09, 2018
Simen Kjærås
Apr 09, 2018
Seb
Apr 09, 2018
Stefan Koch
April 09, 2018
Is it possible to get the source expression sent to a lazy function?

So that I can implement something like

show(Arg)(lazy Arg arg)
{
    writeln(arg.sourceof, arg);
}

used as

    show(1+2+3);

will print

    1+2+3:6

April 09, 2018
On Monday, 9 April 2018 at 08:27:50 UTC, Per Nordlöw wrote:
> Is it possible to get the source expression sent to a lazy function?
>
> So that I can implement something like
>
> show(Arg)(lazy Arg arg)
> {
>     writeln(arg.sourceof, arg);
> }
>
> used as
>
>     show(1+2+3);
>
> will print
>
>     1+2+3:6

No (afaik), what you need is an internal compiler function, "toChars" IIRC, that's available for each node.
April 09, 2018
On Monday, April 09, 2018 08:27:50 Per Nordlöw via Digitalmars-d-learn wrote:
> Is it possible to get the source expression sent to a lazy function?
>
> So that I can implement something like
>
> show(Arg)(lazy Arg arg)
> {
>      writeln(arg.sourceof, arg);
> }
>
> used as
>
>      show(1+2+3);
>
> will print
>
>      1+2+3:6

Given how lazy parameters work, I don't see how that would be possible. lazy parameters are implemented as delegates, and the function doesn't have access to what the argument was, just the delegate to get the result of evaluating it. Functions with lazy parameters don't have to be templates, and if the function is a template, as long as the type of the expression is the same, it should only result in one instantiation of the function template. As such, the only way that something like what you're suggesting would work would be if there were some way to get the string representation of the body of a delegate at runtime, and that would be pretty much the same as getting the string representation of any function at runtime. That sort of thing simply isn't kept around beyond what's required to compile the function in the first place. The closest that you'd get would be whatever comes with debug symbols when they're enabled.

- Jonathan M Davis


April 09, 2018
On Monday, 9 April 2018 at 08:27:50 UTC, Per Nordlöw wrote:
> Is it possible to get the source expression sent to a lazy function?

Nope. Something along the lines of __traits(getSource, arg) has been discussed occasionally.

For lazy what you're asking is impossible, since the compiler doesn't know which actual arguments have been passed. show(1+2) will look absolutely identical to show(3), will look identical to show(myVarWithValue3).

Now, there are some things you can do. Notably, lambdas are included verbatim in templated type names, which we can exploit.

struct S(alias fn) {}
void show(alias fn)() {
    import std.stdio;
    writeln(S!fn.stringof[18..$-1], ": ", fn());
}

unittest {
    show!(()=>1+2); // prints "3: 3"
}

As we can see, it optimizes '1+2' to become 3, so it's not perfect.

This also works for lambdas that include local variables:

unittest {
    int i = 13;
    show!(() => i+2); // Prints "i + 2: 15"
}

However, it fails for lambdas that take arguments:

struct S(alias fn) {}
void show(alias fn, T...)(T args) {
    import std.stdio;
    writeln(S!fn.stringof[18..$-1], ": ", fn(args));
}

unittest {
    show!(a => a+2)(3); // Fails to compile
}

The reason this fails is the lambda's textual representation decays to '__lambda1'.

There is however still something we can do, but things get even less flexible:

struct show(alias fn) {
    static void opCall(T...)(T args) {
        import std.stdio, std.string;
        enum s = show.stringof;
        enum i = s.indexOf("=>");
        writeln(s[i+3..$-1], ": ", fn(args));
    }
}

unittest {
    show!(a => a+2)(3); // Prints "a + 2: 5"
}

--
  Simen
April 09, 2018
On Monday, 9 April 2018 at 09:20:42 UTC, Simen Kjærås wrote:
> Nope. Something along the lines of __traits(getSource, arg) has been discussed occasionally.

Is this available somehow? And/or do you have a link to the discussion, maybe?

April 09, 2018
On Monday, 9 April 2018 at 11:33:56 UTC, Alex wrote:
> On Monday, 9 April 2018 at 09:20:42 UTC, Simen Kjærås wrote:
>> Nope. Something along the lines of __traits(getSource, arg) has been discussed occasionally.
>
> Is this available somehow? And/or do you have a link to the discussion, maybe?

https://forum.dlang.org/post/huyqfcoosgzfneswnrur@forum.dlang.org

https://github.com/dlang/dmd/pull/953


I'm pretty sure there have been other discussions too, but a brief search yielded too many irrelevant results.

--
  Simen
April 09, 2018
On Monday, 9 April 2018 at 08:27:50 UTC, Per Nordlöw wrote:
> Is it possible to get the source expression sent to a lazy function?
>
> So that I can implement something like
>
> show(Arg)(lazy Arg arg)
> {
>     writeln(arg.sourceof, arg);
> }
>
> used as
>
>     show(1+2+3);
>
> will print
>
>     1+2+3:6

Because of the way D works with a given piece of code may not have a source-location or even a representation which is valid D source code.

Note: There is a way to fix this but it's very involved.

Step 1: you use cow (copy-on-write) when modifying AST nodes in semantic() or you keep distinct trees.
Step 2: you sanitize implicitly generated code to make sure it's actually valid code.
Step 3: you write the generated code, to a well-defined location such that source-of can point to a valid location.

also note that support for sourceof at compiletime will bloat the executable since it needs to store the source-text.
April 09, 2018
On Monday, 9 April 2018 at 13:03:38 UTC, Simen Kjærås wrote:
> On Monday, 9 April 2018 at 11:33:56 UTC, Alex wrote:
>> On Monday, 9 April 2018 at 09:20:42 UTC, Simen Kjærås wrote:
>>> Nope. Something along the lines of __traits(getSource, arg) has been discussed occasionally.
>>
>> Is this available somehow? And/or do you have a link to the discussion, maybe?
>
> https://forum.dlang.org/post/huyqfcoosgzfneswnrur@forum.dlang.org
>
> https://github.com/dlang/dmd/pull/953
>
>
> I'm pretty sure there have been other discussions too, but a brief search yielded too many irrelevant results.
>
> --
>   Simen

For reference, the most recent discussion and PR is https://github.com/dlang/dmd/pull/7821 (it's currently orphaned)