The evils of __traits(compiles)

H. S. Teoh hsteoh at quickfur.ath.cx
Thu Jan 21 20:27:36 UTC 2021


Ran into this today: was submitting a PR for the ddbus package, which
has a function .registerMethods that allows automatic registration of
DBus methods by introspecting a class object, and generating the
appropriate setHandler calls to the router object.  Since not all method
signatures can be supported by DBus, .registerMethods uses
__traits(compiles) as a quick way of determining whether setHandler is
usable on a particular method (unsupported methods will not compile when
passed to setHandler, so they will be skipped).

Unfortunately, my PR touches one of the functions used by setHandler. A
typo caused a compile error inside setHandler itself, but since
__traits(compiles) does not distinguish between errors caused by the
candidate method and errors inside setHandler itself, the erroneous code
simply caused *all* methods to be skipped -- silently.  The problem
would not be noticed until runtime when some methods mysteriously go
missing. :-(

This problem isn't specific to ddbus; I've run into this in a lot of D
code that's heavy on compile-time introspection.  __traits(compiles) is
a quick and easy way of getting code to work, but it inevitably leads to
pain because of the way it gags *all* compile errors, including the ones
you didn't expect and probably should be reported.

tl;dr: __traits(compiles) is evil, and should be avoided. Unless you
*really* mean, literally, "does this piece of code compile", and you're
not using that as a stand-in for some other intended semantics (like
"does X conform to Y's signature constraints" or some such).  SFINAE is
evil. >:-(


T

-- 
Unix is my IDE. -- Justin Whear


More information about the Digitalmars-d mailing list