## digitalmars.D - Implicit dereferencing

=?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
Consider this (non-portable) code:

{
int[2] a;
int[2] b;
int[2] *c;
c = &a;

c[0] = 7;
assert(a[0] == 7); // OK, as expected

c[1] = 42;
assert(b[0] == 42); // do we really want this semantics?
}

Because indexing c automatically dereferences the pointer, "c[0]
= 7" assigns to a[0], as expected. This is the same as "(*c)[0] =
7", which is useful.

But "c[1] = 42" is equivalent to "(*(c+1)) = 42", which might not
be obvious. In this case it ends writing to b[0]. Why not make
the semantics be ((*c)+1) = 42, instead? Wouldn't that be more
useful?

Also, why don't we have pointer dereferencing for AAs?

{
struct Foo { int f; }

// given that this works...
Foo x;
Foo *y = &x;
x.f = 1;
y.f = 2; // implicit dereferencing

// coudln't this be made to work?...
int[string] c;
int[string] *d;
d = &c;
c["foo"] = 1;
d["foo"] = 2; // fails, dereferencing must be explicit
(*d)["foo"] = 2; // works, of course
}
Apr 01 2013
"Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 01 Apr 2013 20:07:30 -0400, Lu=C3=ADs Marques <luismarques gmail=
.com>  =

wrote:

Consider this (non-portable) code:

{
int[2] a;
int[2] b;
int[2] *c;
c =3D &a;

c[0] =3D 7;
assert(a[0] =3D=3D 7); // OK, as expected

c[1] =3D 42;
assert(b[0] =3D=3D 42); // do we really want this semantics?
}

Because indexing c automatically dereferences the pointer, "c[0] =3D 7=
" =
assigns to a[0], as expected. This is the same as "(*c)[0] =3D 7", whi=
ch =
is useful.
This is not what is happening. If you add: writeln(a); you will see: 7, 7 You see, indexing does NOT dereference the pointer, it's an index for th= at = pointer. c[0] means *(c + 0). A pointer is essentially an unchecked = slice, with undefined length. This is how it works in C also. c[1] is the same as *(c + 1), completely consistent (and also sets b to = = 42, 42) -Steve
Apr 01 2013
=?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
On Tuesday, 2 April 2013 at 02:52:48 UTC, Steven Schveighoffer
wrote:
You see, indexing does NOT dereference the pointer, it's an
index for that pointer.  c[0] means *(c + 0).  A pointer is
essentially an unchecked slice, with undefined length.  This is
how it works in C also.

c[1] is the same as *(c + 1), completely consistent (and also
sets b to 42, 42)
OK, I think I see where I went astray. I was a case of bad induction from a few tests :-) So, I guess what is happening is the following, right? int[2] a; int[2] *c; c = &a; c[0] = 7; // same thing as below a = 7; // same thing above (cast(int*) c)[0] = 7; // but different from this I verified that c is a pointer to a.ptr, I guess what I didn't consider is that because c points to int[2], the assignment becomes the same as a = 7, and not a[0] = 7. Still, what do you think of the struct vs AA automatic pointer dereferencing?
Apr 01 2013
"Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 01 Apr 2013 23:23:49 -0400, Lu=C3=ADs Marques <luismarques gmail=
.com>  =

wrote:

On Tuesday, 2 April 2013 at 02:52:48 UTC, Steven Schveighoffer wrote:
You see, indexing does NOT dereference the pointer, it's an index for=
=
that pointer.  c[0] means *(c + 0).  A pointer is essentially an  =
unchecked slice, with undefined length.  This is how it works in C al=
so.
c[1] is the same as *(c + 1), completely consistent (and also sets b =
to =
42, 42)
OK, I think I see where I went astray. I was a case of bad induction =
from a few tests :-)
So, I guess what is happening is the following, right?

int[2] a;
int[2] *c;
c =3D &a;

c[0] =3D 7;  // same thing as below
a =3D 7;      // same thing above

(cast(int*) c)[0] =3D 7; // but different from this

I verified that c is a pointer to a.ptr, I guess what I didn't conside=
r =
is that because c points to int[2], the assignment becomes the same as=
a =
=3D 7, and not a[0] =3D 7.

Still, what do you think of the struct vs AA automatic pointer  =
dereferencing?
a pointer defines indexing. To have implicit dereferencing for indexing= = on any pointer type would not be good. For example: string[int][2] aas; string[int] *aaptr =3D aas.ptr; auto x =3D aaptr[1]; If x is not a pointer to aas[1], then you would have to access it using = = *(aaptr + 1), which would suck. Plus it would make pointers to indexed = = types inconsistent with all pointers to types that don't define indexing= . -Steve
Apr 01 2013
=?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
On Tuesday, 2 April 2013 at 03:36:04 UTC, Steven Schveighoffer
wrote:
Plus it would make pointers to indexed types inconsistent with
all pointers to types that don't define indexing.
Yeah, of course you're right... Taking a step back, I think the problem here is that I wanted to have multiple references to the contents of an associative array. With a regular array, while you can't *store* a reference to the array "header" (ptr, length) without using pointers, you can have another array pointing to the same content. I guess you can't do something like that with an associative array, right? (mm... that kinda breaks the ideia of an AA as a more general array)
Apr 01 2013
"Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 02 Apr 2013 00:12:37 -0400, Lu=C3=ADs Marques <luismarques gmail=
.com>  =

wrote:

On Tuesday, 2 April 2013 at 03:36:04 UTC, Steven Schveighoffer wrote:
Plus it would make pointers to indexed types inconsistent with all  =
pointers to types that don't define indexing.
Yeah, of course you're right... Taking a step back, I think the problem here is that I wanted to have =
=
multiple references to the contents of an associative array. With a  =
regular array, while you can't *store* a reference to the array "heade=
r" =
(ptr, length) without using pointers, you can have another array  =
pointing to the same content. I guess you can't do something like that=
=
with an associative array, right? (mm... that kinda breaks the ideia o=
f =
an AA as a more general array)
An AA is a pImpl, meaning a pointer to implementation. A simple copy is= = an alias. HOWEVER, there is one horrible caveat. You must have assigned an elemen= t = at least once in order to alias: int[int] aa1; // pImpl initialized to null int[int] aa2; // pImpl initialized to null aa2 =3D aa1; // just assigns null to aa2 aa1[1] =3D 1; // allocates and initializes aa2[1] =3D 2; // allocates and initializes separate instance assert(aa1[1] =3D=3D 1 && aa2[1] =3D=3D 2); aa2 =3D aa1; // NOW they are aliased assert(aa2[1] =3D=3D 1); aa2[1] =3D 2; assert(aa1[1] =3D=3D 2); -Steve
Apr 01 2013
=?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
On Tuesday, 2 April 2013 at 04:48:54 UTC, Steven Schveighoffer
wrote:
HOWEVER, there is one horrible caveat.  You must have assigned
an element at least once in order to alias:
Thanks Steve, I had already looked into that, but then got dense and I was treating the AA as having value semantics. I don't need the pointer. Is there a way to ensure the AA is initialized as not null, besides adding and removing an element? (I couldn't use a literal) Is the null initializer a consequence of the current opaque implementation, or just of the reference semantics? (I saw on the wiki that there was a desire to use a less opaque implementation. I think the AA ABI should be documented, like the other arrays) Slightly related, it doesn't seem very reasonable to me that the get method of AAs is not safe: safe: void main() { int[string] x; x.get("b", 0); } Error: safe function 'D main' cannot call system function 'object.AssociativeArray!(string, int).AssociativeArray.get'
Apr 01 2013
"Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 02 Apr 2013 01:59:13 -0400, Lu=C3=ADs Marques <luismarques gmail=
.com>  =

wrote:

On Tuesday, 2 April 2013 at 04:48:54 UTC, Steven Schveighoffer wrote:
HOWEVER, there is one horrible caveat.  You must have assigned an  =
element at least once in order to alias:
Thanks Steve, I had already looked into that, but then got dense and I=
=
was treating the AA as having value semantics. I don't need the pointe=
r.
Is there a way to ensure the AA is initialized as not null, besides  =
adding and removing an element? (I couldn't use a literal)
Not sure. Looking... can't find anything. So no. There really should be.
Is the null initializer a consequence of the current opaque  =
implementation, or just of the reference semantics? (I saw on the wiki=
=
that there was a desire to use a less opaque implementation. I think t=
he =
AA ABI should be documented, like the other arrays)
The AA ABI is defined by druntime in object.di. AA's are currently a = hybrid between a compiler-magic type and a template. The plan is to mak= e = it completely a template, that is, the compiler simply always treats T[U= ] = as AssociativeArray!(T, U). The null initializer is a result of D's policy on struct initialization.= = Default constructors are not allowed on structs, they must be able to be= = initialized with static data when declared without a constructor.
Slightly related, it doesn't seem very reasonable to me that the get  =
method of AAs is not safe:

safe:

void main()
{
int[string] x;
x.get("b", 0);
}

Error: safe function 'D main' cannot call system function  =
'object.AssociativeArray!(string, int).AssociativeArray.get'
Someone (can't remember who) went through a lot of effort to try and = re-implement AAs as object.AssociativeArray and ran into a lot of proble= ms = with things like safe and pure. It really should be safe, but I don't= = know if there was a specific reason why it wasn't tagged that way. -Steve
Apr 02 2013
kenji hara <k.hara.pg gmail.com> writes:

On Tuesday, 2 April 2013 at 02:52:48 UTC, Steven Schveighoffer wrote:

You see, indexing does NOT dereference the pointer, it's an index for
that pointer.  c[0] means *(c + 0).  A pointer is essentially an uncheck=
ed
slice, with undefined length.  This is how it works in C also.

c[1] is the same as *(c + 1), completely consistent (and also sets b to
42, 42)
OK, I think I see where I went astray. I was a case of bad induction from a few tests :-) So, I guess what is happening is the following, right? int[2] a; int[2] *c; c =3D &a; c[0] =3D 7; // same thing as below a =3D 7; // same thing above
These are doing that element-wise assignment. c[0][] =3D 7; // same as c[0][0] =3D c[0][1] =3D 7; a[] =3D 7; // same as a[0] =3D a[1] =3D 7; As a side note:
From 2.063, lack of [] for array operation would be warned with -w switch.
So, there is no "implicit dereferencing". Kenji Hara
Apr 01 2013
=?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/01/2013 05:07 PM, "Luís Marques" <luismarques gmail.com>" wrote:>
Consider this (non-portable) code:

Perhaps it is obvious to everyone but allow me still: It is not
non-portable code, but its behavior is undefined.

{
int[2] a;
int[2] b;
int[2] *c;
c is a pointer to a single int[2].
c = &a;

c[0] = 7;
assert(a[0] == 7); // OK, as expected

c[1] = 42;
assert(b[0] == 42); // do we really want this semantics?
A manifestation of undefined behavior.
But "c[1] = 42" is equivalent to "(*(c+1)) = 42", which might not be
obvious. In this case it ends writing to b[0].
It seems to be so but it is not defined to work that way. Ali
Apr 01 2013