Optional parameters are a great tool for building flexible APIs. In most languages, they're not strictly necessary- if you have function overloading, the difference between optional parameters and an overloaded function is just the quantity of boilerplate- but they're certainly a nice to have.

Well, they're a nice to have in the right hands.

Scattered through their code base, Ian P saw many, many calls to dutData.GetMessages(). As they explored the code base, they used Visual Studio's "go to definition" feature to jump to the implementation- and found they were sometimes ending up in different spots.

public static IEnumerable<string> GetMessages(this ScreenScraper screenScraper) { //Do some stuff to get the messages } //snip 100+ lines public static IEnumerable<string> GetMessages(this ScreenScraper screenScraper, long timeSpane = 30000, int timeInterval = 500) { //Do some different stuff to get the messages }

Frankly, I'm a little surprised that this is even possible. It offered warnings, but no errors, presumably because this is an odd bit of syntactic sugar in C# called "extension methods", which are C#'s answer to "monkey patching". Neither GetMessages is actually a member of ScreenScraper, but if you call GetMessages on a ScreenScraper object, C# will call GetMessages and pass an instance of ScreenScraper into it.

The C# compiler is the real WTF. As for Ian, the fix was simple: rename some methods for clarity, and convert extensions to instance methods as appropriate.

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!