Is it possible to obtain textual representation of an arbitary code?

Oleksii Skidan al.skidan at gmail.com
Fri Jan 26 14:43:49 UTC 2018


On Friday, 26 January 2018 at 13:05:26 UTC, Jonathan M Davis 
wrote:
> On Friday, January 26, 2018 12:30:03 Oleksii Skidan via 
> Digitalmars-d-learn wrote:
>> On Friday, 26 January 2018 at 11:32:42 UTC, Mike Parker wrote:
>> > On Friday, 26 January 2018 at 11:18:21 UTC, Oleksii Skidan
>> >
>> > wrote:
>> >> [...]
>> >
>> > Token strings are intended for this and editors *should* 
>> > highlight them (don't know if any currently do):
>> >
>> > https://dlang.org/spec/lex.html#token_strings
>>
>> Seems like I have to add some context into this conversation: 
>> I'm writing a poor man's testing framework, since it's the 
>> best and easiest way to learn D ;-)
>>
>> I'm trying to achieve something similar to 
>> `Catch2``REQUIRE`macro. To be honest, I did not know about 
>> toking strings until today, and I don't know D much. Here's 
>> what I came up with so far:
>>
>> ```d
>> string require(string expr)(string file = __FILE__, int line =
>> __LINE__)
>> {
>>      import std.array, std.conv;
>>      return q{
>>          if (!($expr)) {
>>              import std.stdio;
>>              writeln("Test failed @", `$file`, ":", $line, 
>> "\n",
>>                      "  Expected: `", `$expr`, "` to be
>> `true`.\n");
>>          }
>>      }.replace("$expr", expr)
>>       .replace("$file", file)
>>       .replace("$line", to!string(line));
>> }
>>
>> ```
>>
>> That code snippet uses token strings to compose an if 
>> statement that basically checks whether the given condition 
>> holds. That looks okay-ish to me, the usage of that function 
>> is not pretty though:
>>
>> ```d
>> unittest
>> {
>>      mixin(require!q{false}); // This test will fail.
>> }
>> ```
>>
>> It would be awesome if I could write something like the this 
>> instead:
>>
>> ```d
>> unittest
>> {
>>      require!q{false};
>> }
>> ```
>>
>> At first glance it seems like I could have moved the `mixin` 
>> statement into the `require` function itself, but that would 
>> not really work. Consider the following snippet:
>>
>> ```d
>> unittest
>> {
>>      float value = 3f;
>>      require!q{value == 3f}; // This line won't compile.
>> }
>> ```
>>
>> That code won't even compile, since `value` exists in 
>> `unittest` scope, which is not visible to the `require` 
>> function.
>
> Why are you using strings for any of this? Printing out the 
> expression is kind of pointless. If you have the file and line 
> number (which an AssertError will give you), then you know 
> where the failure is, and you can see the expression. All of 
> this extra machinery is just going to increase your compile 
> times for no benefit. So, what you're doing here is objectively 
> worse than just using assertions.
>
> There might be some value if you had something like
>
> assertEqual(lhs, rhs);
>
> and then on failure, you printed the values that were being 
> compared, since that's not necessarily information that's in 
> the code, but the expressions themselves _are_ already in the 
> code, so printing them out doesn't help any.
>
> But even if you have helper functions that take the values 
> separately so that they can be printed, in my experience, the 
> extra template instantiations required to use helper functions 
> like that everywhere in unit tests increases the compilation 
> times (and memory required) enough that it's not worth it, 
> especially when you consider that once the tests are passing, 
> all of that extra machinery does you no good whatsoever. 
> Ultimately, it just costs less to temporarily make an 
> adjustment to the test and rerun it if you need more 
> information.
>
> If you don't think that simply using assertions for unit tests 
> is good enough, then I'd suggest that you look at 
> https://code.dlang.org/packages/unit-threaded
>
> - Jonathan M Davis

I've just realized that I can actually make the test code more 
pleasant if I use string concatenation. For example, this test:

```
unittest
{
     import testing;

      {
         Particle a = Particle(0.9, 0);
         Particle b = Particle(2.1, 0);
         Constraint c = Constraint(a, b);
         c.distance = 1f;
         c.solve();
         mixin(requireEq!q{1f, a.x});
         mixin(requireEq!q{0f, a.y});
         mixin(requireEq!q{2f, b.x});
         mixin(requireEq!q{0f, b.y});
     }
}
```

could be written as:

```
unittest
{
     import testing;

     {
         Particle a = Particle(0.9, 0);
         Particle b = Particle(2.1, 0);
         Constraint c = Constraint(a, b);
         c.distance = 1f;
         c.solve();
         mixin(
             requireEq!q{1f, a.x} ~
             requireEq!q{0f, a.y} ~
             requireEq!q{2f, b.x} ~
             requireEq!q{0f, b.y}
         );
     }
}
```
That code looks a little bit unusual, but I guess I can get used 
to it. Seems like I can write a test scenario per mixin.




More information about the Digitalmars-d-learn mailing list