It's about the cardinality (number of possible values) of the compound type.
The cardinality of a product type is the product of the cardinalities of its constituents. Likewise a sum type's cardinality is the sum of the cardinalities of its constituents.
Examples:
- a struct with a boolean and an 8-bit integer as its members. A boolean has 2 possible values, the integer has 256 possible values. So the struct has 2x256 = 512 values in total. So a struct is a product type.
- an Optional<int8> is either Some(n: int8) or None. The first one has 256 possible values, the second has one possible value. So the Optional<int8> has 256+1 = 257 values in total. So Optional<...> is a sum type.
Why does this matter? Because when modelling problems it's very nice if you come up with a representation where the number of legal states in the domain exactly matches the number of states of the type. It's awkward and confusing to have possible states of the type that are redundant or don't correspond to anything real. e.g. Golang's error handling uses what is morally a product type like (value, err) := foo(). What does it mean if both value and err are non-nil? That's prohibited only by convention, not the language. The type is "too big". But with sum types we can have Result<value, error>, where it can be a value or an error but not both, guaranteed by the compiler.
The cardinality of a product type is the product of the cardinalities of its constituents. Likewise a sum type's cardinality is the sum of the cardinalities of its constituents.
Examples:
- a struct with a boolean and an 8-bit integer as its members. A boolean has 2 possible values, the integer has 256 possible values. So the struct has 2x256 = 512 values in total. So a struct is a product type.
- an Optional<int8> is either Some(n: int8) or None. The first one has 256 possible values, the second has one possible value. So the Optional<int8> has 256+1 = 257 values in total. So Optional<...> is a sum type.
Why does this matter? Because when modelling problems it's very nice if you come up with a representation where the number of legal states in the domain exactly matches the number of states of the type. It's awkward and confusing to have possible states of the type that are redundant or don't correspond to anything real. e.g. Golang's error handling uses what is morally a product type like (value, err) := foo(). What does it mean if both value and err are non-nil? That's prohibited only by convention, not the language. The type is "too big". But with sum types we can have Result<value, error>, where it can be a value or an error but not both, guaranteed by the compiler.