| Thread overview | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
April 03, 2008 Workarounds for Lack of Mutable Keyword | ||||
|---|---|---|---|---|
| ||||
Part of the uneasiness about D's const is that it is much more strict than C++'s, and so has the perception of being more difficult to work with. For example, D lacks C++ mutable keyword, so that there is no way to specify a mutable field. Janice suggested a solution to this that would probably work for most purposes:
>There are trivial workarounds. Instead of
>
> class C
> {
> int x;
> mutable int y;
> }
>
> void f(const(C) c);
>
>just do this:
>
> class C
> {
> int x;
> }
>
> class D
> {
> int y;
> }
>
> void f(const(C) c, D d);
Although this may be good for most, this doesn't work for me, because to use this approach, I would have to make an extra heap allocation, and use an extra parameter. An extra parameter may not seem like a big deal to some. However, a compiler can optimize small recursive functions with small numbers of parameters using registers, so there could be a significant performance penalty for adding a single parameter to a recursive function.
I have a more hackish solution that won't cost me any performance. I'm pretty sure it will work, but I haven't quite fleshed out the details. Maybe some of you D template gurus could help me with this one. My idea is to have a ConstAssign template that would subvert const somehow and assign a value to const data. Here's how it would work to replace a mutable field:
class C
{
int x;
int y;
void setY(int ny) { ConstAssign(y, ny); }
}
Since D has pointers and unions, there's probably some ugly hackish trick we can employ to subvert const. The idea is to put this ugly hack in a template function. This would provide a not-so-messy workaround fo the lack of mutable that doesn't cost anyperformance or memory.
-Craig
| ||||
April 03, 2008 Re: Workarounds for Lack of Mutable Keyword | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Craig Black | I did it and it was very easy. I didn't know you could cast away const so easily in D. This works for const, but not invariant. Since we have the ability to subvert const so easily, there should be no problem living without mutable fields.
import std.stdio;
void ConstAssign(T)(ref const T x, T y) { *cast(T*)&x = y; }
class A
{
public:
int x;
int y;
void setY(int ny) const { ConstAssign(y, ny); }
}
void foo(const A a) { a.setY(2); }
int main(char[][] args)
{
A a = new A;
a.y = 1;
foo(a);
writefln(a.y);
return 0;
}
| |||
April 03, 2008 Re: Workarounds for Lack of Mutable Keyword | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Craig Black | Craig Black wrote:
> I did it and it was very easy. I didn't know you could cast away const so easily in D. This works for const, but not invariant. Since we have the ability to subvert const so easily, there should be no problem living without mutable fields.
>
> import std.stdio;
>
> void ConstAssign(T)(ref const T x, T y) { *cast(T*)&x = y; }
>
> class A
> {
> public:
> int x;
> int y;
> void setY(int ny) const { ConstAssign(y, ny); }
> }
>
> void foo(const A a) { a.setY(2); }
>
> int main(char[][] args)
> {
> A a = new A;
> a.y = 1;
> foo(a);
> writefln(a.y);
> return 0;
> }
ight, but be sure to synchronize for multi threaded access.
| |||
April 03, 2008 Re: Workarounds for Lack of Mutable Keyword | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Robert Fraser | "Robert Fraser" <fraserofthenight@gmail.com> wrote in message news:ft1r7d$1q0b$1@digitalmars.com... > Craig Black wrote: >> I did it and it was very easy. I didn't know you could cast away const so easily in D. This works for const, but not invariant. Since we have the ability to subvert const so easily, there should be no problem living without mutable fields. >> >> import std.stdio; >> >> void ConstAssign(T)(ref const T x, T y) { *cast(T*)&x = y; } >> >> class A >> { >> public: >> int x; >> int y; >> void setY(int ny) const { ConstAssign(y, ny); } >> } >> >> void foo(const A a) { a.setY(2); } >> >> int main(char[][] args) >> { >> A a = new A; >> a.y = 1; >> foo(a); >> writefln(a.y); >> return 0; >> } > > ight, but be sure to synchronize for multi threaded access. In the case that I'm thinking of using this for, I know multiple threads won't be contending for the "mutable" fields. -Craig | |||
April 03, 2008 Re: Workarounds for Lack of Mutable Keyword | ||||
|---|---|---|---|---|
| ||||
On 03/04/2008, Janice Caron <caron800@googlemail.com> wrote: > One problem with this function is demonstrated by > > string s = "hello world"; > > ConstAssign(h[0],'j'); Yikes! I think I must be going mad. That's too many typos for one day! Need more coffee. The h should have been an s. string s = "hello world"; ConstAssign(s[0],'j'); > Oops - it assigns invariants too! Even if you can be sure there are no > other threads vying for access to s, still, those chars might be in a > hardware-locked ROM segment. > > There's a reason why casting away const is not defined. | ||||
April 03, 2008 Re: Workarounds for Lack of Mutable Keyword | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Craig Black | On 03/04/2008, Craig Black <craigblack2@cox.net> wrote:
> void ConstAssign(T)(ref const T x, T y) { *cast(T*)&x = y; }
One problem with this function is demonstrated by
string s = "hello world";
ConstAssign(h[0],'j');
Oops - it assigns invariants too! Even if you can be sure there are no other threads vying for access to s, still, those chars might be in a hardware-locked ROM segment.
There's a reason why casting away const is not defined.
| |||
April 03, 2008 Re: Workarounds for Lack of Mutable Keyword | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Janice Caron | "Janice Caron" <caron800@googlemail.com> wrote in message news:mailman.301.1207206839.2351.digitalmars-d@puremagic.com... > On 03/04/2008, Craig Black <craigblack2@cox.net> wrote: >> void ConstAssign(T)(ref const T x, T y) { *cast(T*)&x = y; } > > One problem with this function is demonstrated by > > string s = "hello world"; > > ConstAssign(h[0],'j'); > > Oops - it assigns invariants too! Even if you can be sure there are no > other threads vying for access to s, still, those chars might be in a > hardware-locked ROM segment. > > There's a reason why casting away const is not defined. If that compiles, I think it may be a bug. Invariant types shouldn't be implicitly convertible to const. -Craig | |||
April 03, 2008 Re: Workarounds for Lack of Mutable Keyword | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Craig Black | The previous solution that I proposed only works because of a bug in DMD. See the "const/invariant bug" post for more info on the bug. But I found another solution. Const doesn't seem to cooperate well with templates, so
void ConstAssign(T)(ref const T a, T b) { *cast(T*)cast(int)(&a) = b; }
doesn't work but
void ConstAssign(T, S)(ref T a, S b) { *cast(S*)cast(int)(&a) = b; }
does work, as long as the second parameter not const.
Here's the full example:
import std.stdio;
void ConstAssign(T, S)(ref T a, S b) { *cast(S*)cast(int)(&a) = b; }
class A
{
public:
int x = 0;
const void setX(int nx) { ConstAssign(x, nx); }
}
void foo(const A a) { a.setX(1); }
int main(char[][] args)
{
A a = new A;
foo(a);
writefln(a.x);
return 0;
}
| |||
April 03, 2008 Re: Workarounds for Lack of Mutable Keyword | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Craig Black | The second solution that I posted didn't work if the second parameter was const. This solution will. It uses a ForceCast template. BTW, this template will work for more than just const. Since D doesn't allow returning a reference, we must pass a pointer to ForceCast and dereference the result.
import std.stdio;
T ForceCast(T, S)(S a) { return *cast(T*)cast(int)(&a); }
class A
{
public:
int x = 0;
const void setX(const int nx) { *ForceCast!(int*)(&x) = nx; }
}
void foo(const A a) { a.setX(1); }
int main(char[][] args)
{
A a = new A;
foo(a);
writefln(a.x);
return 0;
}
| |||
April 03, 2008 Re: Workarounds for Lack of Mutable Keyword | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Craig Black | On 03/04/2008, Craig Black <craigblack2@cox.net> wrote:
> If that compiles, I think it may be a bug. Invariant types shouldn't be
> implicitly convertible to const.
Yes they should.
const means "I promise not to modify this". There is absolutely no problem with promising not to modify something which is invariant.
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply