← Contents · Runnable Specifications by Eric Normand · Work in progress · Comments
85
Structures
Alternative: choose one among many——86
Common encodings for alternatives—87
Combinations: a group of different values——88
Common encodings of combinations—89
Collections: multiple values90
Common encodings for collections—90
Mappings: convert one value to another91
Common encodings for mappings91
Count: numerical quantities——92
Common encodings for quantities—92
Identiers and names: unique reference93
Common encodings for identiers———93
Common encodings for names—93
Supplement
Data Lens
In this supplement, we detail several common relation-
ship structures that appear in the world along with lan-
guage features to encode them.
You can use this supplement in two ways. Treat this as
a reference for those structures and language features.
And use it as inspiration for understanding new struc-
tures and new language features you encounter.
86 Supplement
Alternative: choose one among many
type Payment = CreditCard |
GiftCard |
App |
Cash |
LoyaltyCard |
Gratis ;
Counting the states
Alternatives are modeled as a sum type, what mathemati-
cians call the structure of a “choice of one among many.
It is called a sum type because you calculate the number of
its states by adding the states of all of the alternatives.
For example, if we encode the payment as on the right,
we add up the states for CreditCard, GiftCard, App, etc.:
one of
Soymilk Espresso
Almond
Chocolate
Hazelnut
one of
Raw Burnt Charcoal
Roast
one of
Super Mega Galactic
Size Add In
one of
GratisLoyalty
card
Cash
App
Gift
card
Credit
card
Payment
Alternatives are a common pattern found in domains.
They denote a choice among several alternatives. Here are
some examples from the coffee shop:
statesOf(Payment) = statesOf(CreditCard) + statesOf(GiftCard) +
statesOf(App) + statesOf(Cash) +
statesOf(LoyaltyCard) + statesOf(gratis)
87Data Lens
Common encodings for alternatives
type DigitalPayment = CreditCard | GiftCard | App;
type AnalogPayment = Cash | LoyaltyCard | Comped;
type Payment = DigitalPayment | AnalogPayment;
interface Size {
name: string;
}
type Size = "super" |
"mega" |
"galactic";
Union type
enum Size {
super = "super",
mega = "mega",
galactic = "galactic",
}
Enum
Interface and classes
1
2
3
Natural numbers
Super
Mega
Galactic
Alternatives are encoded easily in most programming
languages. Here are some common language features that
share the “choice of one among many” structure. In this
case, we are encoding the size:
class Super implements Size {
name = "super";
}
class Mega implements Size {
name = "mega";
}
class Galactic implements Size {
name = "galactic";
}
We can encode alternatives as natural
numbers because natural numbers them-
selves are an alternative.
Numbers also have a natural ordering, like
size. The biggest mis-t is that the number
of sizes is nite while natural numbers are
innite.
type NatNumber = 1 | 2 | 3 | ...;
Remember, we can use these language features to encode
alternatives because they have the same “choose one
among many” structure as alternatives.
Adding structure
Sum types give us lots of options for how to encode an
alternative without losing t. Besides using a different
language feature, we could also introduce a new layer of
structure. For instance, we could encode payment like
this and get the same number of states:
88 Supplement
Combinations: a group of different values
Counting the states
Combinations are modeled as product type, what mathe-
maticians call the structure of “a combination of multiple
values.” It is called a product type because you calculate
the number of its states by multiplying the states of its
components.
For example, if we encode the coffee as on the right, we
multiply the states of size, roast, and add ins:
Payment
method
Barista
Delivery
method
Order
method
Coffees
Customer
all of
all of
Size Roast Add Ins
Combinations are a group of values of different kinds that
are “combined” together into a larger whole. We might say
that the structure of cominations are “all of” because they
require all values to make the whole.
Coffee Coffee order
type Coffee = {
size : Size;
roast : Roast;
addIns: AddIn[];
};
states(Coffee) = states(Size) × states(Roast) × states(AddIn[])
89Data Lens
Common encodings of combinations
TypeScript Object
TypeScript Tuple
C StructClojure map
TypeScript Class
Haskell data type
type Coffee = {
roast : Roast;
size : Size;
addIns: AddIn[];
};
type Coffee = [
Roast,
Size,
AddIn[]
];
struct Coffee {
Roast roast,
Size size,
AddIns addIns
};
{:roast :burnt
:size :super
:addIns [:espresso]}
class Coffee {
roast : Roast;
size : Size;
addIns: AddIn[];
};
data Coffee = Coffee {
roast :: Roast,
size :: Size,
addIns :: [AddIn]
}
Combinations are encoded easily in most programming
languages. It is very common to have a way to combine
multiple values together. Here are some common lan-
guage features that share the structure “a combination of
multiple values.
Remember, these features are good for encoding combi-
nations because they have the same structure as combi-
nations. Matching the structure is vital for having good t.
But it is not the only concern. Another important concern
is ergonomics. We’ll see other concerns in other lenses.
90 Supplement
Colle ctions: multiple values
Common encodings for collections
Collections share the some of structure. But that’s not
the whole story. Collections also have other structure, in-
cluding:
order - Is the order of the elements of the collection
important? How is it decided? Is it based on natural
order? Or is it based on the order the elements were
added?
duplicates - Are duplicates allowed in the collection?
containment check - Will you be checking if an item
is in the collection frequently? If so, you’ll want a
collection with constant-time (or near-constant-time)
containment check.
Set
no duplicates
no order
constant-time containment check
some are ordered based on insertion
order or natural order
Map/JS Object
key/value pairs
no duplicate keys
no order
constant-time containment check
some are ordered by key based on
insertion order or natural order
Array
ordered
duplicates allowed
List
ordered
duplicates allowed
some of
Collections are a group of values of the same kind. We’ll
call the structure of collections “some of.
some of some of
Add In Coffee
Customer
Add Ins Coffees Customers
91Data Lens
Mappings: convert one value to another
Common encodings for mappings
Mappings relate one kind of value to another. You have one
type and you can get another. Notice that it’s a one-way
relationship.
JS Object
string keys only
const sizePrice = {
super : 6,
mega : 7,
galactic: 8
};
sizePrice['super'] //=> 6
Map
any key type
const sizePrice = new Map([
['super' , 6],
['mega' , 7],
['galactic', 8]
]);
sizePrice.get('super') //=> 6
Function
arbitrary logic
function sizePrice(size) {
if(size === "galactic") {
return 8;
} else if(size === "mega") {
return 7;
} else if(size === "super") {
return 6;
} else {
throw "Unknown size";
}
}
sizePrice('super') //=> 6
Add In
Size Price
Price
Coupon
code
Discount
MAY2024
92 Supplement
Count: numerical quantities
Counts are numerical quantities. We use them all the time
and they deserve a little attention.
There are a number of questions we need to ask when we
encode counts:
What is the range of numbers you need?
Do you need integers, rational, or real numbers?
What decimal precision do you need?
Do you need negative numbers?
Do you need units?
Do you need to compare them for equality?
$ Amount % Discount Volume
Common encodings for quantities
Integers
whole numbers only
can choose signed or unsigned
range based on size
perfect precision
Floating point
decimal numbers
range and precision based on size
no equality comparison
rounding errors
Fixed Point
decimal numbers
xed precision
equality comparison
Combination with units
choose a number type
choose a unit
type MoneyAmount = {
amount : number;
currency: Currency;
};
93Data Lens
Identiers and names: unique reference
Common encodings for names
Common encodings for identiers
Integers
serial/ordered
plentiful
UUID
hard to guess
generate in parallel
Strings
easily serialized
Symbols/Keywords
avoid string operations
Namespacing
We can avoid name collisions by prexing
a name with a namespace, another name
that subdivides the space of names.
"size/medium"
"roast/medium"
We often need to refer to a thing in the real world and dis-
tinguish it from other similar things. For instance, we give
users a username to distinguish the user from all others.
Likewise, we give a bank account a number so we can refer
to it. To do that, we use identiers and names. The main
difference between them is that names are human-read-
able.
Identiers Names
Username
Bank
account #
Order # Student ID
License Plate
Size Roast
Add In
Coupon
code
MAY2024
Strings
letters and digits