On Tue, Jun 21, 2016 at 01:48:27PM +0000, jmh530 via Digitalmars-d-learn wrote:
[...]
> Thanks to you and the others for the detailed clarifications. I think
> part of the difficulty is that there are basically three things being
> discussed that are all very similar: an alias to data, a pointer to
> data, and a view of data.

The word "alias" is unfortunately overloaded to mean similar, but not
exactly the same, things.

"Alias" as used in the keyword "alias" is a compiler construct that has
no real bearing on the type system.  All it is, is to create a new name
for something. For example, if I have:

        struct S {
                int x;
        }
        alias y = S.x;

all this means is that whenever the compiler sees "y" it should act as
if it has seen "S.x" instead. Well, not exactly, but basically y will
refer to whatever S.x refers to in the scope of the declaration.  This
makes it useful sometimes for naming things that are hard or impossible
to name in a different scope, for example:

        struct S(T) {
                alias ElementType = T;
        }
        S!int s;
        static assert(is(s.ElementType == int));

>From an outsider's POV, the template parameter T is not easily obtained,
but having a convenient alias inside the scope where it *is* easily
obtained, makes it readily available to outside code.

None of this is related to the present topic, though.  Which brings us
to the second meaning of "alias", as used in the type system to mean
that the same data can be reached from multiple references.  At the
bottom of this is pointers, and abstractions built on top of pointers.

        int x;
        int* p = &x;

This sense of "alias" is usually used as a verb, as in "the pointer p
aliases the variable x". Meaning, you can reach the data represented by
x via the pointer p.  So this is similar to the first meaning of "alias"
in the sense that p is kinda like a different name for x, but
semantically it's not quite the same thing, because alias in the first
sense is a compile-time concept of having one identifier being treated
as though it were another, whereas alias in the second sense here is a
runtime concept, in that the data x exists somewhere in memory, say
location L, and the pointer p happens to contain the value L, so using p
we can find x in memory without actually referring to x directly in the
code.

Now, what's the distinction between int*, const(int)*, and
immutable(int)*?  Or, for that matter, const(int*) and immutable(int*)?

To understand this, it's useful to think of the data being pointed to
distinctly from the pointer.  All of the above pointers point to some
int sitting somewhere in memory.  Let's say there are two ints, sitting
in memory locations L1 and L2, respectively. When we declared the two
ints, we specified the first one as simply 'int', meaning it's mutable.
So memory location L1 contains an int that can be modified.  Let's say
the second int is declared as immutable(int), so L2 contains an int
that, once initialized, cannot be modified.  (In this respect, there is
no difference if we declared const(int) instead, since either way nobody
can modify the value once it's initialized.)

Now, int* is a pointer to (mutable) int, so it can never point to L2. If
the language allowed that, it would break the contract that L2 cannot be
modified. Similarly, immutable(int)* is a pointer to immutable(int), so
it can never point to L1.  However, const(int)* can point to both L1 and
L2, because const(int)* just means that you cannot use *this* pointer to
modify the data, but somebody else who has a mutable reference (i.e.,
int*) pointing to the same data, may use it to modify the data.

So in short:

int*            means "pointer to an int that anybody can modify"
immutable(int)* means "pointer to an int that nobody can modify"
const(int)*     means "pointer that cannot be used to modify the int,
                but can be used to read the int"

So if you have an int* in hand, you know that the memory location it
points to is mutable, and if you have an immutable(int)* in hand, you
know that the memory location it points to is immutable (to everybody,
not just you).  However, if you have a const(int)* in hand, all you know
is that *you* can't modify the data (or more precisely, you cannot use
this particular pointer to modify the data), but it says nothing about
whether the data itself is actually modifiable or not.

What about const(int*) and immutable(int*)?  Here, thanks to transitive
const in D, the const and immutable applies both to the pointer and the
data pointed to. So const(int*) means that the data cannot be modified
through this pointer, and also that you cannot modify this pointer
itself.  (But somebody with a mutable reference to this pointer may
change what it points to.) Similarly, immutable(int*) means that the
data cannot be modified by anybody (whether through this pointer or
otherwise), and the pointer itself also cannot be modified by anybody.


T

-- 
Many open minds should be closed for repairs. -- K5 user

Reply via email to