Hacker News new | ask | show | jobs
by pavon 1580 days ago
In C++ the convention is that exceptions shouldn't be used for things you expect to happen in the normal execution of the program, in a way that would harm performance. For example, it is better to explicitly check if an item is in a map than to rely on exception handling to branch to the case where the item doesn't exist. Generating an exception for FileNotFound would be fine for a single file selected by the user in a UI, but you'd probably avoid it if checking for the existence of a large number of files based on a pattern. Most exceptions should either be a bug, or exhaustion of resources.

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.

1 comments

I'm not really a fan of this pattern in python. As far as I can tell, it's all done in the name of duck typing: if the returned object appears to have the right property, that's good enough. But the problem comes when take that object and pass it on to some other function. It may have appeared like a duck to you, but 10 functions later, it's slightly off and you get a difficult to understand TypeError or AttributeError.

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?

In C++ I would consider the best option in those cases would be for the function that performs the operation to return an error rather than throw an exception. That way you avoid the race condition, but also don't have to worry about the overhead of calling it in a tight loop.

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.