Re: Feature to get or add value to an associative array.

2018-04-25 Thread Giles Bathgate via Digitalmars-d

On Tuesday, 24 April 2018 at 09:09:37 UTC, Andrea Fontana wrote:

Just one question: does this work for value-types?


The intention is that it will work for value types. I will add 
some unit tests to check that use case.


- Giles


Re: Feature to get or add value to an associative array.

2018-04-24 Thread Andrea Fontana via Digitalmars-d

On Sunday, 15 April 2018 at 22:52:47 UTC, Giles Bathgate wrote:

Hi,

I wanted a way to lazily insert a value into an associative 
array, and I am proposing a new function called getOrAdd in  
https://github.com/dlang/druntime/pull/2162


Yes please :)

Just one question: does this work for value-types?

This is a pretty common case for me (simplified and not optimized 
version):


size_t[string] counter;
...
foreach(e; elements)
{
   if (e.something !in counter) counter[e.something] = 0;
   else counter[e.something]++;
}

So will this work?

foreach(e; elements)
   counter.update(e.something, { return 0; }, (size_t v) { return 
v+1; })


Andrea


Andrea


Re: Feature to get or add value to an associative array.

2018-04-20 Thread Uknown via Digitalmars-d
On Friday, 20 April 2018 at 15:00:39 UTC, Steven Schveighoffer 
wrote:

On 4/20/18 10:34 AM, Uknown wrote:
On Friday, 20 April 2018 at 14:02:17 UTC, Steven Schveighoffer 
wrote:

On 4/20/18 4:24 AM, Nick Treleaven wrote:

On Wednesday, 18 April 2018 at 16:47:50 UTC, ag0aep6g wrote:

[...]


Sorry, it was a typo. In my real code I have:

xp = &(foo(x));

That's what I get for hand-typing instead of copy-pasting :)

-Steve


It seems like a bug. Changing foo to take and return an `int *` 
works as expected

https://run.dlang.io/is/3NYXYv


Re: Feature to get or add value to an associative array.

2018-04-20 Thread Steven Schveighoffer via Digitalmars-d

On 4/20/18 10:34 AM, Uknown wrote:

On Friday, 20 April 2018 at 14:02:17 UTC, Steven Schveighoffer wrote:

On 4/20/18 4:24 AM, Nick Treleaven wrote:

On Wednesday, 18 April 2018 at 16:47:50 UTC, ag0aep6g wrote:

You can get a pointer from the ref return:

    Value* p = ("key", { inserted = true; return Value.init; 
});


This is not @safe, even with -dip1000:

Error: cannot take address of ref return of f() in @safe function main


Hm... I would have expected it to work in dip1000.

Hard for me to understand what dip1000 is doing, but it seems like an 
omission:


@safe ref int foo(return ref int x) { return x; }

void main() @safe
{
   int x;
   scope int *xp =  // OK with dip1000
   xp = foo(x); // Error, even though it's exactly the same
}

And in this case, it doesn't even need to be scope, as it's GC data. 
How does one communicate that the ref return is of GC data and can be 
escaped as much as you want?




The error seems to be about type mismatching, it works if you use auto. 
I don't see how you could convert the `ref int` to `int *`

https://run.dlang.io/is/eIJMIK


Sorry, it was a typo. In my real code I have:

xp = &(foo(x));

That's what I get for hand-typing instead of copy-pasting :)

-Steve


Re: Feature to get or add value to an associative array.

2018-04-20 Thread Uknown via Digitalmars-d
On Friday, 20 April 2018 at 14:02:17 UTC, Steven Schveighoffer 
wrote:

On 4/20/18 4:24 AM, Nick Treleaven wrote:

On Wednesday, 18 April 2018 at 16:47:50 UTC, ag0aep6g wrote:

You can get a pointer from the ref return:

    Value* p = ("key", { inserted = true; return 
Value.init; });


This is not @safe, even with -dip1000:

Error: cannot take address of ref return of f() in @safe 
function main


Hm... I would have expected it to work in dip1000.

Hard for me to understand what dip1000 is doing, but it seems 
like an omission:


@safe ref int foo(return ref int x) { return x; }

void main() @safe
{
   int x;
   scope int *xp =  // OK with dip1000
   xp = foo(x); // Error, even though it's exactly the same
}

And in this case, it doesn't even need to be scope, as it's GC 
data. How does one communicate that the ref return is of GC 
data and can be escaped as much as you want?


-Steve


The error seems to be about type mismatching, it works if you use 
auto. I don't see how you could convert the `ref int` to `int *`

https://run.dlang.io/is/eIJMIK


Re: Feature to get or add value to an associative array.

2018-04-20 Thread Steven Schveighoffer via Digitalmars-d

On 4/20/18 4:24 AM, Nick Treleaven wrote:

On Wednesday, 18 April 2018 at 16:47:50 UTC, ag0aep6g wrote:

You can get a pointer from the ref return:

    Value* p = ("key", { inserted = true; return Value.init; });


This is not @safe, even with -dip1000:

Error: cannot take address of ref return of f() in @safe function main


Hm... I would have expected it to work in dip1000.

Hard for me to understand what dip1000 is doing, but it seems like an 
omission:


@safe ref int foo(return ref int x) { return x; }

void main() @safe
{
   int x;
   scope int *xp =  // OK with dip1000
   xp = foo(x); // Error, even though it's exactly the same
}

And in this case, it doesn't even need to be scope, as it's GC data. How 
does one communicate that the ref return is of GC data and can be 
escaped as much as you want?


-Steve


Re: Feature to get or add value to an associative array.

2018-04-20 Thread Giles Bathgate via Digitalmars-d

On Friday, 20 April 2018 at 02:12:37 UTC, Jonathan M Davis wrote:
Out of all of those, I _really_ hope that you don't go with 
require. It sounds like the sort of thing that you'd get in a 
library having to do with unit testing or contracts and gives 
no indication whatsoever as to what it does.


Yes I know. I gave up on trying to find a single verb or 
runTogetherWords that would describe exactly what it does, and 
instead opted for something that I like, and added documentation 
to describe what it does.


I don't think I will find a name that everybody likes. But I am 
open to more suggestions as its probably the easiest aspect of 
the PR to change.


Re: Feature to get or add value to an associative array.

2018-04-20 Thread Giles Bathgate via Digitalmars-d

On Friday, 20 April 2018 at 08:37:59 UTC, Nick Treleaven wrote:

Again, would the delegate calls always be inlined, in all cases?

I think having a low-level API in druntime is appropriate, it's 
a runtime library after all.


So the low-level API you are requesting is part of the pull 
request, the low-level API is called _aaGetX, whereas the 
previous API was _aaGetY, the new API adds a boolean out 
parameter `found` and if you really wanted to you could do this:


-
extern (C) void* _aaGetX(void** paa, const 
TypeInfo_AssociativeArray ti, in size_t valuesize, in void* pkey, 
out bool found) pure nothrow;


V* slot(K, V)(ref V[K] aa, K key, out bool found)
{
return cast(V*) _aaGetX(cast(void**), typeid(V[K]), 
V.sizeof, , found);

}
-

I am also benchmarking the `update` function I talked about 
previously.

https://gist.github.com/GilesBathgate/8409b5889ebb7b1302627c50f342a28b

The results seem to indicate that there isn't much in it 
performance wise.


test1 [56 ms, 377 µs, and 4 hnsecs]
test2 [56 ms, 262 µs, and 2 hnsecs]

I can't fathom why the delegates version is faster, but I am just 
putting it down to luck ;)


Re: Feature to get or add value to an associative array.

2018-04-20 Thread ag0aep6g via Digitalmars-d

On Friday, 20 April 2018 at 09:24:26 UTC, Jonathan M Davis wrote:
The compiler assumes that a pointer is valid when determining 
whether code is @safe.

[...]
Basically, it verifies the @safety of pointers when they're 
created and then assumes that they're @safe after that.


Can't it do the same for ref returns? Unsafe stuff like returning 
a ref to a local is already disallowed, just like returning a 
pointer to a local. So the compiler checks the safety on 
creation, at least in some cases.


So, passing around a pointer is perfectly @safe, whereas taking 
the address of a ref return value to get a pointer is not.


It's still not clear to me how taking the address of a ref return 
is necessarily less safe than using a returned pointer. Do you 
maybe have an example in code that shows the difference?


It seems to me that refs and pointers are very much equivalent. I 
should always be able to turn one into the other.


Re: Feature to get or add value to an associative array.

2018-04-20 Thread Jonathan M Davis via Digitalmars-d
On Friday, April 20, 2018 10:56:37 ag0aep6g via Digitalmars-d wrote:
> On 04/20/2018 10:24 AM, Nick Treleaven wrote:
> > On Wednesday, 18 April 2018 at 16:47:50 UTC, ag0aep6g wrote:
> >> You can get a pointer from the ref return:
> >>
> >> Value* p = ("key", { inserted = true; return Value.init;
> >> });
> >
> > This is not @safe, even with -dip1000:
> >
> > Error: cannot take address of ref return of f() in @safe function main
>
> Hm. Do you know why that's not allowed? I can't see how it would be less
> safe than returning a pointer, and I can't find a mention of it in DIP
> 1000 [1]. Maybe it's just a case of incomplete/buggy implementation?
>
>
> [1] https://github.com/dlang/DIPs/blob/master/DIPs/DIP1000.md

The compiler assumes that a pointer is valid when determining whether code
is @safe. It then disallows operations that it can't guarantee are @safe
even if the pointer is valid, and it disallows taking the address in cases
where it can't guarantee that that's @safe. Basically, it verifies the
@safety of pointers when they're created and then assumes that they're @safe
after that. So, passing around a pointer is perfectly @safe, whereas taking
the address of a ref return value to get a pointer is not.

- Jonathan M Davis



Re: Feature to get or add value to an associative array.

2018-04-20 Thread ag0aep6g via Digitalmars-d

On 04/20/2018 10:24 AM, Nick Treleaven wrote:

On Wednesday, 18 April 2018 at 16:47:50 UTC, ag0aep6g wrote:

You can get a pointer from the ref return:

    Value* p = ("key", { inserted = true; return Value.init; });


This is not @safe, even with -dip1000:

Error: cannot take address of ref return of f() in @safe function main


Hm. Do you know why that's not allowed? I can't see how it would be less 
safe than returning a pointer, and I can't find a mention of it in DIP 
1000 [1]. Maybe it's just a case of incomplete/buggy implementation?



[1] https://github.com/dlang/DIPs/blob/master/DIPs/DIP1000.md


Re: Feature to get or add value to an associative array.

2018-04-20 Thread Dominikus Dittes Scherkl via Digitalmars-d

On Thursday, 19 April 2018 at 08:20:02 UTC, Giles Bathgate wrote:
On Wednesday, 18 April 2018 at 21:04:53 UTC, Jordan Wilson 
wrote:
Thinking seems sound, although having a name starting with 
"get" does have the advantage of being more related to the 
existing get.


Ah yes, good point. I think now we've had the discussion about 
other use cases though that ultimately there might need to be 
an "atomic" AddOrUpdate style function too, which I was 
thinking could just be called 'update'. The necessity to keep 
them all starting with get seemed less important.


How about something like "forceGet" to make clear you will get 
it, even if it wasn't there before.


Re: Feature to get or add value to an associative array.

2018-04-20 Thread Nick Treleaven via Digitalmars-d

On Wednesday, 18 April 2018 at 16:04:13 UTC, Giles Bathgate wrote:
I understand where you are coming from, but I am not sure it is 
appropriate to shoehorn every use case into one api.


It is not shoehorning, the difference here is just returning by 
ref vs pointer. I understand that, as the pointer address is not 
needed by the caller, it is cleaner to use ref. The problem is 
that local refs are not supported by D, and so I would need to do 
this (at least in safe code):


import std.functional : unaryFun;
bool ins;
aa.update("key", {ins = true; return 1;}).unaryFun!((v){ if (ins) 
v++; });


This seems pretty convoluted. It could be made a bit better if D 
supported UFCS for lambdas, then unaryFun wouldn't be needed.


BTW, I like the name `update`.

void createOrUpdate(K, V)(ref V[K] aa, K key, V delegate() 
create, void delegate(V*) update);


Again, would the delegate calls always be inlined, in all cases?

I think having a low-level API in druntime is appropriate, it's a 
runtime library after all.




Re: Feature to get or add value to an associative array.

2018-04-20 Thread Nick Treleaven via Digitalmars-d

On Wednesday, 18 April 2018 at 16:47:50 UTC, ag0aep6g wrote:

You can get a pointer from the ref return:

Value* p = ("key", { inserted = true; return 
Value.init; });


This is not @safe, even with -dip1000:

Error: cannot take address of ref return of f() in @safe function 
main


Re: Feature to get or add value to an associative array.

2018-04-19 Thread Jonathan M Davis via Digitalmars-d
On Wednesday, April 18, 2018 17:19:45 Giles Bathgate via Digitalmars-d 
wrote:
> On Sunday, 15 April 2018 at 22:55:41 UTC, Giles Bathgate wrote:
> > Time for a bikeshed discussion...
>
> I have had some thoughts about the name and would like to share
> my idea.
>
> Firstly to summarise here are the names that have been
> found/discussed so far:
>
> C#   : GetOrAdd
> Java : computeIfAbsent
> Python   : setdefault
> Rust : entry(key).or_insert_with
>
> Jordan Wilson: getOrAdd, getOrSet
> User1234 : valueOrDefault
> Nicholas Wilson  : getOrInsert
> Steven Schveighoffer : getPtr, getRef, getInitialized
> Nick Treleaven   : slot
> MrSmith  : getOrCreate
>
> My latest idea is just a working title, but I think I prefer it
> to my original getOrAdd.
>
> Giles Bathgate   : require
>
> My thinking is that if you `require` there to be a value in the
> associative array, then you should have the ability to add one
> iff it doesn't exist. It name also has parallels with the term in
> other programming languages to require a module, meaning to
> import it if it hasn't already been loaded.

Out of all of those, I _really_ hope that you don't go with require. It
sounds like the sort of thing that you'd get in a library having to do with
unit testing or contracts and gives no indication whatsoever as to what it
does. The only one in that list that seems similarly opaque is slot. Those
names say nothing about either getting a value or adding / inserting one.
Every other name at least gives some clue as to what the function does.

If I were adding it, and we already had get, I would just make it an
optional argument to get, which wouldn't necessarily be clear about
inserting, but it would at least be clear about getting. However, since we
used overloaded operators, there's no get.

Another option would be getOrInit, though I agree that they're all kind of
ugly.

Either way, IMHO, getOrAdd is infinitely better than require.

- Jonathan M Davis



Re: Feature to get or add value to an associative array.

2018-04-19 Thread Giles Bathgate via Digitalmars-d

On Wednesday, 18 April 2018 at 21:04:53 UTC, Jordan Wilson wrote:
Thinking seems sound, although having a name starting with 
"get" does have the advantage of being more related to the 
existing get.


Ah yes, good point. I think now we've had the discussion about 
other use cases though that ultimately there might need to be an 
"atomic" AddOrUpdate style function too, which I was thinking 
could just be called 'update'. The necessity to keep them all 
starting with get seemed less important.


Re: Feature to get or add value to an associative array.

2018-04-18 Thread Jordan Wilson via Digitalmars-d

On Wednesday, 18 April 2018 at 17:19:45 UTC, Giles Bathgate wrote:

On Sunday, 15 April 2018 at 22:55:41 UTC, Giles Bathgate wrote:

Time for a bikeshed discussion...


I have had some thoughts about the name and would like to share 
my idea.


Firstly to summarise here are the names that have been 
found/discussed so far:


C#   : GetOrAdd
Java : computeIfAbsent
Python   : setdefault
Rust : entry(key).or_insert_with

Jordan Wilson: getOrAdd, getOrSet
User1234 : valueOrDefault
Nicholas Wilson  : getOrInsert
Steven Schveighoffer : getPtr, getRef, getInitialized
Nick Treleaven   : slot
MrSmith  : getOrCreate

My latest idea is just a working title, but I think I prefer it 
to my original getOrAdd.


Giles Bathgate   : require

My thinking is that if you `require` there to be a value in the 
associative array, then you should have the ability to add one 
iff it doesn't exist. It name also has parallels with the term 
in other programming languages to require a module, meaning to 
import it if it hasn't already been loaded.


Thinking seems sound, although having a name starting with "get" 
does have the advantage of being more related to the existing get.


Weirdly, in all cases if I replace "Or" with "Else", it seems to 
read easier for me... getElseAdd, getElseCreate, etc.


Ultimately I'm not too bothered with any name really, I'm just 
looking forward to using it eventually :-)


Jordan


Re: Feature to get or add value to an associative array.

2018-04-18 Thread Giles Bathgate via Digitalmars-d

On Sunday, 15 April 2018 at 22:55:41 UTC, Giles Bathgate wrote:

Time for a bikeshed discussion...


I have had some thoughts about the name and would like to share 
my idea.


Firstly to summarise here are the names that have been 
found/discussed so far:


C#   : GetOrAdd
Java : computeIfAbsent
Python   : setdefault
Rust : entry(key).or_insert_with

Jordan Wilson: getOrAdd, getOrSet
User1234 : valueOrDefault
Nicholas Wilson  : getOrInsert
Steven Schveighoffer : getPtr, getRef, getInitialized
Nick Treleaven   : slot
MrSmith  : getOrCreate

My latest idea is just a working title, but I think I prefer it 
to my original getOrAdd.


Giles Bathgate   : require

My thinking is that if you `require` there to be a value in the 
associative array, then you should have the ability to add one 
iff it doesn't exist. It name also has parallels with the term in 
other programming languages to require a module, meaning to 
import it if it hasn't already been loaded.


Re: Feature to get or add value to an associative array.

2018-04-18 Thread ag0aep6g via Digitalmars-d

On 04/18/2018 11:41 AM, Nick Treleaven wrote:

How do you implement this if the function returns with ref:

bool inserted;
auto p = aa.slot("key", );
if (inserted) {
   ...
   // set *p
}
else {
   // read *p
   ...
   // set *p
}


You can get a pointer from the ref return:

Value* p = ("key", { inserted = true; return Value.init; });

Then do with the pointer whatever you want.


Re: Feature to get or add value to an associative array.

2018-04-18 Thread Giles Bathgate via Digitalmars-d

On Wednesday, 18 April 2018 at 09:41:48 UTC, Nick Treleaven wrote:

How do you implement this if the function returns with ref:


I understand where you are coming from, but I am not sure it is 
appropriate to shoehorn every use case into one api. I think 
actually what you are describing here is the AddOrUpdate style 
method 
https://msdn.microsoft.com/en-us/library/ee378665(v=vs.110).aspx


Perhaps the implementation could be:

void createOrUpdate(K, V)(ref V[K] aa, K key, V delegate() 
create, void delegate(V*) update);



C newc;
aa.createOrUpdate("key", {
/* set *p */
newc = new C;
return newc;
},
(C* u){
// read *p
newc = *u;
// set *p
*u = new C;
});
assert(aa["key"] == newc);

¯\_(ツ)_/¯


Re: Feature to get or add value to an associative array.

2018-04-18 Thread Nick Treleaven via Digitalmars-d
On Tuesday, 17 April 2018 at 20:49:30 UTC, Steven Schveighoffer 
wrote:

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


Wouldn't an extra function call have to happen, at least in some 
cases?


This pattern needs a pointer to be returned, instead of using 
`ref`. Note that `` 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.


How do you implement this if the function returns with ref:

bool inserted;
auto p = aa.slot("key", );
if (inserted) {
  ...
  // set *p
}
else {
  // read *p
  ...
  // set *p
}

There is a common basic use case for this - counting the 
occurrence of a key in a data set. If the key doesn't exist, 
initialize and insert the value. *Iff* it does exist, increment 
the value - I don't think you can do this without functional 
contortions with your ref return.


(A side benefit is that returning a pointer is consistent with 
`in`.)


Re: Feature to get or add value to an associative array.

2018-04-17 Thread Giles Bathgate via Digitalmars-d

On Tuesday, 17 April 2018 at 21:40:55 UTC, Giles Bathgate wrote:

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


Of course, a rustic API could be built atop this PR:

template entry(K, V)
{
static struct Entry
{
alias get this;
V[K] aa;
K key;
V get()
{
return aa[key];
}
V orInsert()
{
return aa.getOrAdd(key);
}
V orInsertWith(lazy V value = V.init)
{
return aa.getOrAdd(key, value);
}
}

Entry entry(ref V[K] aa, K key)
{
return Entry(aa,key);
}
}


void main()
{
class C{}
C[string] aa;
auto v1 = aa.entry("foo");
auto v2 = aa.entry("bar").orInsert();
auto v3 = aa.entry("baz").orInsertWith(new C);
}

But I think, this would be out of scope.




Re: Feature to get or add value to an associative array.

2018-04-17 Thread Giles Bathgate via Digitalmars-d
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


Re: Feature to get or add value to an associative array.

2018-04-17 Thread Steven Schveighoffer via Digitalmars-d

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 `` 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


Re: Feature to get or add value to an associative array.

2018-04-17 Thread Giles Bathgate via Digitalmars-d

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.






Re: Feature to get or add value to an associative array.

2018-04-17 Thread MrSmith via Digitalmars-d

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


Re: Feature to get or add value to an associative array.

2018-04-17 Thread Giles Bathgate via Digitalmars-d

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.


Re: Feature to get or add value to an associative array.

2018-04-17 Thread Nick Treleaven via Digitalmars-d

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", );
if (inserted) {
  ...
  *p = new Value(...);
}
// use *p

This pattern needs a pointer to be returned, instead of using 
`ref`. Note that `` 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.


Re: Feature to get or add value to an associative array.

2018-04-17 Thread Giles Bathgate via Digitalmars-d

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 ;)






Re: Feature to get or add value to an associative array.

2018-04-17 Thread Steven Schveighoffer via Digitalmars-d

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


Re: Feature to get or add value to an associative array.

2018-04-17 Thread Giles Bathgate via Digitalmars-d

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-


Re: Feature to get or add value to an associative array.

2018-04-17 Thread Giles Bathgate via Digitalmars-d

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.




Re: Feature to get or add value to an associative array.

2018-04-16 Thread Nicholas Wilson via Digitalmars-d

On Tuesday, 17 April 2018 at 00:04:32 UTC, Cym13 wrote:

auto value = ptr ? *ptr : *ptr = default;


That is going to crash if ptr is null.

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.


I think `getOrInsert` is a good name for this function


Re: Feature to get or add value to an associative array.

2018-04-16 Thread Cym13 via Digitalmars-d

On Monday, 16 April 2018 at 18:59:54 UTC, Giles Bathgate wrote:

On Monday, 16 April 2018 at 12:41:07 UTC, JN wrote:
It's only one additional "in", but makes the code more 
explicit and clear. I think in most cases, you will want to 
check if you are dealing with a fetched object or a default 
created one, so that will complicate the function even further.


You can still use a combination of `in` and the update syntax 
if you want, this doesn't take that away. In the future, for a 
concurrent implementation of associative arrays, a way of 
getting or adding an element as an atomic operation becomes 
more important. Either way the beauty of hashed based lookups 
is that they average O(1), seems a shame to double that up for 
no reason ;)


"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;

// to set default value on the fly
auto value = ptr ? *ptr : *ptr = default;

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.


Re: Feature to get or add value to an associative array.

2018-04-16 Thread user1234 via Digitalmars-d

On Sunday, 15 April 2018 at 22:55:41 UTC, Giles Bathgate wrote:

On Sunday, 15 April 2018 at 22:52:47 UTC, Giles Bathgate wrote:

I am proposing a new function called getOrAdd in


I posted details of the PR here because at least 2 people do 
not like the name getOrAdd (and one of those people being 
myself)


Time for a bikeshed discussion...


It's hard to name... I cant find better than "valueOrDefault"


Re: Feature to get or add value to an associative array.

2018-04-16 Thread Giles Bathgate via Digitalmars-d

On Monday, 16 April 2018 at 12:41:07 UTC, JN wrote:
It's only one additional "in", but makes the code more explicit 
and clear. I think in most cases, you will want to check if you 
are dealing with a fetched object or a default created one, so 
that will complicate the function even further.


You can still use a combination of `in` and the update syntax if 
you want, this doesn't take that away. In the future, for a 
concurrent implementation of associative arrays, a way of getting 
or adding an element as an atomic operation becomes more 
important. Either way the beauty of hashed based lookups is that 
they average O(1), seems a shame to double that up for no reason 
;)


Re: Feature to get or add value to an associative array.

2018-04-16 Thread JN via Digitalmars-d

On Sunday, 15 April 2018 at 22:52:47 UTC, Giles Bathgate wrote:

Hi,

I wanted a way to lazily insert a value into an associative 
array, and I am proposing a new function called getOrAdd in  
https://github.com/dlang/druntime/pull/2162


I am not sure if it's a good idea to combine accessor and 
insertion in a same method call. Is it really such a big overhead 
to do "if in assocarray then take else create new"? It's only one 
additional "in", but makes the code more explicit and clear. I 
think in most cases, you will want to check if you are dealing 
with a fetched object or a default created one, so that will 
complicate the function even further.




Re: Feature to get or add value to an associative array.

2018-04-16 Thread bauss via Digitalmars-d

On Monday, 16 April 2018 at 03:42:18 UTC, Jordan Wilson wrote:

On Sunday, 15 April 2018 at 22:55:41 UTC, Giles Bathgate wrote:

On Sunday, 15 April 2018 at 22:52:47 UTC, Giles Bathgate wrote:

I am proposing a new function called getOrAdd in


I posted details of the PR here because at least 2 people do 
not like the name getOrAdd (and one of those people being 
myself)


Time for a bikeshed discussion...


I think Adding a Yes.add flag to the existing get makes sense, 
but property functions only have max 2 args.


S...getOrAdd or getOrSet would be my pick.

Jordan


I'm opposed to flags. I hate the whole "yes" "no" thing when it 
comes to such things, just like the "true" "false"... It's a no 
go for me.


A function name that fits would be perfect in my opinion.



Re: Feature to get or add value to an associative array.

2018-04-16 Thread Giles Bathgate via Digitalmars-d

On Monday, 16 April 2018 at 03:42:18 UTC, Jordan Wilson wrote:

I think Adding a Yes.add flag to the existing get makes sense


That's an interesting idea. I forgot to mention that getOrAdd is 
a mutable function whereas get is inout, so that might also be 
problematic.





Re: Feature to get or add value to an associative array.

2018-04-15 Thread Jordan Wilson via Digitalmars-d

On Sunday, 15 April 2018 at 22:55:41 UTC, Giles Bathgate wrote:

On Sunday, 15 April 2018 at 22:52:47 UTC, Giles Bathgate wrote:

I am proposing a new function called getOrAdd in


I posted details of the PR here because at least 2 people do 
not like the name getOrAdd (and one of those people being 
myself)


Time for a bikeshed discussion...


I think Adding a Yes.add flag to the existing get makes sense, 
but property functions only have max 2 args.


S...getOrAdd or getOrSet would be my pick.

Jordan


Re: Feature to get or add value to an associative array.

2018-04-15 Thread Giles Bathgate via Digitalmars-d

On Sunday, 15 April 2018 at 22:52:47 UTC, Giles Bathgate wrote:

I am proposing a new function called getOrAdd in


I posted details of the PR here because at least 2 people do not 
like the name getOrAdd (and one of those people being myself)


Time for a bikeshed discussion...