Interested in D, spec confuses me.
Bambi via Digitalmars-d
digitalmars-d at puremagic.com
Wed Feb 3 03:38:06 PST 2016
On Tuesday, 2 February 2016 at 23:41:07 UTC, H. S. Teoh wrote:
> You're misunderstanding D's type system. Immutable is not a
> "better const", as though const is somehow defective. Perhaps
> the following diagram may help to clear things up:
>
> const
> / \
> (mutable) immutable
>
> What this means is that both mutable and immutable are
> implicitly convertible to const. Or, to put it another way,
> const is a kind of "wildcard" that can point to underlying data
> that's either mutable or immutable.
>
> Mutable data is, well, mutable -- anybody who can get to it,
> can modify it. Immutable means *nobody* can modify it once it's
> initialized.
>
> Why const, then? Const is useful for when a function doesn't
> care whether the underlying data is mutable or not, because it
> doesn't need to change the data. Const provides guarantees to
> the caller that the function won't touch the data -- even if
> the data is actually mutable in the caller's context. It's a
> "no-mutation view" on data that's possibly mutable by a third
> party.
>
> Furthermore, since const provides actual guarantees that the
> called function isn't going to touch the data, this opens up
> optimization opportunities for the compiler. E.g., it can
> assume that any part(s) of the data that are held in registers
> will remain valid after the function call (provided said
> registers aren't touched by the function), so it doesn't need
> to issue another load after the function returns. As a
> contrived example, say you have code like this:
>
> struct Data { int x; }
> int func1(Data* d) { ... }
> int func2(const(Data)* d) { ... }
> ...
> void main() {
> Data d;
> int value1 = d.x*func1(&d) + d.x;
> int value2 = d.x*func2(&d) + d.x;
> d.x++;
> }
>
> When evaluating value1, the compiler may have issued a load for
> the first occurrence of d.x, then it calls func1. But since
> func1 may modify d.x, the second d.x needs another load in
> order to ensure the correct value is used.
>
> When evaluating value2, however, since func2 takes a const
> pointer to the Data, the compiler knows the value of d.x cannot
> possibly change across that function call, so it can safely
> reuse the value of d.x that was previously loaded. It may also
> go further and refactor the expression as d.x*(func2(&d) + 1),
> because the const guarantees that func2 can't mutate d.x behind
> our backs and invalidate the result. Such a refactoring is
> invalid with func1, because there is no guarantee that d.x will
> have the same value after func1 returns.
>
> Now, the same argument applies if immutable was used in place
> of const. However, the last line in main() illustrates why we
> need const rather than immutable in this case: we actually
> *want* to modify d.x in main(). We just don't want func2 to
> touch anything. So we can't use immutable -- since immutable
> means *nobody* can touch the data. So, const provides both the
> guarantee that func2 won't touch the data, thus allowing the
> aforementioned optimization, and also continues to let main()
> mutate the data at its leisure.
>
>
> T
In C90+, const can apply to both values and pointers to those
values. And since pointers are themselves values of a memory
address that is consistent usage. That seems to be the only
meaningful distinction here. Pointing to a const value makes the
pointer mutable but the value immutable. Pointing a const to a
value makes the pointer immutable but the value mutable. etc.
Immutable accomplishes nothing distinct here that I can see,
other than making the use of const confusing. To make a function
not change a value you declare a const input. Because it is the
value declared in the function definition that is a const, not
the value you pass it. "Passing as const" doesn't make any
logical sense. To be honest, it smells like the kind of opaque
cleverness D is ostensibly supposed to obviate.
More information about the Digitalmars-d
mailing list