Skip to content

Commit 4071a7a

Browse files
authored
Explain why Orphan Instances are forbidden (#313)
* Explain why Orphan Instances are forbidden * review feedback * Review feedback - Add explicit example * Fix uniqueness typo * Fix another uniques
1 parent 91c1283 commit 4071a7a

File tree

1 file changed

+7
-0
lines changed

1 file changed

+7
-0
lines changed

language/Type-Classes.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ instance semigroupAddInt :: Semigroup AddInt where
106106

107107
In fact, a type similar to this `AddInt` is provided in `Data.Monoid.Additive`, in the `monoid` package.
108108

109+
Orphan instances are banned because they can lead to incompatible duplicated instances for the same type and class. For example, suppose two separate modules define an orphan `Semigroup Int` instance, and one of them uses `+` for `append`, whereas the other uses `*`. Now suppose someone writes a third module which imports both of the first two, and that somewhere in that third module we have the expression `2 <> 3`, which calls for a `Semigroup Int` instance. The compiler now has two instances to choose from. What should it do? It could report an error, or it could arbitrarily pick one of the instances. Neither option is particularly appealing:
110+
111+
* If it chooses to report an error, it means that any pair of modules which define the same orphan instance can never be used together.
112+
* If it arbitrarily picks one, we won't be able to determine whether `2 <> 3` will evaluate to 5 or 6. This can make it very difficult to ensure that your program will behave correctly!
113+
114+
Banning orphan instances also ensures global uniqueness of instances. Without global uniqueness, you risk operating on data with incompatible instances in different sections of code. For example, in Ord-based maps and sets, if it were possible to insert some values into a map using one `Ord` instance, and then try to retrieve them using a different `Ord` instance, you'd have keys disappear from your map. Another example is if you had a type class which defined serialization and deserialization operations, you'd be able to serialize something with one instance and then try to deserialize it with a different incompatible instance.
115+
109116
For multi-parameter type classes, the orphan instance check requires that the instance is either in the same module as the class, or the same module as at least one of the types occurring in the instance. (TODO: example)
110117

111118
## Functional Dependencies

0 commit comments

Comments
 (0)