www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 6695] New: immutable not inherited by members

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695

           Summary: immutable not inherited by members
           Product: D
           Version: unspecified
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: major
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: luka8088 owave.net



import std.stdio;

immutable struct a {
  b b1;
}

struct b {
  void c () immutable {
    writeln(typeid(typeof(this))); // b instead of immutable(b)
  }
}
void main () {
  a a1;
  a1.b1.c();
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Sep 19 2011
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695


Steven Schveighoffer <schveiguy yahoo.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |schveiguy yahoo.com
            Version|unspecified                 |D2
            Summary|immutable not inherited by  |typeof(this) does not take
                   |members                     |into account
                   |                            |const/immutable attributes
                   |                            |inside member functions



05:53:59 PDT ---
This is only a problem with the expression typeof(this), the real reference
'this' actually *is* immutable:

simplified example:

import std.stdio;

struct b {
   void c () immutable {
      writeln(typeid(typeof(this))); // b
      auto x = this;
      writeln(typeid(typeof(x))); // immutable(b)
   }
}

void main()
{
   immutable b b1;
   b1.c();
}

However, if you tried to change a member of b, you will get a compiler error. 
So the type of the this reference inside c() is not simply b, it really is
immutable(b).

However, typeof(this) is a special expression that the compiler replaces with
the actual type of the struct (i.e. struct b).

This is so it can be used in static functions and at a declaration level.  See
the special cases here:
http://www.d-programming-language.org/declaration.html#Typeof

However, I think it is extremely unintuitive to make that happen inside a
member function as well.  I'm not sure if this is an enhancement, it's not
exactly clear from the spec that typeof(this) should still be a special case
*inside* a member function.  It says it should be the same as if it were inside
a member function, it doesn't say *what kind* of member function.

At the very least, this is a doc bug.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Sep 20 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695




The actual problem is:


import std.stdio;

immutable struct a {
  b b1;
}

struct b {
  /*
    void c () { }
      case 1 => Error: function b.c () is not callable using argument types ()
immutable
    void c () immutable { }
     case 2 => Error: function b.c () immutable is not callable using argument
types ()
  */
  void c () { }
}
void main () {

  a a1;
  b b1;

  a1.b1.c(); // case 1
  b1.c();    // case 2

}



Lets say there is a struct b that can be independent and is mutable. On the
other hand we have struct a that has b immutable, by some reason immutable is
not inherited by void c () { }, so by trying to call a1.b1.c(); compiler throws
Error: function b.c () is not callable using argument types () immutable

I also tried a work-around by making void c () immutable { }, but then
independent usage of b throws Error: function b.c () immutable is not callable
using argument types ()


The reason for trying typeof(this) is I was trying to make two functions:
  void c () if (is(typeof(this) == b)) { }
  void c () if (is(typeof(this) == immutable(b))) immutable { }
but since typeof(this) does not indicate immutable I found no work-around.

Until this is resolved, is there any work-around for this situation... or am I
doing something wrong ?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Sep 20 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695




08:47:22 PDT ---
void c() const {}

This should work, as mutable and const implicitly cast to immutable.

Two other things (even though the above is the *right* solution to your
problem):

1. You can overload c, you don't need to use a template
2. You *can* get the exact type called with by using a this template parameter:

import std.stdio;

struct b
{
    void c(this T)() const
    {
        writeln(typeid(T));
    }
}

void main()
{
    immutable b b1;
    b b2;
    b1.c();
    b2.c();
}

output:

immutable(testimmutable.b)
testimmutable.b

But please note, the struct a has nothing to do with these issues, it's just
simply a way you have declared an immutable b (which you can easily do on the
stack).

Declaring an immutable struct is the same as applying immutable to all the
members.  Declaring a local immutable variable is the same thing.

Also note that in your attempt to use if constraints, you must use templates
(I'm sure you would have gotten error messages, so I think this is a simple
copy-paste omission)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Sep 20 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695




08:48:52 PDT ---

 void c() const {}
 
 This should work, as mutable and const implicitly cast to immutable.
Oh my, that was completely off. Should have read: This should work, as mutable and immutable implicitly cast to const. Sorry... -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 20 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695





 void c() const {}
 
 This should work, as mutable and const implicitly cast to immutable.
yes, it works, thx !
 Declaring an immutable struct is the same as applying immutable to all the
 members.  Declaring a local immutable variable is the same thing.
 
so this is a bug or not ... ? // Error: function b.c () is not callable using argument types () immutable import std.stdio; immutable struct a { b b1; } struct b { void c () { } } void main () { a a1; a1.b1.c(); } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 20 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695




10:26:54 PDT ---

 so this is a bug or not ... ?
 
 // Error: function b.c () is not callable using argument types () immutable
 
 import std.stdio;
 
 immutable struct a {
   b b1;
 }
 
 struct b {
   void c () { }
 }
 
 void main () {
   a a1;
   a1.b1.c();
 }
Not a bug. Inside the c function, 'this' is mutable, and you are trying to pass an immutable struct as the 'this' parameter. Immutable cannot implicitly cast to mutable, so it fails to compile. You should read up on the spec documentation about const and immutable, it will help to understand it. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 20 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695






 so this is a bug or not ... ?
 
 // Error: function b.c () is not callable using argument types () immutable
 
 import std.stdio;
 
 immutable struct a {
   b b1;
 }
 
 struct b {
   void c () { }
 }
 
 void main () {
   a a1;
   a1.b1.c();
 }
Not a bug. Inside the c function, 'this' is mutable, and you are trying to pass an immutable struct as the 'this' parameter. Immutable cannot implicitly cast to mutable, so it fails to compile. You should read up on the spec documentation about const and immutable, it will help to understand it.
I agree that maybe this is not a bug, but I don't agree with the explanation ... Documentation says "Both immutable and const are transitive, which means that any data reachable through an immutable reference is also immutable, and likewise for const." So in this example: import std.stdio; immutable struct a { b b1; } struct b { immutable void c () { } void d () { } immutable int e ; int f ; } void main () { a a1; b b1; writeln(" b1.c ", typeid(typeof(b1.c))); // immutable(void()) writeln(" b1.d ", typeid(typeof(b1.d))); // void() writeln(" b1.e ", typeid(typeof(b1.e))); // immutable(int) writeln(" b1.f ", typeid(typeof(b1.f))); // int writeln("a1.b1.c ", typeid(typeof(a1.b1.c))); // immutable(void()) writeln("a1.b1.d ", typeid(typeof(a1.b1.d))); // void() writeln("a1.b1.e ", typeid(typeof(a1.b1.e))); // immutable(int) writeln("a1.b1.f ", typeid(typeof(a1.b1.f))); // immutable(int) } From the documentation, both typeid(typeof(a1.b1.d)) and typeid(typeof(a1.b1.f)) should be either mutable or immutable, right ? -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 20 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695




11:42:19 PDT ---

 I agree that maybe this is not a bug, but I don't agree with the explanation
 ... 
 
 Documentation says "Both immutable and const are transitive, which means that
 any data reachable through an immutable reference is also immutable, and
 likewise for const."
Note the key element here is *data*, not *functions*.
 So in this example:
[snip]
 From the documentation, both
   typeid(typeof(a1.b1.d))
 and
   typeid(typeof(a1.b1.f))
 should be either mutable or immutable, right ?
typeid(typeof(a1.b1.d)) is a method, not a piece of data. In fact, when you say typeof(a1.b1.d), you might as well have written typeof(b.d). There is a confusing concept to grasp, and it's made harder because of the terminology. An immutable function is not actually immutable. An immutable function is a member function that *can be called* on an immutable instance of the struct/class. The immutable modifier only affects the 'this' pointer, even though it seems like it's applied to the entire function. Remember that all member functions have a hidden this pointer? If we were forced to write them out, then this: struct S { void foo () immutable {} void foo2() const {} void foo3() {} } becomes this: struct S { void foo (ref immutable(S) this) {} void foo2(ref const(S) this) {} void foo3(ref S this) {} } Now you can see why its clear you cannot call for instance foo with a non-immutable instance of S. The reason the modifiers are applied to the function is because there's no parameter for them to cling to -- the parameter is hidden. If you want to discuss this more, I think the d.learn newsgroup is probably best, or you can email me directly. I'd be happy to answer any questions on it. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 20 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695






 I agree that maybe this is not a bug, but I don't agree with the explanation
 ... 
 
 Documentation says "Both immutable and const are transitive, which means that
 any data reachable through an immutable reference is also immutable, and
 likewise for const."
Note the key element here is *data*, not *functions*.
 So in this example:
[snip]
 From the documentation, both
   typeid(typeof(a1.b1.d))
 and
   typeid(typeof(a1.b1.f))
 should be either mutable or immutable, right ?
typeid(typeof(a1.b1.d)) is a method, not a piece of data. In fact, when you say typeof(a1.b1.d), you might as well have written typeof(b.d). There is a confusing concept to grasp, and it's made harder because of the terminology. An immutable function is not actually immutable. An immutable function is a member function that *can be called* on an immutable instance of the struct/class. The immutable modifier only affects the 'this' pointer, even though it seems like it's applied to the entire function. Remember that all member functions have a hidden this pointer? If we were forced to write them out, then this: struct S { void foo () immutable {} void foo2() const {} void foo3() {} } becomes this: struct S { void foo (ref immutable(S) this) {} void foo2(ref const(S) this) {} void foo3(ref S this) {} } Now you can see why its clear you cannot call for instance foo with a non-immutable instance of S. The reason the modifiers are applied to the function is because there's no parameter for them to cling to -- the parameter is hidden. If you want to discuss this more, I think the d.learn newsgroup is probably best, or you can email me directly. I'd be happy to answer any questions on it.
OK, I understand it now, you are right, thank you very much for detailed explanation ! -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 20 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695




---
This issue is not limited only typeof(this).

struct S
{
  int x;
  void f() immutable {
    static assert(is(typeof(x) == immutable(int)));  // fails!
    static assert(is(typeof(x) == int));  // pass, but it is fake
  }
}

Because typeof(x) inside immutable member function f is translated to
typeof(this.x), and `this` is specially typed as S, then typeof returns int.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 05 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695


Kenji Hara <k.hara.pg gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |patch



---
https://github.com/D-Programming-Language/dmd/pull/434

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 06 2011
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=6695


Walter Bright <bugzilla digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |bugzilla digitalmars.com
         Resolution|                            |FIXED



02:25:32 PDT ---
https://github.com/D-Programming-Language/dmd/commit/48ad063f127d3b150f4f1ed5cb4b27ff18d9b6fe

https://github.com/D-Programming-Language/dmd/commit/451dbb73e356e3cf530cfc11e1b5094bc2b823af

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 06 2011