Thread overview
Cannot call mutable method on final struct
Sep 09, 2007
Christopher Wright
Sep 09, 2007
Carlos Santander
Sep 10, 2007
Christopher Wright
Sep 10, 2007
Christian Kamm
Sep 10, 2007
Carlos Santander
September 09, 2007
Hey everyone.

I get an error on the following code complaining about the use of Box.toString. The message is:
"Error: cannot call mutable method on final struct"

I don't know what that means. I believe it's complaining about const stuff and the struct being altered (that is all that makes sense, given the message and the fact that it's in a loop), but looking at the toString method in std.boxer.Box, it doesn't seem to alter the struct. As far as I can tell, the code should be valid.

The workaround is using 'ref Box b' (or 'ref b') in the foreach loop.

---
import std.boxer, std.string, std.stdio;

class C(U...) {
   string value;
   this (U u) {
      value = "";
      foreach (Box b; boxArray(u)) {
         value ~= b.toString;
      }
   }
}

void main () {
   auto c = new C!(int, string, char)(12, "foom", 't');
   writefln(c.value);
}
---

Can anyone here else say whether this is a bug in Box.toString or in determining whether a function is mutable?
September 09, 2007
Christopher Wright escribió:
> Hey everyone.
> 
> I get an error on the following code complaining about the use of Box.toString. The message is:
> "Error: cannot call mutable method on final struct"
> 
> I don't know what that means. I believe it's complaining about const stuff and the struct being altered (that is all that makes sense, given the message and the fact that it's in a loop), but looking at the toString method in std.boxer.Box, it doesn't seem to alter the struct. As far as I can tell, the code should be valid.
> 
> The workaround is using 'ref Box b' (or 'ref b') in the foreach loop.
> 
> ---
> import std.boxer, std.string, std.stdio;
> 
> class C(U...) {
>    string value;
>    this (U u) {
>       value = "";
>       foreach (Box b; boxArray(u)) {
>          value ~= b.toString;
>       }
>    }
> }
> 
> void main () {
>    auto c = new C!(int, string, char)(12, "foom", 't');
>    writefln(c.value);
> }
> ---
> 
> Can anyone here else say whether this is a bug in Box.toString or in determining whether a function is mutable?

I don't use D 2.0, but here it goes...

string is const(char)[] or const char[] or something like that... It's const, anyway, so you aren't supposed to modify it. Replace "string value" with "char[] value".

-- 
Carlos Santander Bernal
September 10, 2007
Carlos Santander wrote:
> I don't use D 2.0, but here it goes...
> 
> string is const(char)[] or const char[] or something like that... It's const, anyway, so you aren't supposed to modify it. Replace "string value" with "char[] value".
> 

If I use char[] rather than string, it fails with the error message I stated (and indeed, in the original, I used char[] accidentally). If I just call Box.toString and don't do anything with the returned string, it fails with the same error message.

'string ~= whatever' is valid because the string is not final. The compiler rewrites it as 'string = string ~ whatever'.

New minimal test case:
---
import std.boxer;
void main () {
   foreach (b; boxArray(9, 'b')) {
      b.toString;
   }
}
---
September 10, 2007
"Christopher Wright" <dhasenan@gmail.com> wrote in message news:fc3bdu$8tn$1@digitalmars.com...
> 'string ~= whatever' is valid because the string is not final. The compiler rewrites it as 'string = string ~ whatever'.

Iiii wouldn't be so sure about that.  I don't know if the compiler rewrites "a ~= b" as "a = a ~ b" when dealing with const stuff, but as far as D1 goes, ~= and ~ are two different operations.  ~ always creates a copy of the original data, while ~= attempts to resize the destination in place and append the new data in the newly-resized space.


September 10, 2007
Christopher Wright wrote:

> New minimal test case:
> ---
> import std.boxer;
> void main () {
>     foreach (b; boxArray(9, 'b')) {
>        b.toString;
>     }
> }
> ---

The problem is that the b defined in the foreach statement is final, thus D won't let you call non-const methods on it. Boxer.toString is not a const method.

Same thing without boxer or toString:
---
struct Foo
{
  const void const_bar() {}
  void nonconst_bar() {}
}

void main()
{
  Foo[] foo_arr;
  foo_arr.length = 1;

  foreach(foo; foo_arr)
  {
    foo.const_bar(); // OK
    foo.nonconst_bar(); // Error: cannot call mutable method on final struct
  }
}
---
September 10, 2007
Christopher Wright escribió:
> Carlos Santander wrote:
>> I don't use D 2.0, but here it goes...
>>
>> string is const(char)[] or const char[] or something like that... It's const, anyway, so you aren't supposed to modify it. Replace "string value" with "char[] value".
>>
> 
> If I use char[] rather than string, it fails with the error message I stated (and indeed, in the original, I used char[] accidentally). If I just call Box.toString and don't do anything with the returned string, it fails with the same error message.
> 
> 'string ~= whatever' is valid because the string is not final. The compiler rewrites it as 'string = string ~ whatever'.
> 
> New minimal test case:
> ---
> import std.boxer;
> void main () {
>    foreach (b; boxArray(9, 'b')) {
>       b.toString;
>    }
> }
> ---

In that case, I guess the workaround (ref b) is not really a workaround but the way it should be done.

-- 
Carlos Santander Bernal