Package com.apple.foundationdb.util
Interface Lens<C,A>
- Type Parameters:
C- the container ("whole") typeA- the attribute ("part") type focused by this lens
public interface Lens<C,A>
A typed "focus" on a part
A sitting inside a whole C — the object-oriented
shape of the well-known functional lens. A Lens<C, A> carries two operations:
a get that extracts the inner A from a C, and a
set that produces an updated C (or a fresh one) with a
new inner A.
Where this useful is when generic library code needs to operate on the A
inside caller-supplied Cs without forcing the caller to unwrap everything
upfront and re-wrap afterward. The caller passes a lens that knows how to peek at and rebuild
their domain object; the library stays oblivious to C beyond the lens.
Example
Suppose the caller has labeled vectors and wants to hand them to a generic clustering API that only cares about the geometric vector inside each one:
record Labeled(String name, RealVector vector) {}
Lens<Labeled, RealVector> vectorLens = new Lens<>() {
public RealVector get(Labeled c) {
return c.vector();
}
public Labeled set(Labeled c, RealVector v) {
// c == null signals "no existing container, build a fresh one from a"
return new Labeled(c == null ? "" : c.name(), v);
}
};
// Library code can now generically work over List<Labeled> without ever importing Labeled:
RealVector v = pointLens.getNonnull(record); // peek
Labeled updated = pointLens.set(record, normalized); // replace
Labeled wrapped = pointLens.wrap(newVector); // build fresh
Labeled scaledByTwo = pointLens.map(record, p -> p.multiply(2.0d)); // read-modify-write
Composition
Lenses compose:compose(Lens) chains a downstream lens so the result focuses through
two layers at once. For example, outerLens.compose(innerLens) produces a lens that
reaches the inner A2 of an inner A inside an outer C.
identity() returns the trivial lens whose container and part are the same type — useful
as a default argument when the caller's input is the attribute.
Contract
getmay returnnullif the implementation models an absent attribute. UsegetNonnullas a convenience when the caller is sure the attribute is present.setaccepts a nullableC:set(null, a)is the "construct a new container arounda" case, surfaced as the more readablewrap.- Implementations are expected to be pure functions of their inputs (no shared mutable
state). Whether
setreturns a fresh container or mutatescis up to the implementation; callers should always use the returned value rather than assume identity with the argument.
-
Method Summary
Modifier and TypeMethodDescriptionReturns a lens that focuses through this lens and then throughdownstream, so the resulting lens reaches the inner attributeA2of an innerAinside aC.static <T1,T2> List <T2> Convenience for the common batch-extract pattern: appliesgetNonnull(Object)to every element ofelementsand collects the results into a fresh immutable list.Extracts the focused attribute fromc.default AgetNonnull(C c) Likeget(Object)but throwsNullPointerExceptionif the attribute is missing.static <T> Lens<T, T> identity()The identity lens: container and attribute are the same type and the lens is a no-op pair ofget(t) -> tandset(t, t2) -> t2.default Cmap(C c, UnaryOperator<A> operator) Read-modify-write: extracts the attribute, appliesoperator, and returns a container with the result.Returns a container equivalent tocbut with the focused attribute set toa.default CBuilds a fresh container arounda— equivalent toset(null, a)but reads more naturally at the call site when there is no existing container to update.
-
Method Details
-
getNonnull
Likeget(Object)but throwsNullPointerExceptionif the attribute is missing. Use when the caller is certain the attribute is present and wants the non-null type to flow through downstream code.- Parameters:
c- the container; must not benull- Returns:
- the extracted attribute, never
null - Throws:
NullPointerException- ifget(c)returnsnull
-
get
Extracts the focused attribute fromc.- Parameters:
c- the container; must not benull- Returns:
- the attribute, or
nullif the implementation models an absent attribute
-
wrap
Builds a fresh container arounda— equivalent toset(null, a)but reads more naturally at the call site when there is no existing container to update.- Parameters:
a- the attribute to wrap; may benullif the implementation supports containers without the attribute- Returns:
- a non-null container holding
a
-
set
Returns a container equivalent tocbut with the focused attribute set toa. Passingnullforcsignals "no existing container, build a fresh one arounda" — implementations are expected to handle this case, typically with a default for the unfocused parts of the container.- Parameters:
c- the existing container to update, ornullto construct a fresh onea- the new value of the focused attribute; may benullif the implementation supports containers without the attribute- Returns:
- a non-null container with the attribute set to
a
-
map
Read-modify-write: extracts the attribute, appliesoperator, and returns a container with the result. Reference-equality short-circuits: ifoperatorreturns the same instance it received,citself is returned with no call toset.- Parameters:
c- the container; must not benulloperator- transformation applied to the extracted attribute- Returns:
- a container reflecting the transformed attribute, possibly
citself
-
compose
Returns a lens that focuses through this lens and then throughdownstream, so the resulting lens reaches the inner attributeA2of an innerAinside aC. The composed lens'ssetimplements the standard lens-composition law: get the intermediateA, applydownstream.setto embeda2into it, then write the newAback intoc.- Type Parameters:
A2- the deeply focused attribute type- Parameters:
downstream- the inner lens that focuses from the intermediateAontoA2- Returns:
- a composed lens from
CtoA2
-
identity
The identity lens: container and attribute are the same type and the lens is a no-op pair ofget(t) -> tandset(t, t2) -> t2. Handy as a default argument when the caller's input is already the attribute type, or to seed achain.- Type Parameters:
T- shared container/attribute type- Returns:
- a lens that focuses each element on itself
-
extract
Convenience for the common batch-extract pattern: appliesgetNonnull(Object)to every element ofelementsand collects the results into a fresh immutable list. Equivalent to a streams pipeline but skips the boilerplate and preserves order.- Type Parameters:
T1- the source ("container") element typeT2- the extracted ("attribute") type- Parameters:
lens- the lens to apply to each elementelements- the source list- Returns:
- an immutable list of extracted attributes in source order; never
null - Throws:
NullPointerException- if any element extraction yieldsnull
-