This is in contrast to say python where the convention is to rely heavily on exceptions as part of the normal flow of the code, sometimes described as "asking forgiveness, not permission". It is not uncommon for a method argument to support multiple types, and to discern them by treating the object like one type and if you get an exception, then try treating it like another type. Likewise, if you're not sure an item is in a dict, you just try to access it, and catch the exception if it isn't. This has performance impacts, but so does everything else about python, so it isn't worth optimizing.
Where I do think this pattern makes sense is in trying to use system resources. Checking that a file exists or a process is alive before deleting or killing it is a recipe for difficult to track down Time of Check to Time of Use bugs. I'm curious if you think this is also an anti-pattern in c++ and if so, how you properly deal with the TOCTU race conditions?
If the library you are using does throw exceptions, then I would probably start with just using exception handling. Then if I notice poor performance, add an initial check, purely as an optimization, while keeping the exception handling to deal with race condition.
So if you are trying to hold a lock you don't throw an exception, you just wait and try again. Perhaps you can't reach that host; try again a few tiles before giving up and throwing an exception. But if you try to write to removable media and the device won't open, all, your program isn't going to mount a tape itself: throw an exception and let the problem be handled at a higher level.
I would have not have thought an unreachable host was exceptional, given that it's quite normal.
The point is that handling the host unreachable is almost always semantically higher level than the code opening the connection. This the code opening doesn’t implement the policy of what to do when the situation occurs. In the case, say, of a hard-coded address then it’s possible the author of that piece of code does know how to handle a host unreachable case.
On the software abstraction, exceptions are simply a convenient implicit control flow device for handling the alternate path when an intended state cannot be achieved. I don't follow the paper's argument that "current exception design is suboptimal for efficient implementation" - but I would not be surprised considering the lifetime issues.
The argument of the paper is really that exception handling shouldn’t use a global lock, a problem made worse by the proliferation of processor cores on modern chips.
Btw, we don't say "exceptions are for infrequent conditions", because that's not what they're for.
I quite like the etymological "taken out", because it carries a notion of special handling - a control flow aspect that is the main point of using them.