Jump to page: 1 29  
Page
Thread overview
[:] as empty associative array literal, plus warning for null
Jul 03, 2013
bearophile
Jul 03, 2013
deadalnix
Jul 03, 2013
bearophile
Jul 03, 2013
Dicebot
Jul 04, 2013
Timon Gehr
Jul 04, 2013
Henning Pohl
Jul 04, 2013
Jonathan M Davis
Jul 04, 2013
Dicebot
Jul 03, 2013
Diggory
Jul 04, 2013
Regan Heath
Jul 04, 2013
deadalnix
Jul 03, 2013
TommiT
Jul 03, 2013
bearophile
Jul 03, 2013
bearophile
Jul 03, 2013
bearophile
Jul 03, 2013
TommiT
Jul 03, 2013
Timon Gehr
Jul 03, 2013
Timon Gehr
Jul 04, 2013
Regan Heath
Jul 04, 2013
Timon Gehr
Jul 04, 2013
monarch_dodra
Jul 04, 2013
Regan Heath
Jul 04, 2013
monarch_dodra
Jul 04, 2013
Regan Heath
Jul 04, 2013
Regan Heath
Jul 04, 2013
Jonathan M Davis
Jul 04, 2013
Jonathan M Davis
Jul 05, 2013
Regan Heath
Jul 05, 2013
Regan Heath
Jul 04, 2013
Timon Gehr
Jul 04, 2013
monarch_dodra
Jul 04, 2013
Timon Gehr
Jul 04, 2013
TommiT
Jul 04, 2013
Timon Gehr
Jul 04, 2013
NotYetUsingD
Jul 04, 2013
bearophile
Jul 04, 2013
bearophile
Jul 05, 2013
deadalnix
Jul 08, 2013
bearophile
Jul 05, 2013
Nicolas Sicard
Jul 05, 2013
monarch_dodra
Jul 05, 2013
Dicebot
Jul 04, 2013
Timon Gehr
Jul 04, 2013
TommiT
Jul 04, 2013
Regan Heath
Jul 04, 2013
Dmitry Olshansky
Jul 05, 2013
Regan Heath
Jul 05, 2013
Dmitry Olshansky
Jul 05, 2013
Regan Heath
Jul 05, 2013
Dmitry Olshansky
Jul 05, 2013
TommiT
Jul 05, 2013
Artur Skawina
Jul 05, 2013
Dmitry Olshansky
Jul 05, 2013
Artur Skawina
Jul 05, 2013
Regan Heath
Jul 05, 2013
TommiT
Jul 05, 2013
Dmitry Olshansky
Jul 05, 2013
Jonathan M Davis
Jul 05, 2013
Regan Heath
Jul 05, 2013
Jonathan M Davis
Jul 05, 2013
deadalnix
Jul 05, 2013
Daniel Murphy
Jul 04, 2013
Mr. Anonymous
Jul 04, 2013
Timon Gehr
Jul 04, 2013
Regan Heath
Jul 04, 2013
Artur Skawina
Jul 03, 2013
Timon Gehr
July 03, 2013
Time ago I have opened an enhancement request for empty associative array literals:

http://d.puremagic.com/issues/show_bug.cgi?id=7227

This is currently correct code:

void foo(int[int] bb) {}
void main() {
    int[int] aa;
    aa = null;
    foo(null);
    int[int][] aas = [null, null];
}


With the proposal it becomes:

void foo(int[int] bb) {}
void main() {
    int[int] aa;
    aa = [:];
    foo([:]);
    int[int][] aas = [[:], [:]];
}


I am writing about it here because Henning Pohl has written a first version of a patch:

https://github.com/D-Programming-Language/dmd/pull/2284

- - - - - - - - - - - - -

The patch by Henning Pohl uses the [] syntax as literal for empty associative array, but I prefer the [:] syntax, because it's more precise.

Kenji Hara shows the ambiguity of the [] syntax (that was already present with using "null" as literals), that [:] lacks:

void foo(int[]);
void foo(int[int]);
foo([]);   // prefer int[] overload, or ambiguous?

- - - - - - - - - - - - -

On GitHub yebblies commented:

> Ideally this would not be the same as K[V] aa = null;,
> it would behave like K[V] aa = new K[V]; - an AA would be allocated.

I think this is a bad idea, because then the semantics of D code changes if you use [:] instead of null. D associative arrays have problems:


void test(int[int] arraya, int x) {
    arraya[x] = x;
}

void main() {
    int[int] d;
    test(d, 0);
    int[int] d0;
    assert(d == d0); // d is empty, 0:0 is lost

    d[1] = 1;
    test(d, 2);
    assert(d == [1: 1, 2: 2]); // now 2:2 is not lost
}


Compared to the output of this Python code:

def test(arraya, x):
    arraya[x] = x

def main():
    d = {}
    test(d, 0)
    assert d == {0: 0}

    d[1] = 1
    test(d, 2)
    assert d == {0: 0, 1: 1, 2: 2}
main()


Such problems should be faced in other ways. Making the associative array literal semantics even more complex is not helping.

This problem is present for dynamic arrays too, and I asked to fix it:

http://d.puremagic.com/issues/show_bug.cgi?id=5788

- - - - - - - - - - - - -

With the introduction of the new empty associative array literal it's a good idea to warn against the usage of the older "null" literal:

void foo(int[int]) {}
void main() {
    foo(null);
    int[int][] aas = [null];
    aas[0] = [1: 2, 2: 3];
}


Should give the warnings:

test.d(3): Warning: explicit [:] empty associative array literal is better than null, that will be deprecated
test.d(4): Warning: explicit [:] empty associative array literal is better than null, that will be deprecated


The wording of such warning message is modelled on another warning message:

test.d(3): Warning: explicit element-wise assignment (a)[] = 2 is better than a = 2


For Jonathan M Davis: this is a new warning, but later it's supposed to become a deprecation message, and then an error. So this is not meant meant to be a permanent warning.

Lot of time ago I have also proposed to deprecate "null" as literal for dynamic arrays, this goes well with the idea that dynamic arrays are not pointers (the * syntax was disallowed for dynamic arrays, etc), this is meant to go with the optimization requested in issue 5788:

http://d.puremagic.com/issues/show_bug.cgi?id=3889

Bye,
bearophile
July 03, 2013
On Wednesday, 3 July 2013 at 14:33:02 UTC, bearophile wrote:
> Time ago I have opened an enhancement request for empty associative array literals:
>

Why not simply [] ? After all, an array is just a very simple type of hashmap, with the identity as hash function.
July 03, 2013
deadalnix:

> Why not simply [] ? After all, an array is just a very simple type of hashmap, with the identity as hash function.

In a language it's very often handy for different data types to have different textual representations and different literals.


If in D code you see:

foo0(null);

That foo0 can be a function that takes a null pointer, and empty dynamic array, an empty string, an empty associative array (or even a Nullable).


Using [] as empty associative array literal is only a bit better than using null:

foo1([]);

Now foo4 can take an empty dynamic array, an empty string, or an empty associative array.


Instead if you see:

foo2("");
foo3([]);
foo4([:]);

Now you know what you are giving to that function, it's more readable because more explicit.


Currently if you have code like this:

void foo(int[]) {}
void foo(int[int]) {}
void main() {
    foo(null);
}



The compiler gives an error because of the ambiguity:

test.d(4): Error: called with argument types:
    (typeof(null))
matches both:
    temp.d(1): test.foo(int[] _param_0)
and:
    temp.d(2): test.foo(int[int] _param_0)


If you introduce [] as empty associative array literal, the code will give similar errors, the situation is not improved much compared to null, this is what Kenji was saying.


But if you introduce a literal for associative arrays it's better to design it right. [:] avoids the ambiguity, and this code gives no errors:

void foo(int[]) {}
void foo(int[int]) {}
void main() {
    foo([]);
    foo([:]);
}


[:] takes just one more char compared to [] so it's doesn't cause too much typing (and it's shorter than null). And I think D programmers are able to infer what [:] means, I think it's not hard to learn.

Bye,
bearophile
July 03, 2013
On Wednesday, 3 July 2013 at 16:55:59 UTC, bearophile wrote:
> ...

Has sounded convincing enough for me. Anything that enforces stronger typing is big win in my opinion.
July 03, 2013
On Wednesday, 3 July 2013 at 14:33:02 UTC, bearophile wrote:
> [..]

I think it's a good idea to have [:] literal for associative arrays since there's [] literal for dynamic arrays.

But I would expect [] to mean "empty dynamic array", not null. And the same for [:]. This is how I'd expect things to work:

int[] nullArray;
assert(nullArray is null);

int[] emptyArray = [];
assert(emptyArray !is null);

int[string] nullAA;
assert(nullAA is null);

int[string] emptyAA = [:];
assert(emptyAA !is null);

Reasoning by extrapolation:
int[] arr = [1, 2, 3]; // Array of 3 ints
int[] arr = [1, 2]; // Array of 2 ints
int[] arr = [1]; // Array of 1 ints
int[] arr = []; // Array of 0 ints (not null)
July 03, 2013
TommiT:

> But I would expect [] to mean "empty dynamic array", not null. And the same for [:]. This is how I'd expect things to work:
>
> int[] nullArray;
> assert(nullArray is null);
>
> int[] emptyArray = [];
> assert(emptyArray !is null);
>
> int[string] nullAA;
> assert(nullAA is null);
>
> int[string] emptyAA = [:];
> assert(emptyAA !is null);
>
> Reasoning by extrapolation:
> int[] arr = [1, 2, 3]; // Array of 3 ints
> int[] arr = [1, 2]; // Array of 2 ints
> int[] arr = [1]; // Array of 1 ints
> int[] arr = []; // Array of 0 ints (not null)

I have discussed the topic here regarding dynamic arrays:
http://d.puremagic.com/issues/show_bug.cgi?id=3889
http://d.puremagic.com/issues/show_bug.cgi?id=5788

This means you have to keep "null" in the language to represent an empty associative array, because someone somewhere will surely want a literal that avoids memory allocations. So lot of people will keep using null, and the coding situation is improved about zero.

Telling apart the literal for an empty array from the literal of a empty but not null array is a bad idea that muds the language. And thankfully this currently fails:

void main() {
    int[] emptyArray = [];
    assert(emptyArray !is null);
}

Bye,
bearophile
July 03, 2013
I agree - the current state with both null and non-null empty arrays is confusing, and the separate syntax for empty arrays and associative arrays is nice and consistent.

I would go as far as to say it should be impossible, or at least fairly difficult in safe code to distinguish (both intentionally and unintentionally) between an array of size zero with a non-null pointer and an array of size zero with a null pointer, and similar for associative arrays too.
July 03, 2013
> Telling apart the literal for an empty array from the literal of a empty but not null array is a bad idea that muds the language. And thankfully this currently fails:
>
> void main() {
>     int[] emptyArray = [];
>     assert(emptyArray !is null);
> }


But currently this code:

void main() {
    int[] emptyArray = [];
}


produces a call to __d_arrayliteralTX, for reasons unknown to me:


_D4temp10emptyArrayFZAi comdat
L0:     push    EAX
        mov EAX,offset FLAT:_D11TypeInfo_Ai6__initZ
        push    0
        push    EAX
        call    near ptr __d_arrayliteralTX
        mov EDX,EAX
        add ESP,8
        pop ECX
        xor EAX,EAX
        ret

Bye,
bearophile
July 03, 2013
> produces a call to __d_arrayliteralTX, for reasons unknown to me:
>
>
> _D4temp10emptyArrayFZAi comdat
> L0:     push    EAX
>         mov EAX,offset FLAT:_D11TypeInfo_Ai6__initZ
>         push    0
>         push    EAX
>         call    near ptr __d_arrayliteralTX
>         mov EDX,EAX
>         add ESP,8
>         pop ECX
>         xor EAX,EAX
>         ret

Sorry, my mistake, I meant:

__Dmain comdat
L0:     push    EAX
        mov EAX,offset FLAT:_D11TypeInfo_Ai6__initZ
        push    0
        push    EAX
        call    near ptr __d_arrayliteralTX
        add ESP,8
        xor EAX,EAX
        pop ECX
        ret

Bye,
bearophile
July 03, 2013
On Wednesday, 3 July 2013 at 18:10:42 UTC, bearophile wrote:
> TommiT:
>> But I would expect [] to mean "empty dynamic array", not null. [..]
> [..]
>
> This means you have to keep "null" in the language to represent an empty associative array, because someone somewhere will surely want a literal that avoids memory allocations. So lot of people will keep using null, and the coding situation is improved about zero.

Okay, I didn't realize an empty array would need to allocate.
« First   ‹ Prev
1 2 3 4 5 6 7 8 9