April 17, 2018
On Tuesday, 17 April 2018 at 00:04:32 UTC, Cym13 wrote:
> "in" returns a pointer to the object, there'es not double lookup necessary:
>
>     // if we don't know .get(key, default) exists
>     auto ptr   = key in aa;
>     auto value = ptr ? *ptr : default;

This doesn't work. `in` returns null when the key doesn't exist. So you are de-referencing null: https://github.com/dlang/druntime/blob/master/src/rt/aaA.d#L417

> is a new flag/method really that necessary? In my experience if you have trouble naming it you haven't found its true purpose yet.

My personal reason for not liking it is because the same name is used by Microsoft: https://msdn.microsoft.com/en-us/library/ee378676(v=vs.110).aspx

I think I have clearly explained its purpose.


April 17, 2018
On Tuesday, 17 April 2018 at 07:40:23 UTC, Giles Bathgate wrote:
> My personal reason for not liking it is because the same name is used by Microsoft

The java name for such a function is `computeIfAbsent`

https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util.function.Function-
April 17, 2018
On 4/15/18 6:52 PM, Giles Bathgate wrote:

> I find this later code clunky and it requires two hashes/lookups. The proposed implementation adds support directly to rt/aaA.d to avoid this. I should also point out that the allocation of a new Person in the example is trivial, but it might often be the case that the person instance is created by fetching a record from a db, or an Image loaded from disk, or a movie downloaded from the internet.

I think this is a great addition. I've always disliked the double-lookup requirement for ensuring a key was initialized. I'll note that C++ gets around this by always initializing on any access.

The name "getOrAdd" is a bit mechanical sounding. The real reason you want this is to ensure that key's value is initialized. ensureInitialized is long. get is already taken (if get weren't already taken, I'd suggest that name). Others have suggested using flags, but I'll note to them, `Flag` and `Yes` are part of std.typecons, and not accessible here.

getWithDefault sounds reasonable but probably would be confusing with the current `get` overload. Maybe getInitialized? I don't know that either of these are giant leaps ahead of getOrAdd.

Another possibility is getPtr. get currently gets a value, or returns a default value if it doesn't exist. But getPtr would return a pointer to the value, ensuring it's initialized.

In any case, thumbs up to the concept, and I'm ambivalent on the name.

-Steve
April 17, 2018
On Tuesday, 17 April 2018 at 09:21:14 UTC, Giles Bathgate wrote:
> The java name for such a function is `computeIfAbsent`

More names from other languages, this time python:

https://docs.python.org/3/library/stdtypes.html#dict.setdefault

It's horrid though, a method called `set` that returns a value? Maybe I am biased against anything pythonic ;)



April 17, 2018
On Sunday, 15 April 2018 at 22:52:47 UTC, Giles Bathgate wrote:
> The function provides a means to get a value corresponding to the key, but if the value doesn't exist it will evaluate the lazy argument to create a new value, add this to the associative array and then return it.
>
> auto p = lookup.getOrAdd("giles", new Person);

Thanks for making this pull, I've thought about solving this before. I think the function needs to provide a way to tell if the value was already present. I also think it's more ergonomic not to have to use a lazy argument, and probably more efficient, so I had in mind:

Value* slot(AA aa, K key, scope bool* inserted = null);

bool inserted;
auto p = aa.slot("key", &inserted);
if (inserted) {
  ...
  *p = new Value(...);
}
// use *p

This pattern needs a pointer to be returned, instead of using `ref`. Note that `&inserted` is valid in @safe code, but only with -dip1000. I called the function `slot` because it always returns the address of the slot which the value is stored in.
April 17, 2018
On Tuesday, 17 April 2018 at 16:18:32 UTC, Nick Treleaven wrote:
> I called the function `slot` because it always returns the address of the slot which the value is stored in.

I like the name. I think your version is quite low level which ultimately provides more power at the expense of making the callee code less clean. I am not sure with D which of those two aspects is preferred. Perhaps both functions could be provided? What is the use case for knowing whether a value was inserted.
April 17, 2018
On Tuesday, 17 April 2018 at 17:27:02 UTC, Giles Bathgate wrote:
> I like the name. I think your version is quite low level which ultimately provides more power at the expense of making the callee code less clean. I am not sure with D which of those two aspects is preferred. Perhaps both functions could be provided? What is the use case for knowing whether a value was inserted.

You may need to perform extra logic when value is inserted in the container and something else when value already existed.

I have a special version of function for that:
Value* getOrCreate(Key key, out bool wasCreated, Value default_value = Value.init)

here is an example of usage: https://github.com/MrSmith33/voxelman/blob/master/plugins/voxelman/entity/entityobservermanager.d#L33
April 17, 2018
On Tuesday, 17 April 2018 at 19:33:16 UTC, MrSmith wrote:
> You may need to perform extra logic when value is inserted in the container and something else when value already existed.

Fair enough, I will consider adding this and some tests to the PR, a function overload seems like the way to go.



April 17, 2018
On 4/17/18 12:18 PM, Nick Treleaven wrote:
> On Sunday, 15 April 2018 at 22:52:47 UTC, Giles Bathgate wrote:
>> The function provides a means to get a value corresponding to the key, but if the value doesn't exist it will evaluate the lazy argument to create a new value, add this to the associative array and then return it.
>>
>> auto p = lookup.getOrAdd("giles", new Person);
> 
> Thanks for making this pull, I've thought about solving this before. I think the function needs to provide a way to tell if the value was already present.

Not as straightforward, but it can be done:

bool inserted = false;
auto p = aa.getOrAdd("key", {inserted = true; return new Person; });

Note that most of the time, the only reason you need to know it's new is to initialize it. But the lazy parameter takes care of that for you.

> I also think it's more ergonomic not to have to use a lazy argument, and probably more efficient, so I had in mind:
> 
> Value* slot(AA aa, K key, scope bool* inserted = null);

I like the name slot. I'm less enthused about the extra machinery needed for initializing the value.

Why do you think it's less efficient to use a lazy parameter?

> This pattern needs a pointer to be returned, instead of using `ref`. Note that `&inserted` is valid in @safe code, but only with -dip1000. I called the function `slot` because it always returns the address of the slot which the value is stored in.
Returning ref makes more sense to me -- you are never going to return null.

-Steve
April 17, 2018
On Tuesday, 17 April 2018 at 20:49:30 UTC, Steven Schveighoffer wrote:
> Not as straightforward, but it can be done:
>
> bool inserted = false;
> auto p = aa.getOrAdd("key", {inserted = true; return new Person; });

Yes, I like that approach. I don't want to bloat the feature at this stage, although there is nothing stopping adding an overload later. I agree returning ref makes sense since we never return null. Consequently, I am leaning toward thinking it should be called getOrCreate now though.

Rust calls its version of this function `or_insert_with` (blegh)

https://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.or_insert_with