Jump to page: 1 2
Thread overview
Member access of __gshared global object
Jul 31, 2014
Puming
Jul 31, 2014
Daniel Kozak
Jul 31, 2014
Marc Schütz
Aug 06, 2014
Puming
Aug 06, 2014
Marc Schütz
Aug 06, 2014
hane
Aug 06, 2014
Dragos Carp
Aug 06, 2014
Marc Schütz
Aug 06, 2014
Dragos Carp
Aug 06, 2014
Marc Schütz
Aug 06, 2014
Dragos Carp
Aug 07, 2014
Puming
Aug 07, 2014
H. S. Teoh
Aug 07, 2014
Puming
Aug 07, 2014
Kagamin
Aug 07, 2014
Puming
July 31, 2014
Hi,

I'm writing this global Config class, with an AA member:

```d
module my.config;

class Config
{
    Command[string] commands;
}

__gshared Config CONFIG;
```

and initialize it in another module:

```d
module my.app;

import my.config;

void main()
{
  CONFIG = new Config();
  CONFIG.commands["bye"] = new Command(...); // add commands
}
```

This is OK. But when I use a local variable to hold the commands AA:

```
auto cmds = CONFIG.commands;
cmds["list"] = new Command(...);
```

The command "list" is not added.

I guess what happened here was that `cmds` is a threadlocal variable, so the compiler somehow copied the CONFIG.commands.

My questions are:

1. Are AAs reference type? if so, why does the compiler copy it?
2. How do I reference a member of __gshared global objects?
July 31, 2014
V Thu, 31 Jul 2014 02:03:35 +0000
Puming via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com>
napsáno:

> Hi,
> 
> I'm writing this global Config class, with an AA member:
> 
> ```d
> module my.config;
> 
> class Config
> {
>      Command[string] commands;
> }
> 
> __gshared Config CONFIG;
> ```
> 
> and initialize it in another module:
> 
> ```d
> module my.app;
> 
> import my.config;
> 
> void main()
> {
>    CONFIG = new Config();
>    CONFIG.commands["bye"] = new Command(...); // add commands
> }
> ```
> 
> This is OK. But when I use a local variable to hold the commands AA:
> 
> ```
> auto cmds = CONFIG.commands;
> cmds["list"] = new Command(...);
> ```
> 
> The command "list" is not added.
> 
> I guess what happened here was that `cmds` is a threadlocal variable, so the compiler somehow copied the CONFIG.commands.
> 
> My questions are:
> 
> 1. Are AAs reference type? if so, why does the compiler copy it? 2. How do I reference a member of __gshared global objects?

can you post code somewhere? I try it and it works for me.

module main;

import std.stdio;
import config;

void main(string[] args)
{
	CONFIG = new Config();
	CONFIG.commands["bye"] = "yep";

	auto cmds = CONFIG.commands;
	cmds["list"] = "smt";

	writeln(CONFIG.commands);
	// Lets the user press <Return> before program returns
	stdin.readln();
}

module config;

class Config
{
	string[string] commands;
	this()
	{
		// Constructor code
	}
}

__gshared Config CONFIG;


July 31, 2014
On Thursday, 31 July 2014 at 02:03:37 UTC, Puming wrote:
> 1. Are AAs reference type? if so, why does the compiler copy it?

This is probably your problem. They are reference types, but initially that reference is `null`. When you write:

    auto cmds = CONFIG.commands;

`cmds` contains a copy of the `null` value. On assignment, the actual AA is created, and assigned to `cmds`, but not back to `CONFIG.commands`. Try initializing the AA in your class constructor.
August 06, 2014
On Thursday, 31 July 2014 at 10:22:28 UTC, Marc Schütz wrote:
> On Thursday, 31 July 2014 at 02:03:37 UTC, Puming wrote:
>> 1. Are AAs reference type? if so, why does the compiler copy it?
>
> This is probably your problem. They are reference types, but initially that reference is `null`. When you write:
>
>     auto cmds = CONFIG.commands;
>
> `cmds` contains a copy of the `null` value. On assignment, the actual AA is created, and assigned to `cmds`, but not back to `CONFIG.commands`. Try initializing the AA in your class constructor.

I checked the code and could concur your suggestion.

What I found strange were:

1. The only way that I can initialize it is to assign a value. But I want to initialize an empty AA, is that possible?

2. CONFIG.commands is not `null` before initialized, it is '[]'(when I writeln it). But it still behave like what you described (except that it won't produce an NullPointer Exception.

August 06, 2014
On Wednesday, 6 August 2014 at 04:14:51 UTC, Puming wrote:
> On Thursday, 31 July 2014 at 10:22:28 UTC, Marc Schütz wrote:
>> On Thursday, 31 July 2014 at 02:03:37 UTC, Puming wrote:
>>> 1. Are AAs reference type? if so, why does the compiler copy it?
>>
>> This is probably your problem. They are reference types, but initially that reference is `null`. When you write:
>>
>>    auto cmds = CONFIG.commands;
>>
>> `cmds` contains a copy of the `null` value. On assignment, the actual AA is created, and assigned to `cmds`, but not back to `CONFIG.commands`. Try initializing the AA in your class constructor.
>
> I checked the code and could concur your suggestion.
>
> What I found strange were:
>
> 1. The only way that I can initialize it is to assign a value. But I want to initialize an empty AA, is that possible?

I don't know whether there is a way currently. The obvious `CONFIG.commands = []` produces an error: "can't have associative array key of void". This is likely a restriction of the current implementation of AAs, which is known to be suboptimal and being reworked slowly.

>
> 2. CONFIG.commands is not `null` before initialized, it is '[]'(when I writeln it).

That's just how writeln prints empty AAs. Try `writeln(cmds is null)`, it will print "true".

> But it still behave like what you described (except that it won't produce an NullPointer Exception.

Because the runtime checks whether they are null, and allocates memory if necessary.
August 06, 2014
On Wednesday, 6 August 2014 at 04:14:51 UTC, Puming wrote:
> 1. The only way that I can initialize it is to assign a value. But I want to initialize an empty AA, is that possible?

workaround:

string[string] aa;
assert(aa is null);

aa[""] = "";
aa.remove("");
assert(aa !is null);
August 06, 2014
>
> 1. The only way that I can initialize it is to assign a value. But I want to initialize an empty AA, is that possible?

Like arrays, associative arrays have value semantics. This means that they can be always referenced.

It is easier to see this with an array:

int[] a1 = null;
writeln(a1.ptr);
writeln(a1.length);

will print "null" and 0;

The array is in fact a pair: ptr and length. The pair is allocated like any other primitive or struct and thus cannot be null.

This means if you want an empty AA you can write

aa1 = null;

or more explicit

aa1 = typeof(aa1).init;

>
> 2. CONFIG.commands is not `null` before initialized, it is '[]'(when I writeln it). But it still behave like what you described (except that it won't produce an NullPointer Exception.

See 1.
August 06, 2014
On Wednesday, 6 August 2014 at 14:22:32 UTC, Dragos Carp wrote:
>>
>> 1. The only way that I can initialize it is to assign a value. But I want to initialize an empty AA, is that possible?
>
> --snip--
>
> This means if you want an empty AA you can write
>
> aa1 = null;
>
> or more explicit
>
> aa1 = typeof(aa1).init;

This would defeat the purpose, see the original post.
August 06, 2014
On Wednesday, 6 August 2014 at 14:36:23 UTC, Marc Schütz wrote:
>
> This would defeat the purpose, see the original post.

sorry, I red just the last post.

__gshared has no influence on this.

> auto cmds = CONFIG.commands;
> cmds["list"] = new Command(...);

cmds is a thread local variable referencing the shared AA. But if you add new elements to cmds, cmd will be reallocated and the shared AA will remain unchanged. Though, updated values of existing keys will be visible in the original, because no relocation takes place.

If you want to change the original you need a pointer or a reference (for a setter function).

auto cmds = &CONFIG.commands;
(*cmds)["list"] = new Command(...);
August 06, 2014
On Wednesday, 6 August 2014 at 15:18:15 UTC, Dragos Carp wrote:
> On Wednesday, 6 August 2014 at 14:36:23 UTC, Marc Schütz wrote:
>>
>> This would defeat the purpose, see the original post.
>
> sorry, I red just the last post.
>
> __gshared has no influence on this.

Indeed, it was just what the OP suspected as the culprit.

>
>> auto cmds = CONFIG.commands;
>> cmds["list"] = new Command(...);
>
> cmds is a thread local variable referencing the shared AA. But if you add new elements to cmds, cmd will be reallocated and the shared AA will remain unchanged. Though, updated values of existing keys will be visible in the original, because no relocation takes place.

This describes the semantics of regular arrays. Are you sure it also applies to AAs? I thought they will keep referring to the same data once they are initialized. But I might be mistaken...

>
> If you want to change the original you need a pointer or a reference (for a setter function).
>
> auto cmds = &CONFIG.commands;
> (*cmds)["list"] = new Command(...);

« First   ‹ Prev
1 2