digitalmars.D.learn - Error: cannot implicitly convert expression (this) of type const(S)
- Jonathan M Davis (39/39) Sep 18 2010 Okay, if I try and compile the following program.
- Ivo Kasiuk (12/28) Sep 18 2010 Actually, wouldn't it be much more simple to just copy the struct
- Jonathan M Davis (8/44) Sep 18 2010 No. The whole point here is to have a save() method. It's for a range, a...
- Steven Schveighoffer (39/68) Sep 18 2010 Yes, because you are converting "this" from a const(S) to an S to return...
- Jonathan M Davis (13/108) Sep 18 2010 Well, I was trying to make a deep copy (that's what it does if it doesn'...
- Steven Schveighoffer (7/29) Sep 20 2010 You don't want a deep copy of a range. All you want to copy is the
- Jonathan M Davis (5/10) Sep 20 2010 That makes sense, but whenever I see copy, I pretty much always think de...
Okay, if I try and compile the following program. struct S { property S save() const { return this; } int[] _val; } void main() { } I get the error message d.d(5): Error: cannot implicitly convert expression (this) of type const(S)= to S If I remove const from save(), then it works, but with const there, it does= n't.=20 If I change _val to int or a struct type which does not contain an array, i= t=20 works. If I change _val to a struct type which has a member variable which = is an=20 array, it doesn't work. =46rom the looks of it, there's something about having an array as a member= =20 variable which makes this blow up. Perhaps it has to do with the fact that = _val=20 is a reference type and would be shared? Do I need to declare a postplit=20 constructor to fix this? Declaring one doesn't seem to help, but maybe I ju= st=20 don't know how to declare them correctly. I tried this(this) { _val =3D _val.dup; } and it didn't do any good. Setting _val to null didn't work either. Does anyone have any clues as to what I'm doing wrong? Or is this yet anoth= er=20 bug in dmd? =2D Jonathan M Davis
Sep 18 2010
Am Samstag, den 18.09.2010, 02:15 -0700 schrieb Jonathan M Davis:Okay, if I try and compile the following program. =20 struct S { property S save() const { return this; } =20 int[] _val; } =20 void main() { } =20Actually, wouldn't it be much more simple to just copy the struct instance directly, without a save() method: S s1; S s2 =3D s1; And you could add a postblit to control the copy behavior concerning _val. Or if save() is supposed to behave different than normal copying maybe something like this could be the solution: S save() const { return S(_val.dup); }
Sep 18 2010
On Saturday 18 September 2010 06:45:51 Ivo Kasiuk wrote:Am Samstag, den 18.09.2010, 02:15 -0700 schrieb Jonathan M Davis:No. The whole point here is to have a save() method. It's for a range, and forward ranges have the save() method because a range doesn't necessarily have to be a struct and just doing a straight up copy with a class doesn't work.Okay, if I try and compile the following program. struct S { property S save() const { return this; } int[] _val; } void main() { }Actually, wouldn't it be much more simple to just copy the struct instance directly, without a save() method:S s1; S s2 = s1; And you could add a postblit to control the copy behavior concerning _val. Or if save() is supposed to behave different than normal copying maybe something like this could be the solution: S save() const { return S(_val.dup); }For some reason, I haven't gotten postblit to work. Outright creating a new one that's the same rather than trying to use the automatic copy mechanisms does seem like a good idea though. Thanks. - Jonathan M Davis
Sep 18 2010
On Sat, 18 Sep 2010 05:15:38 -0400, Jonathan M Davis <jmdavisProg gmx.com> wrote:Okay, if I try and compile the following program. struct S { property S save() const { return this; } int[] _val; } void main() { } I get the error message d.d(5): Error: cannot implicitly convert expression (this) of type const(S) to SYes, because you are converting "this" from a const(S) to an S to return it. Try: property const(S) save() const { return this; }If I remove const from save(), then it works, but with const there, it doesn't. If I change _val to int or a struct type which does not contain an array, it works. If I change _val to a struct type which has a member variable which is an array, it doesn't work.Because arrays are reference types. You can implicitly convert a const(int) to an int because it's not a reference type. But you can't implicitly convert a const(int *) to an int * because it's a reference type. That axiom of implicit conversion is propagated to structs as well -- if a struct has only value types, then it can be implicitly converted, reference types cannot. I'll give you an example of why your version should not work. Let's say it *did* compile, then this function is allowed to violate const: void foo(const(S) s) { S s2 = s.save; s2._val[0]++; assert(s2._val[0] == s._val[0]); // oops, I modified s._val[0], but s is const! }From the looks of it, there's something about having an array as a member variable which makes this blow up. Perhaps it has to do with the fact that _val is a reference type and would be shared? Do I need to declare a postplit constructor to fix this? Declaring one doesn't seem to help, but maybe I just don't know how to declare them correctly.In reality, you cannot make save const, unless you want to do a deep copy (but I recommend against that, save should be a quick operation). The solution is actually inout. With inout, you can assert that save does not modify the data, but that it doesn't alter the constancy of the actual type. property inout(S) save() inout { return this; } Should work for S, const(S) and immutable(S). However, inout doesn't work at all right now. Please vote for bug http://d.puremagic.com/issues/show_bug.cgi?id=3748 (oh wait, you already did, but others should too :) -Steve
Sep 18 2010
On Saturday 18 September 2010 09:58:15 Steven Schveighoffer wrote:On Sat, 18 Sep 2010 05:15:38 -0400, Jonathan M Davis <jmdavisProg gmx.com> wrote:Well, I was trying to make a deep copy (that's what it does if it doesn't have an array in it anyway). I suppose whether it really needs to be const or not depends on what you're trying to do with it. I'm definitely trying to create a range here, and if save() is supposed to make a copy of the range, whether that needs to be a shallow copy or a deep copy depends on what the std.algorithm stuff does with it. When I think copy, I usually think deep copy, but that's not necessarily the case. I will have to enquire as to the intent of save(). For value types, shallow copy and deep copy are the same, so it's not an issue. But for class ranges or struct ranges with references, it does become an issue.Okay, if I try and compile the following program. struct S { property S save() const { return this; } int[] _val; } void main() { } I get the error message d.d(5): Error: cannot implicitly convert expression (this) of type const(S) to SYes, because you are converting "this" from a const(S) to an S to return it. Try: property const(S) save() const { return this; }If I remove const from save(), then it works, but with const there, it doesn't. If I change _val to int or a struct type which does not contain an array, it works. If I change _val to a struct type which has a member variable which is an array, it doesn't work.Because arrays are reference types. You can implicitly convert a const(int) to an int because it's not a reference type. But you can't implicitly convert a const(int *) to an int * because it's a reference type. That axiom of implicit conversion is propagated to structs as well -- if a struct has only value types, then it can be implicitly converted, reference types cannot. I'll give you an example of why your version should not work. Let's say it *did* compile, then this function is allowed to violate const: void foo(const(S) s) { S s2 = s.save; s2._val[0]++; assert(s2._val[0] == s._val[0]); // oops, I modified s._val[0], but s is const! }From the looks of it, there's something about having an array as a member variable which makes this blow up. Perhaps it has to do with the fact that _val is a reference type and would be shared? Do I need to declare a postplit constructor to fix this? Declaring one doesn't seem to help, but maybe I just don't know how to declare them correctly.In reality, you cannot make save const, unless you want to do a deep copy (but I recommend against that, save should be a quick operation).The solution is actually inout. With inout, you can assert that save does not modify the data, but that it doesn't alter the constancy of the actual type. property inout(S) save() inout { return this; } Should work for S, const(S) and immutable(S). However, inout doesn't work at all right now. Please vote for bug http://d.puremagic.com/issues/show_bug.cgi?id=3748 (oh wait, you already did, but others should too :) -SteveI would _love_ for all of the const-related issues to be fixed, and I most definitely voted on at least the major ones. Heck, when I started using D back with 2.017 or so, I chose D2 over D1 because D2 had const and D1 didn't.
Sep 18 2010
On Sat, 18 Sep 2010 17:20:31 -0400, Jonathan M Davis <jmdavisProg gmx.com> wrote:On Saturday 18 September 2010 09:58:15 Steven Schveighoffer wrote:You don't want a deep copy of a range. All you want to copy is the iteration state, not the data. save is definitely supposed to be shallow. I.e. you should copy the range itself, not what the range points to. -SteveIn reality, you cannot make save const, unless you want to do a deep copy (but I recommend against that, save should be a quick operation).Well, I was trying to make a deep copy (that's what it does if it doesn't have an array in it anyway). I suppose whether it really needs to be const or not depends on what you're trying to do with it. I'm definitely trying to create a range here, and if save() is supposed to make a copy of the range, whether that needs to be a shallow copy or a deep copy depends on what the std.algorithm stuff does with it. When I think copy, I usually think deep copy, but that's not necessarily the case. I will have to enquire as to the intent of save(). For value types, shallow copy and deep copy are the same, so it's not an issue. But for class ranges or struct ranges with references, it does become an issue.
Sep 20 2010
On Monday, September 20, 2010 04:11:05 Steven Schveighoffer wrote:You don't want a deep copy of a range. All you want to copy is the iteration state, not the data. save is definitely supposed to be shallow. I.e. you should copy the range itself, not what the range points to.That makes sense, but whenever I see copy, I pretty much always think deep copy, though obviously a copy isn't always a deep copy or you wouldn't need the word deep. - Jonathan M Davis
Sep 20 2010