May 28, 2016 Re: is my code to get CTFE instantiated object valid D ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | On Saturday, 28 May 2016 at 08:47:48 UTC, Kagamin wrote: > For a trick of static mutable allocation see https://github.com/dlang/druntime/pull/1325 In the following instruction of the above commit, what effect has the [] after init ? _store[0 .. __traits(classInstanceSize, T)] = typeid(T).init[]; T is a template argument that is a class derived from Error. I couldn't find an explanation here https://dlang.org/spec/property.html#init. I saw that this is a concise implementation of what is being done in emplace(). |
May 28, 2016 Re: is my code to get CTFE instantiated object valid D ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to chmike | On 05/28/2016 06:09 PM, chmike wrote: > In the following instruction of the above commit, what effect has the [] > after init ? > > _store[0 .. __traits(classInstanceSize, T)] = typeid(T).init[]; > > T is a template argument that is a class derived from Error. > > I couldn't find an explanation here > https://dlang.org/spec/property.html#init. > > I saw that this is a concise implementation of what is being done in > emplace(). `typeid(T).init` is a different `init` than the one you linked. We have since renamed it to `initializer` to fix the name clash. Documentation is here: http://dlang.org/phobos/object.html#.TypeInfo.initializer As you can see there, it's a `const(void)[]`. The statement is a form of "array copying": http://dlang.org/spec/arrays.html#array-copying As you can see there, it would also work without the `[]`. With them it's a bit clearer that array copying is going on, and not "array setting" (next section on the spec page). |
May 28, 2016 Re: is my code to get CTFE instantiated object valid D ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to chmike | On Friday, 27 May 2016 at 20:20:36 UTC, chmike wrote:
> I need to create an app wide singleton instance for my class.
> The singleton is immutable, but I want to allow mutable references to that singleton object so that I can do fast 'is' tests.
>
> I declared this
>
> class Category
> {
> protected static immutable Category instance_ = new Category;
> Category instance() { return cast(Category)instance_; }
> ...
> }
>
> It compiles and the instance should be instantiated at compile time. I couldn't check yet.
>
> The public interface of Category is designed so that the object's state can't be modified and thus remains immutable.
>
> Is this code valid D or is the behavior undefined due to the cast ?
>
>
> A variant implementation would have a method that modifies the object but only internally and in a very controlled way to store strings in a cache for faster access. Would it still be valid D code ?
I answer to myself on this question because I finally found out.
Creating an app wide singleton object is as simple as this
class Category
{
this() { assert __ctfe); } // Just to make sure
private __gshared instance_ = new Info;
static Category instance() { return _instance; }
}
It works as long as the constructor doesn't reference other global or static variables.
Unfortunately this is what I have in my use case. I had this
final class Info
{
Info(Category category, string name)
{
category_ = category;
name_ = name;
assert(__ctfe);
}
private string name_;
private Category category_;
string name() { return name_; }
Category category() { return category_; }
}
This class can't be instantiated as compile time because the constructor depends on the global variable Category.instance_.
Category {
...
__gshared Info a1 = new Info(Category.instance(), "I'm a1");
__gshared Info a2 = new Info(Category.instance(), "I'm a2");
...
}
The problem is solved by changing Category into an immutable class and instance. It's Ok in my case because it is immutable. The only inconvenience left is that we can't have mutable references to immutable objects.
But at least now I can write
Info x1 = Cateqory.a1, x2 = Category.a2;
Info x3 = x1, x4;
assert(x3 is x1);
assert(x3 !is x2);
assert(x1.category is x2.category);
assert(x4 is null);
And of course we can also access all the properties of the Info values. Objects are identified by their unique address.
Another problem left is that synchronization
|
May 28, 2016 Re: is my code to get CTFE instantiated object valid D ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to chmike | On 05/28/2016 09:54 PM, chmike wrote:
> The only inconvenience left is that we can't have mutable references
> to immutable objects.
There is std.typecons.Rebindable for that.
|
May 29, 2016 Re: is my code to get CTFE instantiated object valid D ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to ag0aep6g | On Saturday, 28 May 2016 at 15:39:44 UTC, ag0aep6g wrote: > On 05/28/2016 10:34 AM, Mike Parker wrote: >> On Saturday, 28 May 2016 at 05:30:26 UTC, chmike wrote: > [...] >>> Is a static const Category c variable a TLS variable ? >> >> Yes. All variables are TLS unless explicitly marked with __gshared or >> shared. > > I don't think that's true. > Prints (for example): > ---- > 7F554F9E1710 695FF0 695FF4 > 7F554EDDA5D0 695FF0 695FF4 > ---- > > So there are two different `m`s, but the `c`s and `i`s have the same address on both threads. Seems to me that `m` is in TLS, but `c` and `i` are not. Well then, this completely breaks my understanding of variable scope. Consider this: ------ class Foo { int x; this(int i) { x = i; } } class Bar { static const Foo f; static this() { __gshared static firstRun = true; f = new Foo(firstRun ? 10 : 20); firstRun = false; import std.stdio; writeln("static con"); } } void main() { import core.thread; print(); new Thread(&print).start(); Thread.sleep(1.seconds); print(); } void print() { import std.stdio; writefln("Bar.f.x = %s, &Bar.f = %s", Bar.f.x, &Bar.f); } ---- The static constructor is run per thread. The second iteration reinitializes the const reference 'f' with a new instance. Not at all what I would expect. IMO, either its a bug that there is only one instance of 'f', or it's a bug that it can be reinitialized. |
May 29, 2016 Re: is my code to get CTFE instantiated object valid D ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Parker | On Sunday, 29 May 2016 at 05:35:33 UTC, Mike Parker wrote: > Well then, this completely breaks my understanding of variable scope. OK, I see now at [1] the following: " Immutable data doesn't have synchronization problems, so the compiler doesn't place it in TLS." I've read that page more than once, but I had forgotten this bit. Still, I don't see anything there about const. I would not expect const variables to behave the same way, given the weaker guarantee about modification. But if they are intended to behave that way, then, IMO, it should not be possible to reinitialize them in a static constructor. https://dlang.org/migrate-to-shared.html |
May 29, 2016 Re: is my code to get CTFE instantiated object valid D ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to ag0aep6g | On Saturday, 28 May 2016 at 21:21:34 UTC, ag0aep6g wrote:
> On 05/28/2016 09:54 PM, chmike wrote:
>> The only inconvenience left is that we can't have mutable references
>> to immutable objects.
>
> There is std.typecons.Rebindable for that.
That would be a good news. What is the right way to use it ? I had a hard time to understand how to use Rebindable.
Rebindable!(immutable Category) instance( return Rebindable!(immutable Category)(instance_); }
Or should, I do it like that ?
Rebindable!(const Category) instance( return Rebindable!(const Category)(instance_); }
The immutable and const concepts are really different from C and C++.
A problem with rebindable is that its current assembly translation for 'is' test does a byte per byte comparison which is much less efficient than a direct 64bit comparison of the struct.
I checked that with dmd. I don't know about gdc and ldc. This is something that will,be optimized soon I hope.
|
May 29, 2016 Re: is my code to get CTFE instantiated object valid D ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to chmike | On Sunday, 29 May 2016 at 06:49:42 UTC, chmike wrote:
> What is the right way to use it ?
I answer to my self after testing so that people looking for that info can find it here.
The right way would be
immutable Category category_;
Rebindable!(immutable Category) instance() { return rebindable(category_); }
it is equivalent and shorter (for the lazy) to write
auto instance() { return rebindable(category_); }
The disadvantage of this form is that the reader of documentation generated automatically from the source file will only see this : auto instance()
and he won't know what this instance method effectively returns.
If we want a mutable reference that accept mutable and immutable Category objects, we should define this
Rebindable!(const Category) x = Category.instance();
x = new Category;
The concept of immutable and constness of D was the most difficult thing to learn because it is radically different from the const concept of C and C++. Now that I understood it and stopped getting hit with immutability and constness compiler errors, I start to like it.
So the only problem I see with Rebindable is the inefficiency of reference comparison in the generated assembly code with DMD64 D Compiler v2.071.0.
This will hopefully get fixed in next versions.
Thank you very much to everybody who took the time to help me learn D and answer my so many questions.
|
May 29, 2016 Re: is my code to get CTFE instantiated object valid D ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Parker | On Sunday, 29 May 2016 at 05:43:31 UTC, Mike Parker wrote:
> On Sunday, 29 May 2016 at 05:35:33 UTC, Mike Parker wrote:
>
>> Well then, this completely breaks my understanding of variable scope.
>
> OK, I see now at [1] the following:
>
> " Immutable data doesn't have synchronization problems, so the compiler doesn't place it in TLS."
>
> I've read that page more than once, but I had forgotten this bit. Still, I don't see anything there about const. I would not expect const variables to behave the same way, given the weaker guarantee about modification. But if they are intended to behave that way, then, IMO, it should not be possible to reinitialize them in a static constructor.
>
> https://dlang.org/migrate-to-shared.html
It's reasonable to treat const variables like immutable when the const variable has no indirections. However, it shouldn't allow rewriting the variable in each thread ctor.
-Steve
|
Copyright © 1999-2021 by the D Language Foundation