Head Const
Jonathan M Davis via Digitalmars-d
digitalmars-d at puremagic.com
Tue Feb 16 02:09:19 PST 2016
On Tuesday, 16 February 2016 at 09:45:34 UTC, ZombineDev wrote:
> On Tuesday, 16 February 2016 at 08:03:31 UTC, Jonathan M Davis
> wrote:
>> ...
>> Given that very few optimizations can be made based solely on
>> const (and I'm not sure that the compiler currently does any
>> of them) ...
>
> I think that the fact that we have shared can help a lot in the
> area of optimization.
> Taking a non-shared const parameter should be as good as taking
> an immutable one (if the function pure-like - only does
> computation based on the parameter and doesn't escape it).
> Or am I missing something?
The fact that variables are thread-local by default in D
definitely helps, but it's still far from sufficient. If you have
auto result = func(foo);
where foo is const, for the compiler to know that foo was not
mutated by the call to func, it has to know that there's no way
that func could have accessed a mutable reference to the object
that foo refers to. The fact that we have shared means that it
doesn't have to worry about other, arbitrary code mutating foo
while func is called, but it still has to be able to determine
that neither func no anything that it accesses is able to mutate
foo.
If func is pure, that gets us a good chunk of the way, because
then the only way that func can access a mutable reference to foo
is via its arguments. If it's just foo, then - unless I'm missing
something - that should be enough, since foo would not be able to
access a mutable reference to itself except via a non-pure
function, which wouldn't be callable from func if it's pure. But
if func is a member function, or if it took addition, mutable
arguments, e.g.
auto result = func(foo, bar);
then the compiler has to know that func can't access a mutable
foo via the other arguments - and if they're not const, that's
hard to do.
In general, I think that the compiler pretty much has to be able
to see where foo was created and that no mutable references _can_
exist that func would have access to. e.g.
const foo = new Foo(42);
auto result = func(foo, bar);
or
auto mutableFoo = new Foo(42);
const foo = mutableFoo;
auto result = func(foo, bar);
would be enough. But without a lot of code flow analysis, it
doesn't take much for it to be too much for the compiler to
figure out, and unless it has access to the bodies of the
functions that are being called and does deep inspection of what
they do and call, simply calling a function (especially a
non-pure one) very quickly makes it so that the compiler doesn't
know enough to guarantee that func can't possibly access foo via
a mutable reference to the same data. e.g. in
auto mutableFoo = new Foo(42);
auto result1 = otherFunc(mutableFoo, bar);
const foo = mutableFoo;
auto result2 = func(foo, bar);
otherFunc might have given bar access to mutableFoo which it then
accessed inside of func.
So, yes, the combination of non-shared, pure, and const does
allow for some optimizations, but it really doesn't take much to
make it so that the compiler can't guarantee that const object
hasn't been changed by a function call without it doing a lot of
deep analysis that compilers just don't normally do.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list