Jump to page: 1 2
Thread overview
__traits(compiles, ...) returns true for syntactic garbage and for semantically incorrect code
Dec 17, 2012
Pavel
Dec 17, 2012
mist
Dec 17, 2012
Pavel
Dec 17, 2012
monarch_dodra
Dec 17, 2012
Simen Kjaeraas
Dec 17, 2012
Pavel
Dec 17, 2012
Pavel
Dec 17, 2012
Pavel
Dec 17, 2012
David Nadlinger
Dec 17, 2012
Pavel
Dec 17, 2012
Pavel
December 17, 2012
Either I do not understand the work of this feature or it is an obvious bug:

import std.stdio;
import std.conv;

void main()
{
   enum string expr = "DMD compiles this garbage ... iiiii - \" #### $$$";
	
   enum bool bTest = __traits(compiles, expr);
   enum bool bTest2 = __traits(compiles, "int i = q{};");
		
   writeln("bTest: " ~ to!string(bTest));
   writeln("bTest2: " ~ to!string(bTest2));
}

Produces (tested with dmd32 2.060 and dmd32 2.059):
  bTest: true
  bTest2: true

(http://dpaste.dzfl.pl/5d338ab3)

Could you please somebody explain this?

Thanks,
Pavel
December 17, 2012
Argument is supposed to be not a string but plain D code. And it is pretty logical that string literal is a valid compiling D code, as well as an existing variable name.

On Monday, 17 December 2012 at 10:42:38 UTC, Pavel wrote:
> Either I do not understand the work of this feature or it is an obvious bug:
>
> import std.stdio;
> import std.conv;
>
> void main()
> {
>    enum string expr = "DMD compiles this garbage ... iiiii - \" #### $$$";
> 	
>    enum bool bTest = __traits(compiles, expr);
>    enum bool bTest2 = __traits(compiles, "int i = q{};");
> 		
>    writeln("bTest: " ~ to!string(bTest));
>    writeln("bTest2: " ~ to!string(bTest2));
> }
>
> Produces (tested with dmd32 2.060 and dmd32 2.059):
>   bTest: true
>   bTest2: true
>
> (http://dpaste.dzfl.pl/5d338ab3)
>
> Could you please somebody explain this?
>
> Thanks,
> Pavel

December 17, 2012
On Monday, 17 December 2012 at 10:42:38 UTC, Pavel wrote:
> Either I do not understand the work of this feature or it is an obvious bug:
>
> import std.stdio;
> import std.conv;
>
> void main()
> {
>    enum string expr = "DMD compiles this garbage ... iiiii - \" #### $$$";
> 	
>    enum bool bTest = __traits(compiles, expr);
>    enum bool bTest2 = __traits(compiles, "int i = q{};");
> 		
>    writeln("bTest: " ~ to!string(bTest));
>    writeln("bTest2: " ~ to!string(bTest2));
> }
>
> Produces (tested with dmd32 2.060 and dmd32 2.059):
>   bTest: true
>   bTest2: true
>
> (http://dpaste.dzfl.pl/5d338ab3)
>
> Could you please somebody explain this?
>
> Thanks,
> Pavel

__traits(compiles, xxx) just verifies that xxx does not resolve to error. In your case, it resolves to... string!

Perhaps you wanted to mixin the string?

//----
import std.stdio;
import std.conv;

void main()
{
   enum string expr = "DMD compiles this garbage ... iiiii - \" #### $$$";
	
   enum bool bTest = __traits(compiles, mixin(expr));
   enum bool bTest2 = __traits(compiles, mixin("int i = q{};"));
   enum bool bTest3 = __traits(compiles, mixin("(int i) => 2*i"));
		
   writeln("bTest: " ~ to!string(bTest));
   writeln("bTest2: " ~ to!string(bTest2));
   writeln("bTest3: " ~ to!string(bTest3));
}
//----
December 17, 2012
On 2012-42-17 11:12, Pavel <proger79@gmail.com> wrote:

> Either I do not understand the work of this feature or it is an obvious bug:
>
> import std.stdio;
> import std.conv;
>
> void main()
> {
>     enum string expr = "DMD compiles this garbage ... iiiii - \" #### $$$";
> 	
>     enum bool bTest = __traits(compiles, expr);
>     enum bool bTest2 = __traits(compiles, "int i = q{};");
> 		
>     writeln("bTest: " ~ to!string(bTest));
>     writeln("bTest2: " ~ to!string(bTest2));
> }
>
> Produces (tested with dmd32 2.060 and dmd32 2.059):
>    bTest: true
>    bTest2: true
>
> (http://dpaste.dzfl.pl/5d338ab3)
>
> Could you please somebody explain this?
>
> Thanks,
> Pavel

Let's start off with the obligatory 'You're doing it wrong'.

__traits(compiles, ...) does not check the content of strings.
If you want that, use mixin("somestring").

What your code does is simply check if the string is one that
could be embedded in D code, which both of them can.

If instead of using strings you do this:

   enum bool bTest2 = __traits(compiles, {int i = q{};});

You will see that the result is false.

-- 
Simen
December 17, 2012
On Monday, 17 December 2012 at 10:59:38 UTC, mist wrote:
> Argument is supposed to be not a string but plain D code. And it is pretty logical that string literal is a valid compiling D code, as well as an existing variable name.
>
> On Monday, 17 December 2012 at 10:42:38 UTC, Pavel wrote:
>> Either I do not understand the work of this feature or it is an obvious bug:
>>
>> import std.stdio;
>> import std.conv;
>>
>> void main()
>> {
>>   enum string expr = "DMD compiles this garbage ... iiiii - \" #### $$$";
>> 	
>>   enum bool bTest = __traits(compiles, expr);
>>   enum bool bTest2 = __traits(compiles, "int i = q{};");
>> 		
>>   writeln("bTest: " ~ to!string(bTest));
>>   writeln("bTest2: " ~ to!string(bTest2));
>> }
>>
>> Produces (tested with dmd32 2.060 and dmd32 2.059):
>>  bTest: true
>>  bTest2: true
>>
>> (http://dpaste.dzfl.pl/5d338ab3)
>>
>> Could you please somebody explain this?
>>
>> Thanks,
>> Pavel

Thanks for the clarification - now everything is clear!
December 17, 2012
On Monday, 17 December 2012 at 11:03:01 UTC, Simen Kjaeraas wrote:
> On 2012-42-17 11:12, Pavel <proger79@gmail.com> wrote:
>
>> Either I do not understand the work of this feature or it is an obvious bug:
>>
>> import std.stdio;
>> import std.conv;
>>
>> void main()
>> {
>>    enum string expr = "DMD compiles this garbage ... iiiii - \" #### $$$";
>> 	
>>    enum bool bTest = __traits(compiles, expr);
>>    enum bool bTest2 = __traits(compiles, "int i = q{};");
>> 		
>>    writeln("bTest: " ~ to!string(bTest));
>>    writeln("bTest2: " ~ to!string(bTest2));
>> }
>>
>> Produces (tested with dmd32 2.060 and dmd32 2.059):
>>   bTest: true
>>   bTest2: true
>>
>> (http://dpaste.dzfl.pl/5d338ab3)
>>
>> Could you please somebody explain this?
>>
>> Thanks,
>> Pavel
>
> Let's start off with the obligatory 'You're doing it wrong'.
>
> __traits(compiles, ...) does not check the content of strings.
> If you want that, use mixin("somestring").
>
> What your code does is simply check if the string is one that
> could be embedded in D code, which both of them can.
>
> If instead of using strings you do this:
>
>    enum bool bTest2 = __traits(compiles, {int i = q{};});
>
> You will see that the result is false.


Nice hint with __traits(compiles, { <statements> }) - thanks!
(Because as I've now read in documentation the __traits(compiles) does not accepts statements directly.)

Because when writing templates with operating code as strings it is easy to forget that __traits(compiles, ...) behaves so I suppose it is useful to create a utility template for it:

template Compiles(string code)
{
   enum bool Compiles = __traits(compiles, mixin("{" ~ code ~ "}"));
}

void main()
{
   enum string code1 = "int i = q{};";
   enum string code2 = "int i = 5; i++;";
	
   writeln("Compiles `" ~ code1 ~ "`: " ~ to!string(Compiles!code1));
   writeln("Compiles `" ~ code2 ~ "`: " ~ to!string(Compiles!code2));
}

Pavel
December 17, 2012
On Monday, 17 December 2012 at 12:04:30 UTC, Pavel wrote:
> On Monday, 17 December 2012 at 11:03:01 UTC, Simen Kjaeraas wrote:
>> On 2012-42-17 11:12, Pavel <proger79@gmail.com> wrote:
>>
>>> Either I do not understand the work of this feature or it is an obvious bug:
>>>
>>> import std.stdio;
>>> import std.conv;
>>>
>>> void main()
>>> {
>>>   enum string expr = "DMD compiles this garbage ... iiiii - \" #### $$$";
>>> 	
>>>   enum bool bTest = __traits(compiles, expr);
>>>   enum bool bTest2 = __traits(compiles, "int i = q{};");
>>> 		
>>>   writeln("bTest: " ~ to!string(bTest));
>>>   writeln("bTest2: " ~ to!string(bTest2));
>>> }
>>>
>>> Produces (tested with dmd32 2.060 and dmd32 2.059):
>>>  bTest: true
>>>  bTest2: true
>>>
>>> (http://dpaste.dzfl.pl/5d338ab3)
>>>
>>> Could you please somebody explain this?
>>>
>>> Thanks,
>>> Pavel
>>
>> Let's start off with the obligatory 'You're doing it wrong'.
>>
>> __traits(compiles, ...) does not check the content of strings.
>> If you want that, use mixin("somestring").
>>
>> What your code does is simply check if the string is one that
>> could be embedded in D code, which both of them can.
>>
>> If instead of using strings you do this:
>>
>>   enum bool bTest2 = __traits(compiles, {int i = q{};});
>>
>> You will see that the result is false.
>
>
> Nice hint with __traits(compiles, { <statements> }) - thanks!
> (Because as I've now read in documentation the __traits(compiles) does not accepts statements directly.)
>
> Because when writing templates with operating code as strings it is easy to forget that __traits(compiles, ...) behaves so I suppose it is useful to create a utility template for it:
>
> template Compiles(string code)
> {
>    enum bool Compiles = __traits(compiles, mixin("{" ~ code ~ "}"));
> }
>
> void main()
> {
>    enum string code1 = "int i = q{};";
>    enum string code2 = "int i = 5; i++;";
> 	
>    writeln("Compiles `" ~ code1 ~ "`: " ~ to!string(Compiles!code1));
>    writeln("Compiles `" ~ code2 ~ "`: " ~ to!string(Compiles!code2));
> }

Oops, bad idea - it will work only for self-contained code but will not work when code references some variables from current scope.
December 17, 2012
On Monday, 17 December 2012 at 12:20:23 UTC, Pavel wrote:

> Oops, bad idea - it will work only for self-contained code but will not work when code references some variables from current scope.

Template mixin helps to solve the issue, so the utility template can be:

mixin template Compiles(string code)
{
   enum bool Result = __traits(compiles, mixin("{" ~ code ~ "}"));
}

with usage:

  enum string code1 = "int i = q{};";
  int j = 0;
  enum string code2 = "j++;";
  enum string code3 = "void foo(){}";
			
  mixin Compiles!code1 compilesCode1;
  mixin Compiles!code2 compilesCode2;
  mixin Compiles!code3 compilesCode3;
	
  writeln("Compiles `" ~ code1 ~ "`: " ~ to!string(compilesCode1.Result) );
  writeln("Compiles `" ~ code2 ~ "`: " ~ to!string(compilesCode2.Result) );
  writeln("Compiles `" ~ code3 ~ "`: " ~ to!string(compilesCode3.Result) );

It seems to me handier to use it from templates manipulating code as strings than usage of __traits(compiles,...) directly.

Pavel
December 17, 2012
On Monday, 17 December 2012 at 14:15:42 UTC, Pavel wrote:
> It seems to me handier to use it from templates manipulating code as strings than usage of __traits(compiles,...) directly.

I'm not quite sure how this is nicer to use than »enum foo = __traits(compiles, { mixin(bar); });«, but tastes differ…

David
December 17, 2012
On Monday, 17 December 2012 at 14:18:25 UTC, David Nadlinger wrote:
> On Monday, 17 December 2012 at 14:15:42 UTC, Pavel wrote:
>> It seems to me handier to use it from templates manipulating code as strings than usage of __traits(compiles,...) directly.
>
> I'm not quite sure how this is nicer to use than »enum foo = __traits(compiles, { mixin(bar); });«, but tastes differ…

Yup, it is only IMHO :) Useful for forgetful people as me: because without the utility template it is easy to forget to use 'mixin' and to put the statements in the block.




« First   ‹ Prev
1 2