I would like the '+' operator to be polymorphic to support integer, float and so on. Why do we need '+.'?
Excellent question. There are many subtle trade-offs involved here.
The advantages of not overloading operators (as in OCaml) are:
- Type inference is simpler and more predictable.
- Code is more composable: moving code from one place to another cannot affect its meaning.
- Predictable performance: you always know exactly which function is being invoked.
The disadvantages are:
- Number of different operators quickly gets out of control:
+
for int
, +.
for float
, +/
for arbitrary-precision rationals, +|
for vectors, +||
for matrices and the complex numbers, low-dimensional vectors and matrices, homogeneous coordinates etc.
Some alternatives are:
- Closed ad-hoc polymorphism and equality types as in Standard ML: slightly more complicated type inference, code no longer composable but a good solution for a fixed number of pre-defined types.
- Open ad-hoc polymorphism and equality types as in F#: same as SML but can be applied to user-defined types as well. Expressive, fast and bug free but overloading is limited to certain operators and run-time resolution is prohibited.
- Type classes as in Haskell: expressive but complicated and unpredictably slow due to potential run-time resolution.
- Implicit promotion as in C/C++: simple but causes bugs like
2.3/0
and 1/12*3.7
.
- Dynamic typing as in Lisp's numerical tower: unpredictably slow.