On Tuesday, 12 March 2013 at 16:28:14 UTC, Nick Sabalausky wrote:
"Happy accidents" is nothing more than another way of saying
"Shit
fucked up, but by pure dumb luck there was no damage". It's an
absolutely *terrible* thing to encourage and design for. You
may as
well just go dynamic all the way, a la ActionScript 2 or Python
- it's
all the same "let random things happen by accident and blindly
hope it
just happens to turn out correct" philosophy.
Design-by-accident is an anti-pattern.
To me more specific, the problem with duck typing is that it
falsely
assumes that name+signature uniquely defines semantics (which is
clearly not a valid assumption). Avoiding accidental screwups
under
duck typing *is* feasible if there's only a few well-known duck
types
that are ever in play (ex: our entire list of available duck
types is a
handful of phobos-defined ranges and basically nothing else).
But it
does not scale: The likelihood of accidental fuckups is
multiplied with
each additional duck type in existence, with non-stdlib duck
types
carrying a greater "accidental fuck up" weight.
I thought about this a bit more, and I agree with the fundamental
content of what you said.
The crux of the matter is that we can't specify new semantics
with code. We can only specify new semantics through
documentation. And compilers don't read documentations.
But, I think a good way to alleviate this problem would be to
allow programmers to specify that two different concepts are in
fact the same exact concept. Then two unrelated libraries could
be made interoperable with each other.
Example:
There are two unrelated libraries, LibA and LibB.
Library LibA defines:
1) concept ConceptA { ... }
2) void functionA(ConceptA A)(A a) { ... }
Library LibB defines:
1) concept ConceptB { ... }
2) void functionB(ConceptB B)(B b) { ... }
The two concepts, ConceptA and ConceptB, specify the same exact
concept (this can be verified only by reading their respective
documentations). If the end user now creates a type which
implements ConceptA:
struct MyStruct implements ConceptA { ... }
...then the problem is that instances of MyStruct can't be passed
to functionB. But, if the end-user has a way to say that ConceptA
is a synonym to ConceptB, then he can make the two libraries
interoperable with each other and with his own types. E.g:
concept ConceptA = ConceptB; // make them synonymous
struct MyStruct implements ConceptA { ... }
MyStruct ms;
functionB(ms); // OK
If ConceptA and ConceptB have happened to use different function
names for doing the same conceptual thing, then the end-user
should also be able to specify which function names are
synonymous with each other.