www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Implicit dereferencing

reply =?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
next sibling parent reply "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
parent reply =?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
next sibling parent reply "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
parent reply =?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
parent reply "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
parent reply =?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
parent "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
prev sibling parent kenji hara <k.hara.pg gmail.com> writes:
2013/4/2 <luismarques gmail.com>" puremagic.com <"\"Lu=C3=ADs".Marques">

 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
prev sibling parent =?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