digitalmars.D.learn - Problem with taking inout, const references
- Uranuz (52/52) Mar 25 2014 I have problem with understanding of work of modifiers const,
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (18/25) Mar 25 2014 I am sure you know these as well, but here is my quick list:
- Uranuz (8/10) Mar 25 2014 Now I'm using 2.064. May be this bug is already fixed. In 2.065 I
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (4/8) Mar 25 2014 Still compiles for me. Could you please show us a minimal main() as well...
- Uranuz (6/10) Mar 26 2014 Yes. This exact piece of code compiles in 2.064, but it doesn't
- Uranuz (25/25) Mar 26 2014 Source of error is that I have also the following methods inside
- Uranuz (4/11) Mar 26 2014 If inout is treated as const does it mean that in this operator I
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (23/28) Mar 26 2014 I have not investigated the compiler code but the following is very
- Uranuz (25/25) Mar 26 2014 I modified this with casting pointer to pointer to *inout* and it
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (37/51) Mar 26 2014 I think it is a bug then. I only now understand the problem. Here is a
- Uranuz (5/11) Mar 26 2014 Yes. It's my mistake. For CPU there is only data (that are
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (14/16) Mar 26 2014 Go to
- Uranuz (2/2) Mar 27 2014 Posted bugreport.
- Kagamin (3/7) Mar 26 2014 shared is used for low-level multithreading, if you're not
I have problem with understanding of work of modifiers const, inout, immutable modifiers. As I understand inout keyword is intended to consume const, immutable and data without modifiers. It's how I expect it to work otherwise I don't understand what is the purpose of inout. In current implementation of language it looks like (it's just my feeling) that it's completly other modifier that connects badly with const and immutable. In this case I don't understand sense of it. Also I have strange feelings about shared, because it's not widely used in code that I'm experienced to see and lacks of good usage examples. May main question is that I don't understand sense of this error: Error: cannot implicitly convert expression (&c) of type const(Cookie)* to inout(Cookie)* It occured in the following code. Can someone understand what I'm doing wrong? Or is it a bug or something? struct Cookie { string name; string value; string domain; string path; string expires; bool isHTTPOnly; bool isSecure; void opAssign(string rhs) { value = rhs; } string toString() { string result = `Set-Cookie: ` ~ name ~ `=` ~ value; if( domain.length > 0 ) result ~= `; Domain=` ~ domain; if( path.length > 0 ) result ~= `; Path=` ~ path; if( expires.length > 0 ) result ~= `; Expires=` ~ expires; if( isHTTPOnly ) result ~= `; HttpOnly`; if( isSecure ) result ~= `; Secure`; return result; } } class ResponseCookies { Cookie[] _cookies; //..... inout(Cookie)* opBinaryRight(string op)(string name) inout if(op == "in") { foreach( ref inout(Cookie) c; _cookies ) if( c.name == name ) return &c; //Error is here return null; } }
Mar 25 2014
On 03/25/2014 12:20 PM, Uranuz wrote:I have problem with understanding of work of modifiers const, inout, immutable modifiers.I am sure you know these as well, but here is my quick list: const: "I shall not modify data" immutable: "I demand immutable data" inout: "Whatever the actual type qualifier is"As I understand inout keyword is intended to consume const, immutable and data without modifiers.Yes. Further, the code is compiled as 'const' (because const is compatible with mutable, immutable, and const).I don't understand what is the purpose of inout.So that the following function works with any kind of int array: inout(int)[] first_two(inout(int)[] arr) { // (input validation omitted) return arr[0..2]; } We don't have to write three overloads just for these qualifiers. (Yes, templates with constraints can be used as well.)Error: cannot implicitly convert expression (&c) of type const(Cookie)* to inout(Cookie)*Your code compiles with the development branch of dmd. What version are you using? Ali
Mar 25 2014
Your code compiles with the development branch of dmd. What version are you using?Now I'm using 2.064. May be this bug is already fixed. In 2.065 I experience problem that std.json library module is not compatible with code written for previous versions. This is why I returned to 2.064. As far as I understand these breaking changes were a mistake. Now I don't know how to deal with it. I'm not sure that using old Phobos verion with new compiler could be good solution. If were a mistake It doesn't sound reasonable to change existing code to compile with this version.
Mar 25 2014
On 03/25/2014 02:01 PM, Uranuz wrote:Still compiles for me. Could you please show us a minimal main() as well. Thank you, AliYour code compiles with the development branch of dmd. What version are you using?Now I'm using 2.064.
Mar 25 2014
Still compiles for me. Could you please show us a minimal main() as well. Thank you, AliYes. This exact piece of code compiles in 2.064, but it doesn't compile in my project. I don't know how to localize the problem yet. It's very strange. I have tried to create class instance with different modifiers (const, inout, immutable), because it could be because of type of array that I try to access. Very strange. I'll try to repeat it.
Mar 26 2014
Source of error is that I have also the following methods inside ResponseCookise class: void opIndexAssign(string value, string name) { auto cookie = name in this; if( cookie is null ) _cookies ~= Cookie(name, value); else cookie.value = value; } void opIndexAssign( ref Cookie value, string name ) { auto cookie = name in this; if( cookie is null ) _cookies ~= value; else *cookie = value; } In 2.065 I get other error message than in 2.064, but it still not very informative. Why I get message inside *in* operator but not in *opIndexAssign*?. And how could I solve this? /d800/f144.d(49): Error: cannot implicitly convert expression (&c) of type inout(const(Cookie))* to inout(Cookie)* /d800/f144.d(38): Error: template instance f144.ResponseCookies.opBinaryRight!"in" error instantiating /d800/f144.d(38): Error: rvalue of in expression must be an associative array, not f144.ResponseCookies
Mar 26 2014
If inout is treated as const does it mean that in this operator I can't assign new value to cookie object. In this case it means that I still should make separate class method with the same body to woraround this. I think that it's a bug. Am I right?void opIndexAssign(string value, string name) { auto cookie = name in this; if( cookie is null ) _cookies ~= Cookie(name, value); else cookie.value = value; }
Mar 26 2014
On 03/26/2014 01:21 AM, Uranuz wrote:If inout is treated as const does it mean that in this operator I can't assign new value to cookie object.I have not investigated the compiler code but the following is very logical to me. inout is not a template mechanism. The code gets compiled once. What happens is, the inout from some variable is transferred to some other variable(s). Since inout must work with mutable, const, and immutable, and since const binds to all three, it is easy for the compiler to assume inout is const inside the code and reject code that tries to modify an inout variable (even if inout is 'mutable' for some calls to the function). After compiling the code, the compiler also ensures that the inout that is returned from the function is compatible with the calling code. For example, if the source inout array were immutable, a slice of it should not be assigned to a mutable slice at the caller site: inout(int)[] foo(inout(int)[] arr) { return arr; } immutable(int)[] imm = // ...; int[] result = foo(imm); // ERRORIn this case it means that I still should make separate class method with the same body to woraround this. I think that it's a bug. Am I right?It is not a bug. If the member function makes modifications to the object, it cannot be inout, because it can work only with mutable objects. Ali
Mar 26 2014
I modified this with casting pointer to pointer to *inout* and it compiles then. inout(Cookie)* opBinaryRight(string op)(string name) inout if(op == "in") { foreach( ref inout(Cookie) c; _cookies ) if( c.name == name ) return cast(inout(Cookie)*) &c; //Error is here return null; } As I think compiler may be should create const version and mutable version of this function. In case when it's mutable it should return pointer to mutable pointer to *const* data when function is const. In first case it will be able to modify variable from outside using this pointer to mutable. Otherwise if pointer to *const* produced modification is not allowed. I don't understand why compiler produce pointer to const, when inout "converts" to mutable. I think that compiler should check that object field is not modified inside it's const method, but I don't understand why it produces pointer to nonconst in case when object field shouldn't be const. In case when all is treated like const I don't understand how *inout* could be useful to get mutable references and pointers as result of *inout* method when object (and it's fields) are mutable. Is this behaviour forbidden for some reason that I don't know?
Mar 26 2014
On 03/26/2014 12:17 PM, Uranuz wrote:I modified this with casting pointer to pointer to *inout* and it compiles then. inout(Cookie)* opBinaryRight(string op)(string name) inout if(op == "in") { foreach( ref inout(Cookie) c; _cookies ) if( c.name == name ) return cast(inout(Cookie)*) &c; //Error is here return null; }I think it is a bug then. I only now understand the problem. Here is a reduced case: class C { int[1] arr; inout(int)* foo() inout { foreach (ref e; arr) { static assert(is (typeof(e) == inout(const(int)))); // WAT? return &e; } } } void main() { (new C).foo(); } The problem is, when the foreach variable is ref, the type gains a const as well. Unless there is a reason for that we should file a bug. Another workaround for you is using the foreach index: { foreach(i, ref inout(Cookie) c; _cookies ) // NOTE i if( c.name == name ) return &_cookies[i]; // NOTE i return null; }As I think compiler may be should create const version and mutable version of this function.Type is a compile-time concept; there is no difference between the compiled mutable versus const versions of your inout function. So, there is no need for more than one compilation.In case when it's mutable it should return pointer to mutable pointer to *const* data when function is const.Makes sense and it should be checked at compile time.I don't understand why compiler produce pointer to const,I think that's a bug.In case when all is treated like constThe body of an inout function must not mutate the object because the same body supports the non-mutable cases as well. So, it is acceptable for the compiler to compile as if it's const. However, as you say, the interface of the function still obeys the actual types used in the program. You are right. I think it is just a bug. Ali
Mar 26 2014
Type is a compile-time concept; there is no difference between the compiled mutable versus const versions of your inout function. So, there is no need for more than one compilation.Yes. It's my mistake. For CPU there is only data (that are sequence of bits) and comands (that are sequence of bits too). Type is human interpretation of meaning of these bits.The problem is, when the foreach variable is ref, the type gains a const as well. Unless there is a reason for that we should file a bug.So problem is in foreach operator but not in *inout* itself. I haven't send a bug so I'm not familiar with it. How could I do it?
Mar 26 2014
On 03/26/2014 10:29 PM, Uranuz wrote:I haven't send a bug so I'm not familiar with it. How could I do it?Go to https://d.puremagic.com/issues/ Click "File an Issue" (but you may need to "Open a New Account" first). Product: D Component: DMD Version: D2 Importance: P3 normal A descriptive title... Additional Comments: the reduced code etc. Then click "Commit". Thank you, :) Ali
Mar 26 2014
Posted bugreport. https://d.puremagic.com/issues/show_bug.cgi?id=12478
Mar 27 2014
On Tuesday, 25 March 2014 at 19:20:10 UTC, Uranuz wrote:In this case I don't understand sense of it. Also I have strange feelings about shared, because it's not widely used in code that I'm experienced to see and lacks of good usage examples.shared is used for low-level multithreading, if you're not experienced in it, use safer methods from std.concurrency.
Mar 26 2014