Jump to page: 1 2
Thread overview
Associative Array c'tor
Jul 11, 2016
Bahman Movaqar
Jul 11, 2016
Bahman Movaqar
Jul 11, 2016
Ali Çehreli
Jul 12, 2016
Bahman Movaqar
Jul 12, 2016
ketmar
Jul 12, 2016
ketmar
Jul 12, 2016
cym13
Jul 12, 2016
ketmar
July 11, 2016
I'm processing a list of structs (MySt) with `reduce` to produce an
associate array of type `MySt[][string]`.
Right now I'm using the following (slimmed down) code:

    MySt[][string] result;
    return reduce!(
      function MySt[][string](MySt[][string] acc, MySt val) {
        // do something with acc
        return acc;
      }
    )(result, inputList);

I was wondering if I could remove the empty declaration line (line 1);
for example:

    return reduce!(
      function MySt[][string](MySt[][string] acc, MySt val) {
        // do something with acc
        return acc;
      }
    )(new MySt[][string](), inputList);

Obviously, this fails with the error message: "cannot pass type string as a function argument".

I very much would like to avoid empty declaration lines like that of `result`.  Is there anyway you folks would suggest?

Thanks in advance,
--
Bahman
July 11, 2016
On 7/11/16 9:48 AM, Bahman Movaqar wrote:
> I'm processing a list of structs (MySt) with `reduce` to produce an
> associate array of type `MySt[][string]`.
> Right now I'm using the following (slimmed down) code:
>
>     MySt[][string] result;
>     return reduce!(
>       function MySt[][string](MySt[][string] acc, MySt val) {
>         // do something with acc
>         return acc;
>       }
>     )(result, inputList);
>
> I was wondering if I could remove the empty declaration line (line 1);
> for example:
>
>     return reduce!(
>       function MySt[][string](MySt[][string] acc, MySt val) {
>         // do something with acc
>         return acc;
>       }
>     )(new MySt[][string](), inputList);
>
> Obviously, this fails with the error message: "cannot pass type string
> as a function argument".
>
> I very much would like to avoid empty declaration lines like that of
> `result`.  Is there anyway you folks would suggest?

Untested, but you could try MySt[][string].init.

But passing empty AA by value sometimes can be surprising. I'm not sure if it will work.

-Steve


July 11, 2016
On 07/11/2016 06:30 PM, Steven Schveighoffer wrote:
> Untested, but you could try MySt[][string].init.

That did it.  Thanks.

> But passing empty AA by value sometimes can be surprising. I'm not sure if it will work.

Could you elaborate more?

-- 
Bahman
July 11, 2016
On 07/11/2016 07:33 AM, Bahman Movaqar wrote:
> On 07/11/2016 06:30 PM, Steven Schveighoffer wrote:
>> Untested, but you could try MySt[][string].init.
>
> That did it.  Thanks.
>
>> But passing empty AA by value sometimes can be surprising. I'm not sure
>> if it will work.
>
> Could you elaborate more?

Both AAs and slices behave like reference types even when passed by value: When a function adds an element, the argument sees that element as well. This is not the case when the argument is an empty (more correctly, null) AA or slice:

void foo(string[int] aa) {
    aa[1] = "one";
}

void main() {
    string[int] a;
    foo(a);
    assert(a is null);
    // The last result would be different if 'a' were not null
    // before calling 'foo'.

    string[int] b;
    b[0] = "zero";
    foo(b);
    assert(b[0] == "zero");
    assert(b[1] == "one");
}

Ali

P.S. There is std.array.assocArray if you already have a range of tuples at hand:

  https://dlang.org/phobos/std_array.html#.assocArray

P.P.S. There is std.algorithm.fold, which works with range chaining (unlike reduce, which was designed before ranges):

  https://dlang.org/phobos/std_algorithm_iteration.html#.fold

July 11, 2016
On 7/11/16 10:33 AM, Bahman Movaqar wrote:
> On 07/11/2016 06:30 PM, Steven Schveighoffer wrote:
>> But passing empty AA by value sometimes can be surprising. I'm not sure
>> if it will work.
>
> Could you elaborate more?

An AA initializes on demand. So if you pass by value *after* it has been initialized it behaves like a reference type. But before it's initialized, it's essentially a null pointer. This can cause surprising behavior:

foo(int[int] aa)
{
    foreach(i; 0 .. 100)
        aa[i] = i;
}

void main()
{
    import std.random;
    int[int] aa; // initialized as null
    if(uniform!ubyte < 128)
        aa[0] = 0; // intialized
    foo(aa);

    // at this point, depending on random initialization, either aa is filled or is still null.
}

-Steve
July 12, 2016
On 07/11/2016 07:15 PM, Ali Çehreli wrote:
> Both AAs and slices behave like reference types even when passed by value: When a function adds an element, the argument sees that element as well. This is not the case when the argument is an empty (more correctly, null) AA or slice:
> 
> void foo(string[int] aa) {
>     aa[1] = "one";
> }
> 
> void main() {
>     string[int] a;
>     foo(a);
>     assert(a is null);
>     // The last result would be different if 'a' were not null
>     // before calling 'foo'.
> 
>     string[int] b;
>     b[0] = "zero";
>     foo(b);
>     assert(b[0] == "zero");
>     assert(b[1] == "one");
> }

Now I understand.
This is tricky --could introduce hard to find bugs.  Is there anyway to
make sure it doesn't happen?  Such as giving the AA a default empty
value on the declaration line --like `string[int] a = []`?

> P.P.S. There is std.algorithm.fold, which works with range chaining (unlike reduce, which was designed before ranges):
> 
>   https://dlang.org/phobos/std_algorithm_iteration.html#.fold

`fold` definitely feels more natural.

Thanks.

-- 
Bahman
July 12, 2016
On Tuesday, 12 July 2016 at 03:38:44 UTC, Bahman Movaqar wrote:
> Now I understand.
> This is tricky --could introduce hard to find bugs.  Is there anyway to
> make sure it doesn't happen?  Such as giving the AA a default empty
> value on the declaration line --like `string[int] a = []`?

no. the only thing you can do is to add something to aa and immediately `.clear`
July 12, 2016
On 7/12/16 5:42 AM, ketmar wrote:
> On Tuesday, 12 July 2016 at 03:38:44 UTC, Bahman Movaqar wrote:
>> Now I understand.
>> This is tricky --could introduce hard to find bugs.  Is there anyway to
>> make sure it doesn't happen?  Such as giving the AA a default empty
>> value on the declaration line --like `string[int] a = []`?
>
> no. the only thing you can do is to add something to aa and immediately
> `.clear`

There was a suggestion to make .clear (a relatively new feature) actually preallocate if it's currently null, but I didn't want to do allocating in that method (too surprising). I do think it would be nice to have an initializer function that simply allocates the impl.

Anyone want to do a PR?

basically (strawman name):

int[int] aa;
aa.initialize; // still has 0 elements, but no longer null.

I'm not sure you could make a static initializer method, since AA's are special builtin types.

Relative modules needed to be changed are object.d and src/rt/aaA.d

-Steve
July 12, 2016
On Tuesday, 12 July 2016 at 12:34:40 UTC, Steven Schveighoffer wrote:
> There was a suggestion to make .clear (a relatively new feature) actually preallocate if it's currently null, but I didn't want to do allocating in that method (too surprising). I do think it would be nice to have an initializer function that simply allocates the impl.

q&n patch[1]. it adds template arg to `.clear`, so no code breakage here (old `clear` is still not allocate, but `.clear!true` will).


[1] https://issues.dlang.org/show_bug.cgi?id=16269
July 12, 2016
On Tuesday, 12 July 2016 at 13:01:20 UTC, ketmar wrote:
> On Tuesday, 12 July 2016 at 12:34:40 UTC, Steven Schveighoffer wrote:
>> There was a suggestion to make .clear (a relatively new feature) actually preallocate if it's currently null, but I didn't want to do allocating in that method (too surprising). I do think it would be nice to have an initializer function that simply allocates the impl.
>
> q&n patch[1]. it adds template arg to `.clear`, so no code breakage here (old `clear` is still not allocate, but `.clear!true` will).
>
>
> [1] https://issues.dlang.org/show_bug.cgi?id=16269

I'm with Steven here, that's definitely too surprising, initialization should not be linked to clear in any way.
« First   ‹ Prev
1 2