jastrachan | 16 Apr 14:10 2004

Re: New map helper method

On 16 Apr 2004, at 00:31, Bruce Chapman wrote:
>> Yes, I see what you mean. I suppose the best thing would be
>> to supply the default value handling closure could be
>> supplied when the map is created. I can't think of a good way
>> of doing that, though.
> Agreed, this behaviour is really a property of the instance of Map as a
> whole, not of the particular method call.

It could be, though this sounds like one specific kind of Map 
implementation - having the helper method means we can work with any 
map implementation.

> What about
> 	classmap.setMissingValueGenerator({[]})
>       ...
> 	classmap.get("classmethods").add(method)
> If setMissingValueGenerator() is never called, then get will return 
> null as
> currently.
> Presumably in this case, classmap.containsKey() would need to be 
> modified to
> always return true if setMissingValueGenerator() had been called. 
> Because
> according to my reading of the spec for java.util.Map.get() and
> java.util.Map.containsKey() then setMissingValueGenerator() would imply
> there was a mapping for every possible key.

Agreed though this then becomes a different kind of map - where the 
get() contract changes etc. Its now a 'growing on demand map'.

It may be better to implement this functionality as a specific Map 
Facade/Proxy which delegates to an underlying real Map but overloads 
the get() and containsKey() methods to allow this 'autovivication' to 
take place.

i.e. we could implement what you describe in a specific Map facade, 
which could proxy any Map implementation.

Then we could do things like

map = ['abc':123]

// wrap it in a facade that autovivicates
map = new AutoVivicateMap( map, { return [:] } )

// autovivicate
map.foo.bar = 123

The difference here is we have to explicitly wrap a map to enable this 
feature - rather like when we make a Map immutable or synchronized.

We could consider adding a helper method to wrap this up, so any Map 
can be easily converted into an autovivication map.

Already we can do
     map = map.immutable()

so how about

// lets make an auto-vivicating map which auto-creates nested maps
map = ['abc':123, 'x':'zzz'].autovivicate { return [:] }

map.x.y.z.whatever = 456