Duck typing and safety.
Steven Schveighoffer
schveiguy at yahoo.com
Fri Aug 13 10:17:25 PDT 2010
On Fri, 13 Aug 2010 13:01:47 -0400, simendsjo <simen.endsjo at pandavre.com>
wrote:
> While reading std.range, I though that a ducktyping design without
> language/library support can be quite fragile.
>
> Consider the following example:
>
> import std.stdio;
>
> struct S
> {
> void shittyNameThatProbablyGetsRefactored() { };
> }
>
> void process(T)(T s)
> {
> static if( __traits(hasMember, T,
> "shittyNameThatProbablyGetsRefactored"))
> {
> writeln("normal processing");
> }
> else
> {
> writeln("Start nuclear war!");
> }
> }
>
>
> void main()
> {
> S s;
> process(s);
> }
>
>
> If you rename S's method, process() does something completely different
> without a compile time error. By using interfaces this is avoided as the
> rename would break the interface.
>
> Is there any idoms you can use to avoid stuff like this? Relying on
> documentation doesn't seem like a good solution.
You have somewhat missed the point of duck typing. It would look more
like this:
void process(T)(T s)
{
s.shittyNameThatProbabyGetsRefactored();
}
Basically, the point is, you compile *expecting* that you can call the
function, and then when the type doesn't have the function, it simply
fails.
Of course, the error you get is not what you want, because to the
compiler, it's not the call of the function that is the error, it's the
compiling of the function that is the error.
To remedy this, you use template constraints:
void process(T)(T s) if(__traits(hasMember, T,
"shittyNameThatProbabyGetsRefactored")
{
...
}
And then the compiler won't even try to compile the function, it just
fails at the call site.
-Steve
More information about the Digitalmars-d-learn
mailing list