362b7e653c
Which affected all documentation files.
97 lines
5.0 KiB
Markdown
97 lines
5.0 KiB
Markdown
---
|
||
title: Duck Typing
|
||
...
|
||
Assume naming system based on Zooko’s triangle. At what point should
|
||
human readable names with mutable and context dependent meanings be nailed
|
||
down as globally unique identifiers?
|
||
|
||
The most flexible, most convenient, most powerful, most general, and thus
|
||
most prone to disaster form of run time typing is duck typing, wherein the
|
||
human readable name gets translated on the fly in the run time context,
|
||
and the run time context is whatever is on the end users machine.
|
||
|
||
The optimal, most powerful, most powerful, most convenient typing that is
|
||
safe is duck typing that defaults to *compile time* translation of
|
||
human readable type identifiers into globally unique type identifiers,
|
||
translating using the environment present on the end user’s machine.
|
||
|
||
The generality of run time duck typing is dangerous when you expect your
|
||
program to run on someone else’s machine.
|
||
|
||
In fact it is dangerous even on your own machine. Python executing duck
|
||
typed code produces surprising and strange results. C++ refuses to compile it
|
||
without endless incomprehensible boilerplate. Haskel, on the other hand, for
|
||
all its faults, just simply does as you thought you were telling it to do.
|
||
|
||
Python’s duck typing causes endless install grief. Once a complex program
|
||
moves away from its home environment, endless install problems arise,
|
||
because the objects returned are not exactly the objects expected.
|
||
Successive versions of the API return objects that look less and less like
|
||
the previous versions.
|
||
|
||
This, of course, is exactly the problem that COM and its successor NET
|
||
quite successfully solved, but the solution relies on compilation. The
|
||
compiled code running on a newer API is guaranteed to receive the sort of
|
||
objects that the compile time API would have given it or fail cleanly, even
|
||
though the api and the compiled code were compiled by different people on
|
||
different and dissimilar machines.
|
||
|
||
Sometimes you want run time typing for flexibility, some times you don’t.
|
||
|
||
If your program is going to be used in foreign environment, you usually
|
||
want types identified by human readable names, which can stand for many
|
||
things, translated into types identified into globally unique identifiers
|
||
by the translation environment on your machine, the machine on which you
|
||
are debugging the code, rather than the end user’s machine. Duck typing is
|
||
optimal when developing code that will only run on your own machine in
|
||
your own environment.
|
||
|
||
Source code, therefore, should come with libraries mapping human readable names
|
||
to the globally unique type names on which that source code was tested and
|
||
depends.
|
||
|
||
The greatest flexibility is to have choice as to when local names will be
|
||
bound to globally unique identifiers, compile time, or run time. To avoid
|
||
install hell, should default to compile time, except where run time duck
|
||
typing is explicitly invoked..
|
||
|
||
Forty nine times out of fifty the compiler can type objects better than
|
||
you can, and ninety nine times out of a hundred the run time can type
|
||
objects better than you can, and with vastly less effort, but it is that
|
||
one time out of fifty, and the one time out of a hundred, that bites you.
|
||
|
||
Haskel has by far the best duck typing system, producing predictable,
|
||
expected, and intended results, without rigidity or incomprhensible boiler
|
||
plate, unlike C++ metacode. The programmer expresses his intention in a
|
||
programmer intuitive way, and Haskel correctly divines his intent, translates
|
||
into rigid compile time types as appropriate to the situation, or produces a
|
||
relevant type error.
|
||
|
||
The C++11 `auto` type and `decltype` are sort of
|
||
compile time duck typing, steps in that direction. `Decltype`
|
||
is duck typing inside the elaborate C++ straitjacket. If `auto`
|
||
references a `decltype`, that is pretty close to duck
|
||
typing. Real duck typing is doubtless a lot better, but it is
|
||
a good step.
|
||
|
||
However the C++11 `auto` and `decltype`
|
||
require you to explicitly write polymorphism into your code using the
|
||
convoluted complex template formalism and inheritance, whereas Python is
|
||
casually polymorphic by default – and thus apt to produce wildly unexpected results.
|
||
|
||
But even when you are not in fact supporting polymorphism, `auto`,
|
||
`decltype` and the C\# `var` find the correct types
|
||
better than you do, avoiding unintended type conversions, which are a huge
|
||
source of C++ bugs. So it is better to use auto and decltype
|
||
wherever possible,whenever you do not want to explicitly force type
|
||
conversion, wherever the exact type is not all that important to you.
|
||
|
||
Sometimes you really do care that this thing is a uint, it has got to be
|
||
a uint, we are taking advantage of the fact that it is a uint, and if we
|
||
turned it into a ulong or a short, or whatever, then the mechanism would
|
||
break. But usually, particularly with the more complex types,
|
||
the precise type is irrelevant noise and a useless distraction. You
|
||
generally want to know what is being done, not how it is being done.
|
||
Further, if you explicitly specify how it is being done, you are likely to
|
||
get it wrong, resulting in mysterious and disastrous type conversions.
|