Thread overview | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 11, 2016 Associative Array c'tor | ||||
---|---|---|---|---|
| ||||
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 Re: Associative Array c'tor | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bahman Movaqar | 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 Re: Associative Array c'tor | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | 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 Re: Associative Array c'tor | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bahman Movaqar | 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 Re: Associative Array c'tor | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bahman Movaqar | 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 Re: Associative Array c'tor | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | 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 Re: Associative Array c'tor | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bahman Movaqar | 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 Re: Associative Array c'tor | ||||
---|---|---|---|---|
| ||||
Posted in reply to ketmar | 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 Re: Associative Array c'tor | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | 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 Re: Associative Array c'tor | ||||
---|---|---|---|---|
| ||||
Posted in reply to ketmar | 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.
|
Copyright © 1999-2021 by the D Language Foundation