More radical ideas about gc and reference counting

Timon Gehr via Digitalmars-d digitalmars-d at puremagic.com
Wed Apr 30 15:24:28 PDT 2014


On 04/30/2014 10:57 PM, Andrei Alexandrescu wrote:
>>
>>
>> RCSlice!(const T) has nothing to do with const(RCSlice!T) as far as the
>> compiler is concerned.
> ...

There's always this hack:

struct RCSlice(T){
     static if(!is(T==const))
         RCSlice!(const(StripImmutable!T)) upcast(){
             return cast(typeof(return))this;
         }
     alias upcast this;
     // ...
}

> We need to improve the language to allow for such. Did I mention it's
> not going to be easy?

Well, actually an easy way would be to have the compiler infer safe 
coercions.

(A 'coercion' here is meant to denote a no-op implicit conversion, for 
example, conversion to const.)

It would be enabled with an attribute on the template. Coercions between 
different instantiations of the same templated type would be safe and 
allowed if the memory layout does not change between them and the 
compiler can prove the coercion safe field-wise. There needn't be 
restrictions on non-field members. Types annotated like this would get 
the top-level mutability specifier stripped off if possible, during IFTI 
/ when cast().

In particular, this would work:

class C{}
class D:C{}

@infer_coercions
struct Slice(T){
     size_t length;
     T* ptr;
}

void foo(T)(T arg){ /* ... */ }

void main()@safe{
     auto a=[new D,new D];
     auto s=Slice!D(a.length,a.ptr);
     Slice!(const(C)) sc=s; // ok, D* coercible to const(C)*
     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)*
     // (length works because const(size_t) and size_t can be
     //  freely corced between each other.)

     foo(cs); // actually calls foo!(Slice!(const(C))),

     // ==> no more magic in T[]
}

I.e. slices can be implemented in the library under this proposal.
(The above just forwards the magical behaviour of T* to a user-defined 
type.)

I think this fixes the issue in general, for example, for ranges:

const rng1 = [1,2,3].map!(a=>2*a);
const rng2 = rng1.filter!(a=>!!(a&1)); // ok



Probably this should be slightly generalized, eg:

@infer_coercions
struct S(T){
     T field;
}

void foo(T)(T arg){}

void main(){
     S!(T[]) s;
     foo(s); // foo!(S!(const(T)[]))
}

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.




More information about the Digitalmars-d mailing list