2022-02-16 00:53:01 -05:00
|
|
|
|
---
|
|
|
|
|
title: Duck Typing
|
2022-05-06 22:49:33 -04:00
|
|
|
|
...
|
2022-02-16 00:53:01 -05:00
|
|
|
|
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.
|