Const template

Chris Nicholson-Sauls ibisbasenji at gmail.com
Sat Jan 20 10:53:07 PST 2007


Andrei Alexandrescu (See Website for Email) wrote:
> Chris Nicholson-Sauls wrote:
>> Just a thought: B) can be accomplished with an Interface that only 
>> exposes gettors.
> [snip]
>> <code>
>> interface IFoo {
>>   int alpha () ;
>>   int beta  () ;
>> }
>>
>> final class Foo : IFoo {
>>   private {
>>     int m_alpha ;
>>     int m_beta  ;
>>   }
>>
>>   final int alpha () { return m_alpha ; }
>>   final int beta  () { return m_beta  ; }
>>
>>   final int alpha (int x) { return m_alpha = x ; }
>>   final int beta  (int x) { return m_beta  = x ; }
>> }
>>
>> void somefunc (IFoo obj) {
>>   // do stuff with obj.alpha and obj.beta
>> }
>>
>> auto myfoo = new Foo;
>> somefunc(myfoo);
>> </code>
> 
> I think this is very interesting because it opens the door to a new
> implementation of const that I never thought of.
> 
> D is slated to have full-fledged compile-time reflection, meaning that
> you can find out all information about any given symbol, during
> compilation. So it turns out that a possible path to implement const is
> to make it a template. Given an arbitrary struct Foo, you could define a
> template called Const such that Const!(Foo) materializes into a struct
> that holds a Foo* inside, and exposes only the non-mutating parts of Foo.
> 
> So, given:
> 
> struct Foo
> {
>   int alpha, beta;
>   void nonmutator() { assert(alpha * beta != 0); }
>   void mutator() { alpha = beta; }
> }
> 
> the template Const!(Foo) generates the code:
> 
> struct Const!(Foo)
> {
>   private Foo* pFoo;
>   this(inout Foo foo) { pFoo = &foo; }
>   int alpha() { return pFoo->alpha; }
>   int beta() { return pFoo->beta; }
>   void nonmutator() { pFoo->nonmutator(); }
> }
> 
> The reflection mechanism would have to provide the information whether
> or not a given member function changes the object.
> 
> The only drawback that I can think right now is that the compiler can't
> exploit this kind of constness with ease to generate better code; it's a
> "user-space" implementation with semantics that are hard to figure out
> at the compiler level.
> 
> A minor drawback is that Const!(Foo) must be implicitly constructible
> from a Foo, but another in-design language feature (opImplicitCast) will
> take care of that.
> 
> 
> Andrei

Its not a bad idea, although with a little more flavor added to Tuples, template Const 
might become more general and therefore more usable.  Particularly if we could get an 
'identifier' construct in templates such as has been asked for before, and specializations 
that mimic what 'is' expressions can do, and a true "static foreach".  (I know, its a long 
list of wants.)

struct Const (T : struct) {
   private T* ptr ;

   static Const!(T) opCall (inout T t) { ptr = &t; }

   static foreach (field; T.tupleof) {
     typeof(field) identifier(field.nameof) () { return *ptr.field; }
   }
}

struct Foo {
   int alpha, beta;
}

Foo myfoo;
auto cfoo = Const!(Foo)(myfoo);

It loses the mapping to functions, though.  I almost have to admit a 'const' like 
parameter storage class might well be the way to go.  Either the 'byref' that has been 
mentioned previously, or a reuse of either 'static' or (*sigh*) 'const'.

-- Chris Nicholson-Sauls



More information about the Digitalmars-d mailing list