Auto-invariance (WAS: const )
Sean Kelly
sean at invisibleduck.org
Tue Apr 1 09:06:27 PDT 2008
== Quote from Sean Kelly (sean at invisibleduck.org)'s article
> == Quote from Benji Smith (benji at benjismith.net)'s article
> > Sean Kelly wrote:
> > > I think the need for const vs. invariant in D 2.0 is that the compiler isn't
> > > smart enough to know when the referenced data should actually never
> > > change, and because a bunch of interesting optimizations are available
> > > when the data really doesn't ever change, we have a keyword to hint to
> > > the compiler that this is true.
> > If the compiler can't actually detect mutation of const values, then how
> > will it enforce const correctness? Is the 'const' keyword just a fancy
> > compiler-enforced form of documentation?
> The compiler can locally, but what if it doesn't have access to the entire
> program source when compiling a module? For example, let's say I create
> a library function like so:
> void doSomething( const(char)[] buf, void delegate() dg )
> {
> writefln( buf ); // A
> dg();
> writefln( buf ); // B
> }
> If the compiler knows that the data referenced by buf will not change for
> the entire length of the call to doSomething() then it can cache information
> about buf in registers, etc. However, doSomething() contains an opaque
> call to external code, which could in theory modify the contents of buf.
> Consider:
> char[] inp = "hello world";
> doSomething( inp, () { inp[0] = 'j'; } );
> So because there is an opaque call inside doSomething(), the compiler must
> assume that the contents of buf may change across that call, and therefore
> may only assume that buf is invariant from the beginning of doSomething()
> up to the call to dg(), then from the call of dg() to the end of doSomething().
> What I don't like about 'invariant' is that while the label is in the correct or
> at least the easiest place for the compiler, its location means code duplication
> for the programmer if she wants to have her function work for both constant
> and non-constant data. This is fine for passing shared data between threads:
> class MyClass
> {
> private string m_s;
> void setString( string s ) { m_s = s; }
> void setString( char[] s ) { m_s = s.idup; }
> }
> as it avoids the need to perform a copy, or more generally, to acquire a mutex.
> However, I think the far more common case will be that library programmers
> will want to create algorithms that work on any kind of string and have the
> compiler simply optimize the code ideally for each situation:
> size_t find(T)( in T[] buf, T pat )
> {
> foreach( i, e; buf )
> if( e == pat )
> return i;
> return buf.length;
> }
> Here, the need to create separate, identical implementations for the same
> algorithm that vary only by the constancy of buf simply so the compiler can
> optimize differently for each aspect is horrible. I would much rather have
> the compiler invisibly generate the different permutations for me and do
> something fancy with the name mangling to sort out all out invisibly. So:
> "abc".find( 'b' ); // calls the "invariant(char)[]" permutation
> char[] buf; buf.find( 'b' ); // calls the "const(char)[]" permutation
> Of course, this means that the compiler will silently be generating more
> code but so what? A decent linker could throw out the unused routines
> anyway. I haven't given this idea much thought, but on the surface it seems
> like it could do away with the need for 'invariant' almost entirely.
> Sean
No one liked this idea, huh? :-) One thought for reducing the number of
permutations was to only permute on "in" parameters. Explicitly specified
"const" or "invariant" parameters are left as-is. Another possible reduction
would be to only do this for template functions, though this would be
somewhat of an odd special case.
Sean
More information about the Digitalmars-d
mailing list