1
0
forked from cheng/wallet
wallet/docs/duck_typing.md

5.0 KiB
Raw Blame History

title
Duck Typing

Assume naming system based on Zookos 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 users machine.

The generality of run time duck typing is dangerous when you expect your program to run on someone elses 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.

Pythons 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 dont.

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 users 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.