April 30, 2014
On 05/01/2014 12:24 AM, Timon Gehr wrote:
>      const(Slice!C) cs=s; // ok, D* coercible to n-m-ind const(C*)
>      sc=cs; // ok, D* is coercible to n-m-ind const(C)*

(Ignore the 'n-m-ind', those are accidental leftovers from a half-baked version of the post.)
April 30, 2014
On Wednesday, 30 April 2014 at 22:24:29 UTC, Timon Gehr wrote:
> However, then, whether to do const(S!T) => S!(const(T)) or const(S!T) => S!(TailConst!T) should maybe be specified on a per-parameter basis, because this is in general not easy to figure out for the compiler.

That is the whole problem :D
April 30, 2014
On 4/30/14, 3:08 PM, John Colvin wrote:
> On Wednesday, 30 April 2014 at 21:51:17 UTC, Andrei Alexandrescu wrote:
>> On 4/30/14, 2:47 PM, John Colvin wrote:
>>> On Wednesday, 30 April 2014 at 20:57:26 UTC, Andrei Alexandrescu wrote:
>>>>> Finally, immutable is sharable accross thread. That mean, even if we
>>>>> bypass the type system, that RC must be atomic for immutable.
>>>>> As they
>>>>> convert automatically for co,st, that mean that all const code will be
>>>>> full of atomic increment/decrement. They are bad for the CPU, and
>>>>> cannot
>>>>> be optimized away.
>>>>
>>>> Good point. I see that as a problem, albeit a solvable one.
>>>
>>> How? Having lock; instructions implicitly appearing in normal looking
>>> slice code is unacceptable.
>>
>> I'm thinking e.g. non-interlocked refcounts go like 1, 3, 5, ... and
>> interlocked refcounts go like 2, 4, 6, ...
>>
>> Then you do an unprotected read of the refcount. If it's odd, then
>> it's impossible to having originated as an interlocked one. So proceed
>> with simple increment. If it's even, do an interlocked increment.
>>
>>
>> Andrei
>
> I don't think I fully understand.
>
> Either all RC changes for a given type need to be atomic or none do, and
> that information is given by the type (everything that is
> immutable/const/shared). I don't see any feasible way of escaping this,
> or any advantage to a runtime convention like the odd/even trick above.

An object starting as shared or immutable would always need to be atomically refcounted. That information is statically known. For those we'd initialize the refcount to 2.

An object starting as regular mutable would always be refcounted non-atomically. That's also known statically. So that constructor initializes the refcount to 1.

Then a const object would dynamically choose the approach to refcounting depending on the counter's evenness.


Andrei

April 30, 2014
On Wed, Apr 30, 2014 at 02:30:05PM -0700, Andrei Alexandrescu via Digitalmars-d wrote:
> On 4/30/14, 2:15 PM, H. S. Teoh via Digitalmars-d wrote:
> >On Wed, Apr 30, 2014 at 02:13:32PM -0700, Andrei Alexandrescu via Digitalmars-d wrote:
> >>On 4/30/14, 2:09 PM, Timon Gehr wrote:
> >>>On 04/30/2014 10:58 PM, Andrei Alexandrescu wrote:
> >>>>On 4/30/14, 1:56 PM, Timon Gehr wrote:
> >>>>>
> >>>>>struct S{
> >>>>>     ~this(){ /* ... */ }
> >>>>>     /* ... */
> >>>>>}
> >>>>>
> >>>>>class C{
> >>>>>     S s;
> >>>>>}
> >>>>>
> >>>>>?
> >>>>
> >>>>By hand, as I mentioned. -- Andrei
> >>>>
> >>>
> >>>I meant, is it going to be deprecated too?
> >>
> >>No, that will continue to be allowed. -- Andrei
> >
> >Then what is it going to do? S.~this will never get called?
> 
> That is correct. -- Andrei

I don't like the sound of that. I haven't found myself in a place where I needed to do something like this, but if I had to, I'd be very unhappy if struct dtors only work when they're not class members. Can we make them always work, and if necessary prohibit using them as class members?


T

-- 
People tell me I'm stubborn, but I refuse to accept it!
April 30, 2014
On Wednesday, 30 April 2014 at 22:49:01 UTC, H. S. Teoh via Digitalmars-d wrote:
> On Wed, Apr 30, 2014 at 02:30:05PM -0700, Andrei Alexandrescu via Digitalmars-d wrote:
>> On 4/30/14, 2:15 PM, H. S. Teoh via Digitalmars-d wrote:
>> >On Wed, Apr 30, 2014 at 02:13:32PM -0700, Andrei Alexandrescu via Digitalmars-d wrote:
>> >>On 4/30/14, 2:09 PM, Timon Gehr wrote:
>> >>>On 04/30/2014 10:58 PM, Andrei Alexandrescu wrote:
>> >>>>On 4/30/14, 1:56 PM, Timon Gehr wrote:
>> >>>>>
>> >>>>>struct S{
>> >>>>>     ~this(){ /* ... */ }
>> >>>>>     /* ... */
>> >>>>>}
>> >>>>>
>> >>>>>class C{
>> >>>>>     S s;
>> >>>>>}
>> >>>>>
>> >>>>>?
>> >>>>
>> >>>>By hand, as I mentioned. -- Andrei
>> >>>>
>> >>>
>> >>>I meant, is it going to be deprecated too?
>> >>
>> >>No, that will continue to be allowed. -- Andrei
>> >
>> >Then what is it going to do? S.~this will never get called?
>> 
>> That is correct. -- Andrei
>
> I don't like the sound of that. I haven't found myself in a place where
> I needed to do something like this, but if I had to, I'd be very unhappy
> if struct dtors only work when they're not class members. Can we make
> them always work, and if necessary prohibit using them as class members?
>
>
> T

Can't do nothing but agree. Unless I'm missing something, no destructors means memory leaks every time I use non-class objects inside a class object. At least current behaviour makes sure that when memory is needed, everything gets cleaned up properly. Honestly, this sounds crazy to me.
April 30, 2014
On 4/30/14, 3:32 PM, deadalnix wrote:
> On Wednesday, 30 April 2014 at 22:08:23 UTC, John Colvin wrote:
>> I don't think I fully understand.
>>
>> Either all RC changes for a given type need to be atomic or none do,
>> and that information is given by the type (everything that is
>> immutable/const/shared). I don't see any feasible way of escaping
>> this, or any advantage to a runtime convention like the odd/even trick
>> above.
>
> If you CPU is decent you have some cache coherency protocol in place.
> This won't ensure that thing appears sequentially consistent, but you
> don't care here.
>
> You can proceed as follow in pseudo assembly :
>
> count = load count_addr
> need_atomic = count & 0x01
> brtr atomic
> count = count + 2
> store count count_addr
> br follow_up
>
> atomic:
> atomic_add count_addr 2
>
> follow_up:
> // Code after increment goes here

brtr_atomic won't be needed on x86.

> Note that is working as count may not be the correct number in case of
> sharing, but will always have the same parity, so even reading the wrong
> value will make you branch properly and the value of count is not used
> to increment in the atomic block.
>
> I'm not happy with this solution, because:
>   - You still have an atomic in there, and the compiler can't remove it.
> This reduce greatly the capability of the compiler to optimize. For
> instance, the compiler cannot optimize away redundant pairs of
> increment/decrement.

Only on const slices, architectures more relaxed than x86, and objects with destructors.

> That odd/even solution surely works, but ultimately do not solve the
> issue: if you want full speed, you'll have to provide both a const and a
> mutable version of the code, which defeat the purpose of const. Note
> that the exact same issue exists with inout.

I don't think it's all doom and gloom. Defining a destructor for an object suggests that the object is willing and able to give up a little speed for the sake of automation. I think it all dovetails nicely.


Andrei

April 30, 2014
On 4/30/14, 3:47 PM, H. S. Teoh via Digitalmars-d wrote:
> On Wed, Apr 30, 2014 at 02:30:05PM -0700, Andrei Alexandrescu via Digitalmars-d wrote:
>> On 4/30/14, 2:15 PM, H. S. Teoh via Digitalmars-d wrote:
>>> On Wed, Apr 30, 2014 at 02:13:32PM -0700, Andrei Alexandrescu via Digitalmars-d wrote:
>>>> On 4/30/14, 2:09 PM, Timon Gehr wrote:
>>>>> On 04/30/2014 10:58 PM, Andrei Alexandrescu wrote:
>>>>>> On 4/30/14, 1:56 PM, Timon Gehr wrote:
>>>>>>>
>>>>>>> struct S{
>>>>>>>      ~this(){ /* ... */ }
>>>>>>>      /* ... */
>>>>>>> }
>>>>>>>
>>>>>>> class C{
>>>>>>>      S s;
>>>>>>> }
>>>>>>>
>>>>>>> ?
>>>>>>
>>>>>> By hand, as I mentioned. -- Andrei
>>>>>>
>>>>>
>>>>> I meant, is it going to be deprecated too?
>>>>
>>>> No, that will continue to be allowed. -- Andrei
>>>
>>> Then what is it going to do? S.~this will never get called?
>>
>> That is correct. -- Andrei
>
> I don't like the sound of that. I haven't found myself in a place where
> I needed to do something like this, but if I had to, I'd be very unhappy
> if struct dtors only work when they're not class members. Can we make
> them always work, and if necessary prohibit using them as class members?

Then we're back to effectively class destructors. I think we've gathered quite a bit of evidence there are pernicious issues associated with them. -- Andrei


April 30, 2014
On 4/30/14, 3:54 PM, fra wrote:
> Can't do nothing but agree. Unless I'm missing something, no destructors
> means memory leaks every time I use non-class objects inside a class
> object.

If said non-class objects have destructors and are not cleaned up via other mechanisms.

> At least current behaviour makes sure that when memory is
> needed, everything gets cleaned up properly.

I think this was a false sense of security. There's no "making sure". Due to imprecision a destructor may or may not be called. Also, arrays of structs _never_ call destructors for their elements, which should shock you quite a bit more.

> Honestly, this sounds crazy
> to me.

s/crazy/radical/

Yes, radical. Because we want to uproot some bad weeds here.


Andrei
April 30, 2014
On 4/30/14, 3:54 PM, Andrei Alexandrescu wrote:
> On 4/30/14, 3:32 PM, deadalnix wrote:
>> On Wednesday, 30 April 2014 at 22:08:23 UTC, John Colvin wrote:
>>> I don't think I fully understand.
>>>
>>> Either all RC changes for a given type need to be atomic or none do,
>>> and that information is given by the type (everything that is
>>> immutable/const/shared). I don't see any feasible way of escaping
>>> this, or any advantage to a runtime convention like the odd/even trick
>>> above.
>>
>> If you CPU is decent you have some cache coherency protocol in place.
>> This won't ensure that thing appears sequentially consistent, but you
>> don't care here.
>>
>> You can proceed as follow in pseudo assembly :
>>
>> count = load count_addr
>> need_atomic = count & 0x01
>> brtr atomic
>> count = count + 2
>> store count count_addr
>> br follow_up
>>
>> atomic:
>> atomic_add count_addr 2
>>
>> follow_up:
>> // Code after increment goes here
>
> brtr_atomic won't be needed on x86.

Sorry, I misread your code. I meant to say on x86 there's no need to do any handshake on the single-threaded case. -- Andrei

April 30, 2014
On Wednesday, 30 April 2014 at 23:05:29 UTC, Andrei Alexandrescu wrote:
> Sorry, I misread your code. I meant to say on x86 there's no need to do any handshake on the single-threaded case. -- Andrei

You don't need it on most arch. Except alpha, I don't know any that would require it.