www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - std.concurrency & immutable classes...

reply Tomek =?ISO-8859-2?B?U293afFza2k=?= <just ask.me> writes:
... doesn't work.

class C {}
thisTid.send(new immutable(C)());
receive((immutable C) { writeln("got it!"); });

This throws: core.exception.AssertError /usr/include/d/dmd/phobos
std/variant.d(285): immutable(C)

And when I go for Rebindable, I get "Aliases to mutable thread-local data not
allowed.".

Is there anything I can do?

Overall, I think that's another reason D needs native tail const badly.
Polymorphic classes are close to being second class citizens just as soon const
enters. :(

-- 
Tomek
Feb 06 2011
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday 06 February 2011 13:55:36 Tomek Sowi=C5=84ski wrote:
 ... doesn't work.
=20
 class C {}
 thisTid.send(new immutable(C)());
 receive((immutable C) { writeln("got it!"); });
=20
 This throws:
 core.exception.AssertError /usr/include/d/dmd/phobos/std/variant.d(285):
 immutable(C)
=20
 And when I go for Rebindable, I get "Aliases to mutable thread-local data
 not allowed.".
=20
 Is there anything I can do?
=20
 Overall, I think that's another reason D needs native tail const badly.
 Polymorphic classes are close to being second class citizens just as soon
 const enters. :(

Open a bug report on it. There are a number of bugs relating to const and=20 immutable - some of which are library-related and some of which need to be = fixed=20 in the compiler. Until many of those get sorted out, I wouldn't expect usin= g=20 immutable classes to work very well beyond some very basic cases. =2D Jonathan M Davis
Feb 06 2011
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-02-06 16:55:36 -0500, Tomek Sowiński <just ask.me> said:

 ... doesn't work.
 
 class C {}
 thisTid.send(new immutable(C)());
 receive((immutable C) { writeln("got it!"); });
 
 This throws: 
 core.exception.AssertError /usr/include/d/dmd/phobos/std/variant.d(285): 
 immutable(C)
 
 And when I go for Rebindable, I get "Aliases to mutable thread-local 
 data not allowed.".
 
 Is there anything I can do?
 
 Overall, I think that's another reason D needs native tail const badly. 
 Polymorphic classes are close to being second class citizens just as 
 soon const enters. :(

I just made this pull request today: <https://github.com/D-Programming-Language/dmd/pull/> If you want to test it, you're very welcome. Here is my development branch for this feature: <https://github.com/michelf/dmd/tree/const-object-ref> -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Feb 06 2011
next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2011-02-06 20:09:56 -0500, Michel Fortin <michel.fortin michelf.com> said:

 I just made this pull request today:
 <https://github.com/D-Programming-Language/dmd/pull/>

That should have been: <https://github.com/D-Programming-Language/dmd/pull/3> -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Feb 06 2011
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-02-07 17:11:08 -0500, Tomek Sowiński <just ask.me> said:

 Michel Fortin napisał:
 
 I just made this pull request today:
 <https://github.com/D-Programming-Language/dmd/pull/>
 
 If you want to test it, you're very welcome. Here is my development
 branch for this feature:
 <https://github.com/michelf/dmd/tree/const-object-ref>

Thanks for doing this. Is it approved by Walter?

Depends on what you mean by "approved". He commented once on the newsgroup after I posted an earlier version of the patch, saying I should add tests for type deduction and some other stuff. This change his something he attempted to do in the past and failed, I expect him to be skeptical. I guess he'll review it when he has the time and I hope he'll merge these changes in the mainline. He'll probably want to take his time however, since it can break existing code in some cases; it's basically a change to the language. If you want to show your support, I guess you can vote up the enhancement request in the bugzilla. <http://d.puremagic.com/issues/show_bug.cgi?id=5325> Also feel free to compile it, test it, and share your experience. The more tested it is, the more used and appreciated it is, the more exposure it gets, the sooner it gets approved, or so I guess. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Feb 07 2011
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2011-02-10 14:45:14 -0500, Tomek Sowiński <just ask.me> said:

 Michel Fortin napisał:
 
 Thanks for doing this. Is it approved by Walter?

Depends on what you mean by "approved". He commented once on the newsgroup after I posted an earlier version of the patch, saying I should add tests for type deduction and some other stuff. This change his something he attempted to do in the past and failed, I expect him to be skeptical.

It would be much easier if he provided the specific case(s) which broke his teeth. Then we'll all know where's the problem.

I don't think he had much time to look at the patch. His last remark were more of like "I'm skeptical it can work, please make sure you have tests to cover those specific cases..." followed with a list of things to test. I'll surely get some feedback on my patch someday, hopefully right after the next release (which should be imminent now). The architecture of the DMD front end makes it very difficult to approach the tail-const problem for classes the same way it works for pointers. If this is what Walter tried, I have no difficulty understanding why it didn't go very far. My approach was to make the optional 'ref' a modifier that changes the attributes of a new head type attached to classes. This may look a little of a hack, but it works.
 If it's soluble, it'll ope
 n the door to tail type modifiers in general, not just in classes. It's a b
 urning issue e.g. with ranges (mostly struct).
 
 http://d.puremagic.com/issues/show_bug.cgi?id=5377
 
 Look at the attachment to get a feel of what hoops we'll have to jump throu
 gh to side-step lack of tail X.

Passing 'this' by reference in struct member functions makes it pretty much impossible to support tail const. The reason it works for classes is that class member functions receive a *copy* of the 'this' object reference, in other words the constness of the original reference does not matter. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Feb 11 2011
prev sibling next sibling parent Tomek =?ISO-8859-2?B?U293afFza2k=?= <just ask.me> writes:
Michel Fortin napisa=B3:

 I just made this pull request today:
 <https://github.com/D-Programming-Language/dmd/pull/>
=20
 If you want to test it, you're very welcome. Here is my development=20
 branch for this feature:
 <https://github.com/michelf/dmd/tree/const-object-ref>

Thanks for doing this. Is it approved by Walter? --=20 Tomek
Feb 07 2011
prev sibling next sibling parent Tomek =?ISO-8859-2?Q?Sowi=F1ski?= <just ask.me> writes:
Michel Fortin napisa=B3:

 Thanks for doing this. Is it approved by Walter? =20

Depends on what you mean by "approved". =20 He commented once on the newsgroup after I posted an earlier version of=20 the patch, saying I should add tests for type deduction and some other=20 stuff. This change his something he attempted to do in the past and=20 failed, I expect him to be skeptical.

It would be much easier if he provided the specific case(s) which broke his= teeth. Then we'll all know where's the problem. If it's soluble, it'll ope= n the door to tail type modifiers in general, not just in classes. It's a b= urning issue e.g. with ranges (mostly struct). http://d.puremagic.com/issues/show_bug.cgi?id=3D5377 Look at the attachment to get a feel of what hoops we'll have to jump throu= gh to side-step lack of tail X.
 I guess he'll review it when he=20
 has the time and I hope he'll merge these changes in the mainline.=20
 He'll probably want to take his time however, since it can break=20
 existing code in some cases; it's basically a change to the language.
=20
 If you want to show your support, I guess you can vote up the=20
 enhancement request in the bugzilla.
 <http://d.puremagic.com/issues/show_bug.cgi?id=3D5325>
=20
 Also feel free to compile it, test it, and share your experience. The=20
 more tested it is, the more used and appreciated it is, the more=20
 exposure it gets, the sooner it gets approved, or so I guess.

I'd love to, but I'm putting shreds of my spare time to xml. --=20 Tomek
Feb 10 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 10 Feb 2011 14:45:14 -0500, Tomek Sowiński <just ask.me> wrote:

 Michel Fortin napisał:

 Thanks for doing this. Is it approved by Walter?

Depends on what you mean by "approved". He commented once on the newsgroup after I posted an earlier version of the patch, saying I should add tests for type deduction and some other stuff. This change his something he attempted to do in the past and failed, I expect him to be skeptical.

It would be much easier if he provided the specific case(s) which broke his teeth. Then we'll all know where's the problem. If it's soluble, it'll open the door to tail type modifiers in general, not just in classes. It's a burning issue e.g. with ranges (mostly struct). http://d.puremagic.com/issues/show_bug.cgi?id=5377 Look at the attachment to get a feel of what hoops we'll have to jump through to side-step lack of tail X.

I've worked through this very same problem (a few months back), thinking that we need a general solution to tail-const. The large issue with tail-const for structs in the general case is that you cannot control the type of 'this'. It's always ref. This might seem like a very inconsequential detail, but I realized that a ref to X does not implicitly convert to a ref to a tail-const X. This violates a rule of two indirections, in which case you are not able to implicitly convert the indirect type, even if the indirect type would implicitly convert outside the reference. A simple example, you cannot convert an int** to a const(int)**. Reason being, then you could change the indirect pointer to point to something that's immutable, and the original int ** now points to immutable data. The same is for tail-const structs, because you go through one ref via 'this' and the other ref via the referring member. What does this all mean? It basically means that you have to define *separate* functions for tail-const and const, and separate functions for tail-immutable and immutable. This is untenable. You might ask "why doesn't this problem occur with tail-const arrays?", well because you *don't pass them by ref*. With structs we have no choice. I think what we need is a way to define two different structs as being the tail-const version of the other, with some compiler help, and then we do not need to define a new flavor of const functions. We still need to define these "tail-const" functions, but it comes in a more understandable form. But importantly, the implicit cast makes a *temporary* copy of the struct, allowing the cast to work. -Steve
Feb 10 2011
prev sibling next sibling parent Tomek =?ISO-8859-2?Q?Sowi=F1ski?= <just ask.me> writes:
Steven Schveighoffer napisa=B3:

 It would be much easier if he provided the specific case(s) which broke=


 his teeth. Then we'll all know where's the problem. If it's soluble, =20
 it'll open the door to tail type modifiers in general, not just in =20
 classes. It's a burning issue e.g. with ranges (mostly struct).

 http://d.puremagic.com/issues/show_bug.cgi?id=3D5377

 Look at the attachment to get a feel of what hoops we'll have to jump =


 through to side-step lack of tail X. =20

I've worked through this very same problem (a few months back), thinking =

 that we need a general solution to tail-const.  The large issue with =20
 tail-const for structs in the general case is that you cannot control the=

 type of 'this'.  It's always ref.  This might seem like a very =20
 inconsequential detail, but I realized that a ref to X does not implicitl=

 convert to a ref to a tail-const X.  This violates a rule of two =20
 indirections, in which case you are not able to implicitly convert the =20
 indirect type, even if the indirect type would implicitly convert outside=

 the reference.

 A simple example, you cannot convert an int** to a const(int)**.  Reason =

 being, then you could change the indirect pointer to point to something =

 that's immutable, and the original int ** now points to immutable data.

I tried to understand this on an example and now I'm even more confused. :) int* p; int** pp =3D &p; const(int)** cpp =3D pp; // compiles fine immutable int i =3D 7; *cpp =3D &i; **pp =3D 5; // mutate the immutable writeln(cpp, ' ', pp); writeln(*cpp, ' ', *pp, ' ', &i); writeln(**cpp, ' ', **pp, ' ', i); The output is interesting: 12FE08 12FE08 12FE14 12FE14 12FE14 5 5 7 So even they all point to i at the end, it remains unchanged. What gives? R= egister caching? It doesn't matter as the int** to a const(int)** conversio= n should fail in the first place, but I'm curious...
 The same is for tail-const structs, because you go through one ref via =20
 'this' and the other ref via the referring member.
=20
 What does this all mean?  It basically means that you have to define =20
 *separate* functions for tail-const and const, and separate functions for=

 tail-immutable and immutable.  This is untenable.

I, from the very first discussions, assumed tail-const functions are inevit= able. You define empty() as const but popFront() as tail-const. Feels natur= al.
 You might ask "why doesn't this problem occur with tail-const arrays?", =

 well because you *don't pass them by ref*.  With structs we have no choic=

=20
 I think what we need is a way to define two different structs as being th=

 tail-const version of the other, with some compiler help, and then we do =

 not need to define a new flavor of const functions.  We still need to =20
 define these "tail-const" functions, but it comes in a more understandabl=

 form.  But importantly, the implicit cast makes a *temporary* copy of the=

 struct, allowing the cast to work.

I'd like to understand it better. How would you define with this scheme, sa= y, a range on a const collection, to which ranges on an (im)mutable collect= ion are implicitly convertible?=20 --=20 Tomek
Feb 11 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 11 Feb 2011 17:08:26 -0500, Tomek Sowiński <just ask.me> wrote:

 Steven Schveighoffer napisał:

 It would be much easier if he provided the specific case(s) which  

 his teeth. Then we'll all know where's the problem. If it's soluble,
 it'll open the door to tail type modifiers in general, not just in
 classes. It's a burning issue e.g. with ranges (mostly struct).

 http://d.puremagic.com/issues/show_bug.cgi?id=5377

 Look at the attachment to get a feel of what hoops we'll have to jump
 through to side-step lack of tail X.

I've worked through this very same problem (a few months back), thinking that we need a general solution to tail-const. The large issue with tail-const for structs in the general case is that you cannot control the type of 'this'. It's always ref. This might seem like a very inconsequential detail, but I realized that a ref to X does not implicitly convert to a ref to a tail-const X. This violates a rule of two indirections, in which case you are not able to implicitly convert the indirect type, even if the indirect type would implicitly convert outside the reference. A simple example, you cannot convert an int** to a const(int)**. Reason being, then you could change the indirect pointer to point to something that's immutable, and the original int ** now points to immutable data.

I tried to understand this on an example and now I'm even more confused. :) int* p; int** pp = &p; const(int)** cpp = pp; // compiles fine immutable int i = 7; *cpp = &i; **pp = 5; // mutate the immutable writeln(cpp, ' ', pp); writeln(*cpp, ' ', *pp, ' ', &i); writeln(**cpp, ' ', **pp, ' ', i); The output is interesting: 12FE08 12FE08 12FE14 12FE14 12FE14 5 5 7 So even they all point to i at the end, it remains unchanged. What gives? Register caching? It doesn't matter as the int** to a const(int)** conversion should fail in the first place, but I'm curious...

Most likely the compiler replaces usage of i as a value as a usage of the literal 7. Maybe change the initialization of i to something decided at runtime and it will be more as expected. This is more understandable if you use string literals which inherently must be references :) and I guess I should have said "you *shouldn't be able to* convert an int** to a const(int)**...", because obviously that isn't enforced. But it should be (your example shows why). I think there's a bugzilla on this, anyone?
 The same is for tail-const structs, because you go through one ref via
 'this' and the other ref via the referring member.

 What does this all mean?  It basically means that you have to define
 *separate* functions for tail-const and const, and separate functions  
 for
 tail-immutable and immutable.  This is untenable.

I, from the very first discussions, assumed tail-const functions are inevitable. You define empty() as const but popFront() as tail-const. Feels natural.

It seems to work for ranges, but the problem is, const instances cannot call tail-const functions. This means if there is a function that makes sense as tail-const, you still need two implementations (the const one can create a tail-const copy and call the tail-const version). Immutable is even worse, you can't call immutable functions from tail-immutable functions, and you can't call tail-immutable functions from immutable functions. This doesn't sit right when compared to arrays, where you can call tail-* functions from their fully-* equivalents. This is because they can are passed by value. I don't know, maybe it's still viable, but I think we are unlikely to convince Andrei and Walter that they are. If nothing else, having to have new const types is a definite minus.
 You might ask "why doesn't this problem occur with tail-const arrays?",
 well because you *don't pass them by ref*.  With structs we have no  
 choice.

 I think what we need is a way to define two different structs as being  
 the
 tail-const version of the other, with some compiler help, and then we do
 not need to define a new flavor of const functions.  We still need to
 define these "tail-const" functions, but it comes in a more  
 understandable
 form.  But importantly, the implicit cast makes a *temporary* copy of  
 the
 struct, allowing the cast to work.

I'd like to understand it better. How would you define with this scheme, say, a range on a const collection, to which ranges on an (im)mutable collection are implicitly convertible?

Probably with a templated range, where the template defined whether it was iterating const data or not. The trick is, you need to convince the compiler that they implicitly convert to one another. Either by assumption (which I'm not sure can be done) or explicit declaration. -Steve
Feb 14 2011