C++ guys hate static_if?

H. S. Teoh hsteoh at quickfur.ath.cx
Tue Mar 12 09:57:44 PDT 2013


On Tue, Mar 12, 2013 at 12:28:07PM -0400, Nick Sabalausky wrote:
> On Tue, 12 Mar 2013 16:02:24 +0100
> "TommiT" <tommitissari at hotmail.com> wrote:
> 
> > On Tuesday, 12 March 2013 at 13:44:35 UTC, Nick Sabalausky wrote:
> > > On Tue, 12 Mar 2013 12:51:03 +0100
> > > "TommiT" <tommitissari at hotmail.com> wrote:
> > >
> > >> On Tuesday, 12 March 2013 at 02:39:06 UTC, TommiT wrote:
> > >> > struct S1 implements A2 {
> > >> >     void foo() { }
> > >> >     void bar() { }
> > >> > }
> > >> 
> > >> That's not good. Types shouldn't have to explicitly say that 
> > >> they implement a concept.
> > >
> > > I *strongly* disagree. A much as I love ranges (for example),
> > > their duckiness is the one thing I consider to be a huge mistake.
> > 
> > The problem with having to explicitl specify that a type 
> > implements a certain concept, is the resulting strong coupling 
> > between the concept definition and the type. This prevents "happy 
> > accidents" like the following from happening:
> > 
> > Alice and Bob write libraries without knowing anything about each 
> > other or each other's code. Alice implements the following in her 
> > library:
> > 
> > concept IntegerLike {
> >      ...
> > }
> > 
> > void foo(IntegerLike N)(N n) { }
> > 
> > Bob implements the following in his library:
> > 
> > struct SafeInt {
> >      ...
> > }
> > 
> > Later Bob realizes that Alice has written this cool function foo 
> > which accepts his type SafeInt as an argument because SafeInt 
> > just so happens to fulfill the requirements of the IntegerLike 
> > concept defined in Alice's library.
> > 
> > Although, the majority of concepts should come from the standard 
> > library.
> 
> "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 see it from another perspective: I've had to deal with proprietary
libraries that defined types that couldn't be used with a particular
container type, just because the container type expects the item type to
implement a particular interface, but it doesn't. But actually, it
*does* have the requisite members to implement that interface; it just
didn't *say* it implemented that interface. So there's the need for Yet
Another Useless Java-style Wrapper Class just to work around this
nonsense. Duck-typing solves this problem.

Of course, full-out ducktyping has its own problems, like you said; but
there needs to be a way of rewriting APIs such that you could say "type
T doesn't implement interface I right now, but actually, if you rewrite
T.A to T.X and T.B to T.Y, then T implements interface I just fine".
Though with D, I suspect this may actually be possible via alias this:

	struct RewireInterface(T, Interface, Tuple!(string,string)... rewrites)
	{
		T t;
		alias t this;
		foreach (rewrite; rewrites) {
			alias rewrite[0] = rewrite[1];
		}
	}

OK, maybe not. But the foreach could be replace with a suitable
recursive template so that the generated aliases are at the top-level in
RewireInterface. Probably some other hack is needed to work around the
need for Tuple in the compile-time parameters, which I'm pretty sure DMD
rejects right now. But assuming all this can be worked around, you could
do something like this:

	struct StraitJacketedProprietaryItem {
		int propX() { ... }
		int propY() { ... }
	}

	concept MyInterface {
		int myX();
		int myY();
	}

	alias NonStraitJacketedItem = RewireInterface!(
		StraitJacketedProprietaryItem, MyInterface,
		"myX", "propX",
		"myY", "propY"
	);

	assert(NonStraitJacketedItem implements MyInterface);

OK, lots of pseudo-code going on here, but you get the idea.


T

-- 
It is widely believed that reinventing the wheel is a waste of time; but I disagree: without wheel reinventers, we would be still be stuck with wooden horse-cart wheels.


More information about the Digitalmars-d mailing list