www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Argument S to typeof is not an expression

reply "Meta" <jared771 gmail.com> writes:
template Test(alias N)
if (isIntegral!(typeof(N)))
{
     struct S
     {
         typeof(N) n = N;

         auto opAdd(T)(T rhs)
         {
             //Error: argument S to typeof is not an expression
             pragma(msg, typeof(T));
             //Error: variable rhs cannot be read at compile time
             return Test!(n + rhs.n);
         }
     }
     auto st = S(N);
     alias Test = st;
}

void main()
{
     auto a = Test!2;
     auto b = Test!3;
     writeln(typeof(a).stringof ~ " a = ", a, ", ",
             typeof(b).stringof ~ " b = ", b, ", ",
             typeof(a + b).stringof ~ " a + b = ");
}

I don't really understand why either of these error messages are 
occurring. The first is just incomprehensible, and the second 
seems like it should work. In this case, rhs is fully accessible 
at compile time in the expression (a + b), so why does the 
compiler complain?
May 06 2013
next sibling parent reply "Anonimous" <tr1 google.com> writes:
On Tuesday, 7 May 2013 at 06:41:25 UTC, Meta wrote:
 template Test(alias N)
 if (isIntegral!(typeof(N)))
 {
     struct S
     {
         typeof(N) n = N;

         auto opAdd(T)(T rhs)
         {
             //Error: argument S to typeof is not an expression
             pragma(msg, typeof(T));
             //Error: variable rhs cannot be read at compile time
             return Test!(n + rhs.n);
         }
     }
     auto st = S(N);
     alias Test = st;
 }

 void main()
 {
     auto a = Test!2;
     auto b = Test!3;
     writeln(typeof(a).stringof ~ " a = ", a, ", ",
             typeof(b).stringof ~ " b = ", b, ", ",
             typeof(a + b).stringof ~ " a + b = ");
 }

 I don't really understand why either of these error messages 
 are occurring. The first is just incomprehensible, and the 
 second seems like it should work. In this case, rhs is fully 
 accessible at compile time in the expression (a + b), so why 
 does the compiler complain?
First error occures,because typeof(T) is undefined - T is a type,not value. About second error,although in this case rhs is accessible,compiler can't know that you won't call this function in runtime,so it's expected - it's just ordinary function.
May 07 2013
parent "Anonimous" <tr1 google.com> writes:
Sorry for my english.
May 07 2013
prev sibling next sibling parent reply "Dicebot" <m.strashun gmail.com> writes:
On Tuesday, 7 May 2013 at 06:41:25 UTC, Meta wrote:
 I don't really understand why either of these error messages 
 are occurring. The first is just incomprehensible, and the 
 second seems like it should work. In this case, rhs is fully 
 accessible at compile time in the expression (a + b), so why 
 does the compiler complain?
1) typeof don't work on types. Period. It is often inconvenient in generic code (I'd love it typeof(T) to be T for simplicity) but it is how it is done now. In your case pragma(msg, T) will be correct one. 2) template parameter must be known at compile time. "rhs" is a plain function parameter, so compiler can't be sure it is known at compile time, so it is an error. Same goes for n. In general, only enum's and template parameters can be assumed to be known at compile-time. Your code seems to wrongly mix plain variables with template code all over. If you can explain for behavior/API you are trying to achieve, most likely I'll be able to provide a more idiomatic D solution.
May 07 2013
parent reply "Meta" <jared771 gmail.com> writes:
On Tuesday, 7 May 2013 at 10:33:58 UTC, Dicebot wrote:
 On Tuesday, 7 May 2013 at 06:41:25 UTC, Meta wrote:
 I don't really understand why either of these error messages 
 are occurring. The first is just incomprehensible, and the 
 second seems like it should work. In this case, rhs is fully 
 accessible at compile time in the expression (a + b), so why 
 does the compiler complain?
1) typeof don't work on types. Period. It is often inconvenient in generic code (I'd love it typeof(T) to be T for simplicity) but it is how it is done now. In your case pragma(msg, T) will be correct one. 2) template parameter must be known at compile time. "rhs" is a plain function parameter, so compiler can't be sure it is known at compile time, so it is an error. Same goes for n. In general, only enum's and template parameters can be assumed to be known at compile-time. Your code seems to wrongly mix plain variables with template code all over. If you can explain for behavior/API you are trying to achieve, most likely I'll be able to provide a more idiomatic D solution.
This is a little test to see if I can wrap types in structs and do some checking at compile time. For example, statically verifying in opAdd that neither number being added is negative. I added in the pragma to see what T's type is because I had the example compiling before, but two S structs added together was giving a result of void, and I was trying to figure out why that was happening.
May 07 2013
parent reply "Dicebot" <m.strashun gmail.com> writes:
On Tuesday, 7 May 2013 at 15:05:40 UTC, Meta wrote:
 This is a little test to see if I can wrap types in structs and
 do some checking at compile time. For example, statically
 verifying in opAdd that neither number being added is negative. 
 I
 added in the pragma to see what T's type is because I had the
 example compiling before, but two S structs added together was
 giving a result of void, and I was trying to figure out why that
 was happening.
To sum up short: you can't. Not because of D limitations but for unfortunate reason magic does not really work in our world. You can't check at compile-time data that is known only at run-time and function body can't possibly know anything about caller. It can be called from anywhere by anyone. However, if you only want to allow opAdd to accept data known at compile-time, you can either move it to template argument or just make a run-time check and execute whole function with CTFE. That is most likely reason your snippet has worked for a simpler code - CTFE kicked in and everything including function body was completely evaluated at compile-time. But no, you can't possibly check function argument at compile-time, not without extra restrictions. Better approach may be enforcing restriction into the type system by defining some NonNegativeInt user type that implements semantics you want. But even then it will need some sort of run-time check in constructor, important benefit is that it only needs to be run once upon boxing. Make your choices and I am ready to help :)
May 08 2013
parent reply "Meta" <jared771 gmail.com> writes:
I tried defining opAdd for S as following:

auto opAdd(alias rhs)()
if (is(typeof(rhs) == S))
{
     return Test!(n + rhs.n);
}

Which I know is kind of silly, since I can't use opAdd to do a + 
b anymore, but it fails to compile anyway. The compiler says that 
b (of type Test) does not match a's version of opAdd, which 
doesn't seem right to me.

Removing the template constraint doesn't help either, as I run 
into "local variable argument to non-global template" bug, and I 
can't get the structs to be evaluated at compile time, so I guess 
that's a lost cause.
May 08 2013
parent reply "Dicebot" <m.strashun gmail.com> writes:
On Thursday, 9 May 2013 at 01:08:28 UTC, Meta wrote:
 I can't get the structs to be evaluated at compile time, so I 
 guess that's a lost cause.
Well, structs can be evaluated at compile-time but can't be value template parameters. You can do a small trick in this case though: http://dpaste.1azy.net/c2188c90 struct Test(int N) { enum n = N; auto add(int i)() { return Test!(n + i)(); } alias n this; } void main() { import std.stdio; enum a = Test!5(); enum b = Test!3(); writeln(a.add!b()); } Will this do? But actually this feels more like a task for CTFE. You can write a normal opAdd that does bounds check at run-time and then add "if (!__ctfe) assert(0);" to guarantee it will never be used in real run-time.
May 09 2013
parent reply "Meta" <jared771 gmail.com> writes:
 then add "if (!__ctfe) assert(0);" to guarantee it will never 
 be used in real run-time.
I don't think I've ever seen __ctfe before. Is it specific to DMD?
May 09 2013
parent "Dicebot" <m.strashun gmail.com> writes:
On Thursday, 9 May 2013 at 12:35:29 UTC, Meta wrote:
 then add "if (!__ctfe) assert(0);" to guarantee it will never 
 be used in real run-time.
I don't think I've ever seen __ctfe before. Is it specific to DMD?
It is documented here : http://dlang.org/function.html "The __ctfe boolean pseudo-variable, which evaluates to true at compile time, but false at run time, can be used to provide an alternative execution path to avoid operations which are forbidden at compile time. Every usage of __ctfe is evaluated before code generation and therefore has no run-time cost, even if no optimizer is used" So no, it is quite official and not specific to dmd.
May 09 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-05-07 08:41, Meta wrote:
 template Test(alias N)
 if (isIntegral!(typeof(N)))
 {
      struct S
      {
          typeof(N) n = N;

          auto opAdd(T)(T rhs)
          {
              //Error: argument S to typeof is not an expression
              pragma(msg, typeof(T));
              //Error: variable rhs cannot be read at compile time
              return Test!(n + rhs.n);
          }
      }
      auto st = S(N);
      alias Test = st;
 }

 void main()
 {
      auto a = Test!2;
      auto b = Test!3;
      writeln(typeof(a).stringof ~ " a = ", a, ", ",
              typeof(b).stringof ~ " b = ", b, ", ",
              typeof(a + b).stringof ~ " a + b = ");
 }

 I don't really understand why either of these error messages are
 occurring. The first is just incomprehensible, and the second seems like
 it should work. In this case, rhs is fully accessible at compile time in
 the expression (a + b), so why does the compiler complain?
As a workaround for "typeof" you can use this: https://github.com/jacob-carlborg/orange/blob/master/orange/util/Traits.d#L213 -- /Jacob Carlborg
May 07 2013
parent reply "Dicebot" <m.strashun gmail.com> writes:
On Tuesday, 7 May 2013 at 11:03:31 UTC, Jacob Carlborg wrote:
 As a workaround for "typeof" you can use this:

 https://github.com/jacob-carlborg/orange/blob/master/orange/util/Traits.d#L213
You may want to update your implementation: http://dpaste.1azy.net/640a2580
May 07 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-05-07 13:08, Dicebot wrote:

 You may want to update your implementation: http://dpaste.1azy.net/640a2580
Thanks. -- /Jacob Carlborg
May 07 2013