getOpt with shared

Steven Schveighoffer schveiguy at yahoo.com
Fri May 11 18:56:55 UTC 2018


On 5/11/18 2:49 PM, Jonathan M Davis wrote:
> On Friday, May 11, 2018 14:31:17 Steven Schveighoffer via Digitalmars-d-
> learn wrote:
>> On 5/11/18 1:25 PM, Danny Arends wrote:
>>> Hey all,
>>>
>>> I have been working on creating a multi-threaded application, so I have
>>> a shared configuration object which hold several command line parameters
>>> (which I fill using getopt).
>>>
>>> The problem is that I get deprecation warnings when trying to set
>>> numerical values:
>>>
>>> /usr/include/dmd/phobos/std/getopt.d(895,36): Deprecation:
>>> read-modify-write operations are not allowed for shared variables. Use
>>> core.atomic.atomicOp!"+="(*receiver, 1) instead.
>>>
>>> using getopt with a shared object and boolean values seems completely
>>> broken:
>>>
>>> /usr/include/dmd/phobos/std/getopt.d(895,34): Error: operation not
>>> allowed on bool *receiver += 1
>>> /usr/include/dmd/phobos/std/getopt.d(751,46): Error: template instance
>>> `std.getopt.handleOption!(shared(bool)*)` error instantiating
>>> /usr/include/dmd/phobos/std/getopt.d(435,15):        6 recursive
>>> instantiations from here: getoptImpl!(string, shared(string)*, string,
>>> shared(string)*, string, shared(VSync)*, string, shared(ulong)*, string,
>>> shared(bool)*, string, shared(Verbose)*)
>>>
>>> Is getopt not supposed to be used with shared structs ?
>>
>> No, just fill in a local copy, and then copy it to the shared location.
>>
>> In the case where all you want is read-only access to the data, build it
>> once and then cast to immutable:
>>
>> immutable Config config;
>>
>> void main(string[] args)
>> {
>>      Config localConfig;
>>      getopt(...); // fill in localConfig
>>      // VERY IMPORTANT, only do this ONCE, and don't use it before this
>> line *(cast()&config) = localConfig;
>> }
>>
>> It should now be accessible from all threads.
>>
>> Normally, this is not encouraged (casting away immutable), but the
>> compiler gets that an immutable global is allowed to be initialized once
>> (in fact, you can do this without casting inside shared static
>> constructors).
> 
> Except that because this is done outside of a shared static constructor,
> you're technically mutating immutable data. This _should_ work, but it is
> violating the type system, and technically, the compiler is allowed to
> assume that config is Config.init everywhere. In practice, I wouldn't expect
> a problem, but because it's violating the type system, all bets are off.

It's not a problem. The compiler cannot assume the value is .init 
because it doesn't have access to the whole codebase to see if some 
static ctor has changed it. Effectively, you ARE changing it in a static 
ctor, but just after all the other static ctors have run.

Crucially noted as well: don't use this value inside a static ctor!

-Steve


More information about the Digitalmars-d-learn mailing list