pass-by-ref semantics for structs (was Deque impl.)

Dmitry Olshansky dmitry.olsh at gmail.com
Thu Jan 31 12:06:19 PST 2013


31-Jan-2013 23:54, Robert burner Schadek пишет:
>
> On 01/31/2013 08:34 PM, Dmitry Olshansky wrote:
>> 31-Jan-2013 23:32, Maxim Fomin пишет:
>>> On Thursday, 31 January 2013 at 19:17:56 UTC, Dmitry Olshansky wrote:
>>>> 31-Jan-2013 19:21, Andrei Alexandrescu пишет:
>>>>> On 1/31/13 10:18 AM, Steven Schveighoffer wrote:
>>>>>> On Thu, 31 Jan 2013 10:12:53 -0500, Andrei Alexandrescu
>>>>>>> As far as I can tell classes have the same problem.
>>>>>>
>>>>>> Nope.
>>>>>>
>>>>>> void foo(someclass aa, int x, int y)
>>>>>> {
>>>>>> aa[x] = y;
>>>>>> }
>>>>>>
>>>>>> void main()
>>>>>> {
>>>>>> someclass aa;
>>>>>> foo(aa, 1, 2); // segfault
>>>>>> ...
>>>>>> }
>>>>>
>>>>> We could easily arrange things to segfault just the same with a
>>>>> struct-based implementation.
>>>>>
>>>>
>>>> Structs are quite borked in this regard e.g. without extra efforts the
>>>> following:
>>>>
>>>> somclass aa = someclass();
>>>> foor(aa, 1, 2); // segfault, surprize someclass() is someclass.init
>>>>
>>>> The current workaround I find the most sensible is:
>>>> - @disable this();
>>>> - make all constructors private
>>>> - define opCall and forward it to private constructors. 0-arg versions
>>>> have to pass dummy and/or default values to get struct constructed
>>>>
>>>> - automate this boilerplate until something in language is fixed? :)
>>>>
>>>> The advantage is that the following is illegal:
>>>> someclass aa;
>>>>
>>>> and the following works as expected:
>>>> auto aa = someclass(); //create empty container damn it!
>>>
>>> If desired default struct value is constant for all instances of that
>>> struct, there is another workaround by changing init values:
>>> -------------------
>>> import std.stdio;
>>>
>>> class A { int x = 5; }
>>>
>>> struct S { int x = 5; A a; }
>>>
>>> void main()
>>> {
>>>      S s; // defaults to preallocated a, a is not null
>>>      assert(S.x is 100 && s.a !is null && s.a.x is 100);
>>> }
>>
>> This is fine except that it doesn't solve the problem of:
>> Container a = Container(); //should be empty container, not illegal
>> null-container
> Just use a payload struct and check whether that is null before every
> operation.

Lazy evaluation, great. Except that is a useless opcode per every 
operation with container + keep in in mind the problem:

void func(cont a)
{
	//if a was empty and we go with lazy-initialization
	// then the outside cont is not updated
	a.insert(...);
}

void main()
{
	...
	cont x;
	...
	//this could be non-trivial code that
	//may or may not touch x in all path
	func(x);
	...
}


-- 
Dmitry Olshansky


More information about the Digitalmars-d mailing list