www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Accessing mutable data that isn't

reply "Spott" <andrew.spott gmail.com> writes:
I've been screwing around with templates lately, and I'm
attempting to figure out why the following won't compile:

struct value
{
      int a;

      const auto
          opBinary(string op, T)(in T rhs) const pure {
              static if (op == "+")
                  return intermediateValue!(value.plus,this,rhs)();
          }

      ref value opAssign(T)( in T t ) {
          a = t.a;
          return this;
      }

      static
      int plus(T1, T2)(in T1 x, in T2 y) pure {
          return x.a + y.a;
      }

}

struct intermediateValue(alias Op, alias A, alias B)
{

      auto opBinary(string op, T)(in T rhs) const pure {
          static if (op == "+")
              return intermediateValue!(value.plus,this,rhs)();
      }

       property auto a() const pure {
          return Op(A, B);
      }

}

void main()
{
      value a = value(2);
      value b = value(3);
      value c;
      c = a + b;
}

The error is:
d_playground.d(34): Error: pure nested function 'a' cannot access
mutable data 'this'
d_playground.d(34): Error: pure nested function 'a' cannot access
mutable data 'this'
d_playground.d(10): Error: template instance
d_playground.value.opBinary!("+",
value).opBinary.intermediateValue!(plus, this, rhs) error
instantiating
d_playground.d(44):        instantiated from here: opBinary!("+",
value)
d_playground.d(44): Error: template instance
d_playground.value.opBinary!("+", value) error instantiating

What is going on?  Why is 'a' not allowed to "access" mutable
data (even though it isn't modifying it)? How do I tell the
compiler to pass "this" in a const fashion?
Nov 20 2013
next sibling parent "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Wednesday, 20 November 2013 at 22:49:42 UTC, Spott wrote:
 I've been screwing around with templates lately, and I'm
 attempting to figure out why the following won't compile:

 struct value
 {
      int a;

      const auto
          opBinary(string op, T)(in T rhs) const pure {
              static if (op == "+")
                  return 
 intermediateValue!(value.plus,this,rhs)();
          }
const here is redundant, probably wanted const(auto) which isn't valid syntax. The function being const may already be returning a const type.
 What is going on?  Why is 'a' not allowed to "access" mutable
 data (even though it isn't modifying it)? How do I tell the
 compiler to pass "this" in a const fashion?
I'm not seeing an issue with the declarations. The function being declared as const is what make 'this' const. Probably should file as a bug if you don't get any confirmation soon. And reply with the bug entry.
Nov 20 2013
prev sibling next sibling parent reply "qznc" <qznc web.de> writes:
On Wednesday, 20 November 2013 at 22:49:42 UTC, Spott wrote:
 I've been screwing around with templates lately, and I'm
 attempting to figure out why the following won't compile:

 struct value
 {
      int a;

      const auto
          opBinary(string op, T)(in T rhs) const pure {
              static if (op == "+")
                  return 
 intermediateValue!(value.plus,this,rhs)();
          }

      ref value opAssign(T)( in T t ) {
          a = t.a;
          return this;
      }

      static
      int plus(T1, T2)(in T1 x, in T2 y) pure {
          return x.a + y.a;
      }

 }

 struct intermediateValue(alias Op, alias A, alias B)
 {

      auto opBinary(string op, T)(in T rhs) const pure {
          static if (op == "+")
              return intermediateValue!(value.plus,this,rhs)();
      }

       property auto a() const pure {
          return Op(A, B);
      }

 }

 void main()
 {
      value a = value(2);
      value b = value(3);
      value c;
      c = a + b;
 }

 The error is:
 d_playground.d(34): Error: pure nested function 'a' cannot 
 access
 mutable data 'this'
 d_playground.d(34): Error: pure nested function 'a' cannot 
 access
 mutable data 'this'
 d_playground.d(10): Error: template instance
 d_playground.value.opBinary!("+",
 value).opBinary.intermediateValue!(plus, this, rhs) error
 instantiating
 d_playground.d(44):        instantiated from here: 
 opBinary!("+",
 value)
 d_playground.d(44): Error: template instance
 d_playground.value.opBinary!("+", value) error instantiating

 What is going on?  Why is 'a' not allowed to "access" mutable
 data (even though it isn't modifying it)? How do I tell the
 compiler to pass "this" in a const fashion?
No answer, but two notes. First, use dpaste for such code snippets: http://dpaste.dzfl.pl/f2f39b32 Second, what are you trying to do? intermediateValue is a struct without members. I am not sure what 'this' means in such a case.
Nov 20 2013
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, November 21, 2013 07:48:34 qznc wrote:
 First, use dpaste for such code snippets:
 http://dpaste.dzfl.pl/f2f39b32
Really? I find it annoying when people do that unless the code is quite long. It's much easier to have it just be in the message IMHO. Also, it has the benefit of not having to worry about the link not being valid in the future, potentially rendering the message impossible to understand. I have no idea how long dpaste links stick around; a while I expect, but there's no guarantee that they'll be around as long as the forum or its archives will be. - Jonathan M Davis
Nov 20 2013
parent "bearophile" <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 I find it annoying when people do that unless the code is quite 
 long.
 It's much easier to have it just be in the message IMHO. Also, 
 it has the
 benefit of not having to worry about the link not being valid 
 in the future,
I agree with Jonathan. External sites should be avoided unless the code is very long. (And you can even attach files in the D newsgroups when the code is a little longer). On Bugzilla code you have to always avoid code external sites (unless it's GitHub, etc). Bye, bearophile
Nov 21 2013
prev sibling parent "Spott" <andrew.spott gmail.com> writes:
On Thursday, 21 November 2013 at 06:48:40 UTC, qznc wrote:
 On Wednesday, 20 November 2013 at 22:49:42 UTC, Spott wrote:
 I've been screwing around with templates lately, and I'm
 attempting to figure out why the following won't compile:

 struct value
 {
     int a;

     const auto
         opBinary(string op, T)(in T rhs) const pure {
             static if (op == "+")
                 return 
 intermediateValue!(value.plus,this,rhs)();
         }

     ref value opAssign(T)( in T t ) {
         a = t.a;
         return this;
     }

     static
     int plus(T1, T2)(in T1 x, in T2 y) pure {
         return x.a + y.a;
     }

 }

 struct intermediateValue(alias Op, alias A, alias B)
 {

     auto opBinary(string op, T)(in T rhs) const pure {
         static if (op == "+")
             return intermediateValue!(value.plus,this,rhs)();
     }

      property auto a() const pure {
         return Op(A, B);
     }

 }

 void main()
 {
     value a = value(2);
     value b = value(3);
     value c;
     c = a + b;
 }

 The error is:
 d_playground.d(34): Error: pure nested function 'a' cannot 
 access
 mutable data 'this'
 d_playground.d(34): Error: pure nested function 'a' cannot 
 access
 mutable data 'this'
 d_playground.d(10): Error: template instance
 d_playground.value.opBinary!("+",
 value).opBinary.intermediateValue!(plus, this, rhs) error
 instantiating
 d_playground.d(44):        instantiated from here: 
 opBinary!("+",
 value)
 d_playground.d(44): Error: template instance
 d_playground.value.opBinary!("+", value) error instantiating

 What is going on?  Why is 'a' not allowed to "access" mutable
 data (even though it isn't modifying it)? How do I tell the
 compiler to pass "this" in a const fashion?
No answer, but two notes. First, use dpaste for such code snippets: http://dpaste.dzfl.pl/f2f39b32 Second, what are you trying to do? intermediateValue is a struct without members. I am not sure what 'this' means in such a case.
intermediateValue is a structure that ideally should only exist at compile time. Theoretically, (at least in my head), opAssign will traverse the expression and reduce it to the addition that it is inside opAssign. I'm attempting to create a vector DSL (similar to blaze-lib: https://code.google.com/p/blaze-lib/), but starting with just a plain number. Mostly it is for fun, it is a way of working on my understanding of the compile time primitives and template system.
Nov 25 2013
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, November 20, 2013 23:49:42 Spott wrote:
 I've been screwing around with templates lately, and I'm
 attempting to figure out why the following won't compile:
 
 struct value
 {
       int a;
 
       const auto
           opBinary(string op, T)(in T rhs) const pure {
               static if (op == "+")
                   return intermediateValue!(value.plus,this,rhs)();
           }
 
       ref value opAssign(T)( in T t ) {
           a = t.a;
           return this;
       }
 
       static
       int plus(T1, T2)(in T1 x, in T2 y) pure {
           return x.a + y.a;
       }
 
 }
 
 struct intermediateValue(alias Op, alias A, alias B)
 {
 
       auto opBinary(string op, T)(in T rhs) const pure {
           static if (op == "+")
               return intermediateValue!(value.plus,this,rhs)();
       }
 
        property auto a() const pure {
           return Op(A, B);
       }
 
 }
 
 void main()
 {
       value a = value(2);
       value b = value(3);
       value c;
       c = a + b;
 }
 
 The error is:
 d_playground.d(34): Error: pure nested function 'a' cannot access
 mutable data 'this'
 d_playground.d(34): Error: pure nested function 'a' cannot access
 mutable data 'this'
 d_playground.d(10): Error: template instance
 d_playground.value.opBinary!("+",
 value).opBinary.intermediateValue!(plus, this, rhs) error
 instantiating
 d_playground.d(44):        instantiated from here: opBinary!("+",
 value)
 d_playground.d(44): Error: template instance
 d_playground.value.opBinary!("+", value) error instantiating
 
 What is going on?  Why is 'a' not allowed to "access" mutable
 data (even though it isn't modifying it)? How do I tell the
 compiler to pass "this" in a const fashion?
pure functions can only access their arguments and global/static constants. a's only argument is its invisible this pointer. Op, A, and B are aliases to stuff outside of a. I suppose that an argument could be made that because the're template arguments to the type that a is a part of that they should be considered to be arguments to a like the this pointer is, but you are essentially trying to have it access data which is not one of its arguments and that violates purity. But all in all, I find your code quite bizarre and difficult to understand - particularly your use of aliases - so it's kind of hard for me to say how valid it is. I'm surprised that you can get away with feeding a purely runtime argument to a template as an alias (namely rhs). I wouldn't have thought that that would be valid. In most cases, all template alias parameters get used for is passing in predicates to functions (which are almost invariably delegates or lambdas). So, clearly my understanding of how alias template parameters work is too limited. - Jonathan M Davis
Nov 20 2013
parent reply "Spott" <andrew.spott gmail.com> writes:
On Thursday, 21 November 2013 at 07:23:09 UTC, Jonathan M Davis
wrote:
 On Wednesday, November 20, 2013 23:49:42 Spott wrote:
 I've been screwing around with templates lately, and I'm
 attempting to figure out why the following won't compile:
 
 struct value
 {
       int a;
 
       const auto
           opBinary(string op, T)(in T rhs) const pure {
               static if (op == "+")
                   return 
 intermediateValue!(value.plus,this,rhs)();
           }
 
       ref value opAssign(T)( in T t ) {
           a = t.a;
           return this;
       }
 
       static
       int plus(T1, T2)(in T1 x, in T2 y) pure {
           return x.a + y.a;
       }
 
 }
 
 struct intermediateValue(alias Op, alias A, alias B)
 {
 
       auto opBinary(string op, T)(in T rhs) const pure {
           static if (op == "+")
               return intermediateValue!(value.plus,this,rhs)();
       }
 
        property auto a() const pure {
           return Op(A, B);
       }
 
 }
 
 void main()
 {
       value a = value(2);
       value b = value(3);
       value c;
       c = a + b;
 }
 
 The error is:
 d_playground.d(34): Error: pure nested function 'a' cannot 
 access
 mutable data 'this'
 d_playground.d(34): Error: pure nested function 'a' cannot 
 access
 mutable data 'this'
 d_playground.d(10): Error: template instance
 d_playground.value.opBinary!("+",
 value).opBinary.intermediateValue!(plus, this, rhs) error
 instantiating
 d_playground.d(44):        instantiated from here: 
 opBinary!("+",
 value)
 d_playground.d(44): Error: template instance
 d_playground.value.opBinary!("+", value) error instantiating
 
 What is going on?  Why is 'a' not allowed to "access" mutable
 data (even though it isn't modifying it)? How do I tell the
 compiler to pass "this" in a const fashion?
pure functions can only access their arguments and global/static constants. a's only argument is its invisible this pointer. Op, A, and B are aliases to stuff outside of a. I suppose that an argument could be made that because the're template arguments to the type that a is a part of that they should be considered to be arguments to a like the this pointer is, but you are essentially trying to have it access data which is not one of its arguments and that violates purity. But all in all, I find your code quite bizarre and difficult to understand - particularly your use of aliases - so it's kind of hard for me to say how valid it is. I'm surprised that you can get away with feeding a purely runtime argument to a template as an alias (namely rhs). I wouldn't have thought that that would be valid. In most cases, all template alias parameters get used for is passing in predicates to functions (which are almost invariably delegates or lambdas). So, clearly my understanding of how alias template parameters work is too limited. - Jonathan M Davis
Why is rhs a purely runtime argument? I would think it would be known at compile time.
Nov 25 2013
parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, November 25, 2013 18:34:30 Spott wrote:
 Why is rhs a purely runtime argument? I would think it would be
 known at compile time.
Function arguments are runtime entities, not compile-time entities and therefore cannot be used in places where a compile-time entity is required. e.g. this is illegal auto foo(int i)(int j) { return i * j; } auto bar(int k) { return foo!k(5); } because k is not known at compile time. Yes, it's true that if a function is used during CTFE, then its function arguments would technically be known at compile time, as the compiler is in the middle of compiling your program, however, from the function's perspective, it's runtime. It just so happens that it's being run at compile time. e.g. auto foo(int i) { return i; } enum f = foo(5); f must be known at compile time, so foo is called and run at compile time, but from foo's perspective, it's being run, not compiled. So, it can only do the things that it could do at runtime (plus whatever additional restrictions CTFE imposes - e.g. no I/O). Template parameters are compile-time entities and thus must be known at compile time. However, aliases are a bit funny in that they alias the symbol rather than using its value, so apparently, under some set of circumstances, a template alias parameter can accept a runtime argument, because it's the symbol that gets used and not its value, meaning that its value is not calculated until runtime, so it works. But any normal template parameter's value must be known at compile time. - Jonathan M Davis
Nov 25 2013