Head Const

ZombineDev via Digitalmars-d digitalmars-d at puremagic.com
Tue Feb 16 02:42:17 PST 2016


On Tuesday, 16 February 2016 at 10:09:19 UTC, Jonathan M Davis 
wrote:
> 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

I agree with everything you said. What I meant was that **in 
theory** const + thread-local can give similar guarantees as 
immutable (if the compiler can perform the necessary analysis).
That means it's more of an implementation problem than a langauge 
problem.
Given that separate compilation and .di header-only libraries are 
far more rare in D that in C++ (D has faster compilation and 
templates with attribute inference provide even more incentive), 
whole program optimization seems more easily doable in D.
After all the Rust compiler has proven that immutable borrowing 
(of a mutable object) is not hard to enforce, so I don't see a 
hard obstacle for this to be implemented in D. At least not an 
obstacle comming from the language design.


More information about the Digitalmars-d mailing list