187Composition Lens
Example in code
JSON.parse() is the inverse of JSON.stringify():
let object = anyObject();
let asString = JSON.stringify(object);
let parsed = JSON.parse(asString);
assert(_.isEqual(object, parsed));
In the coee shop orders, removeAddIn() is the inverse of
addAddIn():
let coffee = anyCoffee();
let addIn = anyAddIn();
assert(_.isEqual(coffee.addAddIn(addIn).removeAddIn(addIn),
coffee));
Does the reverse hold? is addAddIn() the inverse of
removeAddIn()? Let’s write the test:
let coffee = anyCoffee();
let addIn = anyAddIn();
assert(_.isEqual(coffee.removeAddIn(addIn).addAddIn(addIn),
coffee));
If we can nd a single test case where this doesn’t hold, the prop-
erty doesn’t hold. What if coee has no add-ins?
let coffee = { size: "mega", roast: "burnt", addIns: {}};
Now when you remove an add-in, it’s a no-op (it does nothing).
But when you add the add-in aerwards, then it will have it. The
result will be:
{ size: "mega", roast: "burnt", addIns: { almond: 1 }}
When the coee does not have the add-in, the property does not
hold. But it does hold when it does have the add-in. This means we
can write a partial property:
let coffee = anyCoffee();
let addIn = anyAddIn();
if(coffee.hasAddIn(addIn))
assert(_.isEqual(coffee.removeAddIn(addIn)
.addAddIn(addIn),
coffee));
else assert(true);
We prefer total properties, but
this is probably as good as
you can get for this property.
Another option is to allow for
negative add-ins, which would
allow you to go below zero.
However, I don’t recommend
this because the resulting cof-
fee isn’t meaningful anymore.
What does it mean to have -3
soy milks?