“GetOrCreate” - does that idiom have an established name?
-
13-09-2019 - |
Question
Ok, consider this common idiom that most of us have used many times (I assume):
class FooBarDictionary
{
private Dictionary<String, FooBar> fooBars;
...
FooBar GetOrCreate(String key)
{
FooBar fooBar;
if (!fooBars.TryGetValue(key, out fooBar))
{
fooBar = new FooBar();
fooBars.Add(key, fooBar);
}
return fooBar;
}
}
Does it have any kind of established name?
(Yes, it's written in C#, but it can be "easily" transferred to C++. Hence that tag.)
Solution
Lazy Loading
OTHER TIPS
I always call such functions obtainSomething()
.
It sort of depends why you're doing it - the idiom is one I've seen be called memoization, caching, initialisation on demand, create on first use. Normally I call the method "ensureFoo" rather than "GetOrCreate"
I'm unsure of overall programming name for the high level pattern, but Perl has this wonderful behavior called Autovivification - namely, automatically creating hash (map) key with undefined value when you're querying the value of non-existing key in the hash.
In C#...
... I've got a DefaultingDictionary<> which does about this. As a bonus
- you can specify a default value or factory function to create values for missing keys:
- it comes with implicit conversion from IDictionary<> (wrapping the dictionary)
- it comes with extension methods to morph any dictionary into a DefaultingDictionary<> on the fly
Full Code:
The extensions .AsDefaulting
can be used to transparently use any IDictionary<>
as a defaulting one, so you can opt to use any dictionary (even e.g. obtained from a thirdparty API) as a defaulting one, and the underlying container will be updated with any 'auto-vivified' items.
Use it like
IDictionary<string, MyItem> dict = LoadFromDatabase();
// using a fixed value
SomeFunc(dict.AsDefaulting(defaultItem));
// using an independent generator function
var defaulting = dict.AsDefaulting(() => new MyItem { Id = System.Guid.NewGuid() });
// using a keydepedent generator function
var defaulting = dict.AsDefaulting(key => LazyLoadFromDatabase(key));
Some test cases
are included: