The type Variable<T> expresses a virtualized location which stores a mutable value.
A key use case is modeling the value of a Map at a given key.
It is like the type Optional<T>, except that it has a put() method as well.
Optionality is important for some use cases, so it needs an isPresent method.
Cancelling an isPresent state requires a remove method also.
Supporting methods in Map, List, ListIterator, and other types would provide Variables at keyed, indexed, or cursor locations. Suggest a term like 'of' or 'sub' to mimic subscripting to produce Variables in appropriate contexts. Multiply-indexed structures (like matrix or Map2<J,K,V>) or constrained structures (like bidirectional maps) could use Variables to avoid replication of many similar methods for update.
Many of the default get/set methods on Map can be factored into a Variable type, making those patterns usable over a wider scope. A key example is putIfAbsent(Supplier<V>) returning V. (Note that the 'key' parameter from Map is irrelevant.) The "IfAbsent" part of the name could be elided, as in the example below.
One application of both Variables and the current Map methods is auto-vivification http://en.wikipedia.org/wiki/Autovivification . This assists attempts like the following:
Map<J, Map<K, List<V>>> bimap = ...;
bimap.get(j).get(k).add(v); // BAD NPE
...to work as follows:
bimap.of(j).get(TreeMap<>::new).of(k).get(ArrayList<>::new).add( v)
One problem with the idea of a Variable is that it does not have crisp natural boundaries. It has optional edge-concepts like transactionality or synchronization which may perhaps need support in the API. For example, what does the Variable<Integer> version of "a += b" look like? Map.compute provides a hint.
The Variable type is likely to interact (at least as a design influence) with any possible overloading of the a[b] operator, since that operator produces l-values (variable references).
A key use case is modeling the value of a Map at a given key.
It is like the type Optional<T>, except that it has a put() method as well.
Optionality is important for some use cases, so it needs an isPresent method.
Cancelling an isPresent state requires a remove method also.
Supporting methods in Map, List, ListIterator, and other types would provide Variables at keyed, indexed, or cursor locations. Suggest a term like 'of' or 'sub' to mimic subscripting to produce Variables in appropriate contexts. Multiply-indexed structures (like matrix or Map2<J,K,V>) or constrained structures (like bidirectional maps) could use Variables to avoid replication of many similar methods for update.
Many of the default get/set methods on Map can be factored into a Variable type, making those patterns usable over a wider scope. A key example is putIfAbsent(Supplier<V>) returning V. (Note that the 'key' parameter from Map is irrelevant.) The "IfAbsent" part of the name could be elided, as in the example below.
One application of both Variables and the current Map methods is auto-vivification http://en.wikipedia.org/wiki/Autovivification . This assists attempts like the following:
Map<J, Map<K, List<V>>> bimap = ...;
bimap.get(j).get(k).add(v); // BAD NPE
...to work as follows:
bimap.of(j).get(TreeMap<>::new).of(k).get(ArrayList<>::new).add( v)
One problem with the idea of a Variable is that it does not have crisp natural boundaries. It has optional edge-concepts like transactionality or synchronization which may perhaps need support in the API. For example, what does the Variable<Integer> version of "a += b" look like? Map.compute provides a hint.
The Variable type is likely to interact (at least as a design influence) with any possible overloading of the a[b] operator, since that operator produces l-values (variable references).