Which, and why, do you prefer Exceptions or Return codes?

Language AgnosticException

Language Agnostic Problem Overview


My question is what do most developers prefer for error handling, Exceptions or Error Return Codes. Please be language(or language family) specific and why you prefer one over the other.

I'm asking this out of curiosity. Personally I prefer Error Return Codes since they are less explosive and don't force user code to pay the exception performance penalty if they don't want to.

update: thanks for all the answers! I must say that although I dislike the unpredictability of code flow with exceptions. The answer about return code (and their elder brother handles) do add lots of Noise to the code.

Language Agnostic Solutions


Solution 1 - Language Agnostic

For some languages (i.e. C++) Resources leak should not be a reason

C++ is based on RAII.

If you have code that could fail, return or throw (that is, most normal code), then you should have your pointer wrapped inside a smart pointer (assuming you have a very good reason to not have your object created on stack).

Return codes are more verbose

They are verbose, and tend to develop into something like:

if(doSomething())
{
   if(doSomethingElse())
   {
      if(doSomethingElseAgain())
      {
          // etc.
      }
      else
      {
         // react to failure of doSomethingElseAgain
      }
   }
   else
   {
      // react to failure of doSomethingElse
   }
}
else
{
   // react to failure of doSomething
}

In the end, you code is a collection of idented instructions (I saw this kind of code in production code).

This code could well be translated into:

try
{
   doSomething() ;
   doSomethingElse() ;
   doSomethingElseAgain() ;
}
catch(const SomethingException & e)
{
   // react to failure of doSomething
}
catch(const SomethingElseException & e)
{
   // react to failure of doSomethingElse
}
catch(const SomethingElseAgainException & e)
{
   // react to failure of doSomethingElseAgain
}

Which cleanly separate code and error processing, which can be a good thing.

Return codes are more brittle

If not some obscure warning from one compiler (see "phjr" 's comment), they can easily be ignored.

With the above examples, assume than someone forgets to handle its possible error (this happens...). The error is ignored when "returned", and will possibly explode later (i.e. a NULL pointer). The same problem won't happen with exception.

The error won't be ignored. Sometimes, you want it to not explode, though... So you must chose carefully.

Return Codes must sometimes be translated

Let's say we have the following functions:

  • doSomething, which can return an int called NOT_FOUND_ERROR
  • doSomethingElse, which can return a bool "false" (for failed)
  • doSomethingElseAgain, which can return an Error object (with both the __LINE__, __FILE__ and half the stack variables.
  • doTryToDoSomethingWithAllThisMess which, well... Use the above functions, and return an error code of type...

What is the type of the return of doTryToDoSomethingWithAllThisMess if one of its called functions fail ?

Return Codes are not a universal solution

Operators cannot return an error code. C++ constructors can't, too.

Return Codes means you can't chain expressions

The corollary of the above point. What if I want to write:

CMyType o = add(a, multiply(b, c)) ;

I can't, because the return value is already used (and sometimes, it can't be changed). So the return value becomes the first parameter, sent as a reference... Or not.

Exception are typed

You can send different classes for each kind of exception. Ressources exceptions (i.e. out of memory) should be light, but anything else could be as heavy as necessary (I like the Java Exception giving me the whole stack).

Each catch can then be specialized.

Don't ever use catch(...) without re-throwing

Usually, you should not hide an error. If you do not re-throw, at the very least, log the error in a file, open a messagebox, whatever...

Exception are... NUKE

The problem with exception is that overusing them will produce code full of try/catches. But the problem is elsewhere: Who try/catch his/her code using STL container? Still, those containers can send an exception.

Of course, in C++, don't ever let an exception exit a destructor.

Exception are... synchronous

Be sure to catch them before they bring out your thread on its knees, or propagate inside your Windows message loop.

The solution could be mixing them?

So I guess the solution is to throw when something should not happen. And when something can happen, then use a return code or a parameter to enable to user to react to it.

So, the only question is "what is something that should not happen?"

It depends on the contract of your function. If the function accepts a pointer, but specifies the pointer must be non-NULL, then it is ok to throw an exception when the user sends a NULL pointer (the question being, in C++, when didn't the function author use references instead of pointers, but...)

Another solution would be to show the error

Sometimes, your problem is that you don't want errors. Using exceptions or error return codes are cool, but... You want to know about it.

In my job, we use a kind of "Assert". It will, depending on the values of a configuration file, no matter the debug/release compile options:

  • log the error
  • open a messagebox with a "Hey, you have a problem"
  • open a messagebox with a "Hey, you have a problem, do you want to debug"

In both development and testing, this enable the user to pinpoint the problem exactly when it is detected, and not after (when some code cares about the return value, or inside a catch).

It is easy to add to legacy code. For example:

void doSomething(CMyObject * p, int iRandomData)
{
   // etc.
}

leads a kind of code similar to:

void doSomething(CMyObject * p, int iRandomData)
{
   if(iRandomData < 32)
   {
      MY_RAISE_ERROR("Hey, iRandomData " << iRandomData << " is lesser than 32. Aborting processing") ;
      return ;
   }

   if(p == NULL)
   {
      MY_RAISE_ERROR("Hey, p is NULL !\niRandomData is equal to " << iRandomData << ". Will throw.") ;
      throw std::some_exception() ;
   }

   if(! p.is Ok())
   {
      MY_RAISE_ERROR("Hey, p is NOT Ok!\np is equal to " << p->toString() << ". Will try to continue anyway") ;
   }

   // etc.
}

(I have similar macros that are active only on debug).

Note that on production, the configuration file does not exist, so the client never sees the result of this macro... But it is easy to activate it when needed.

Conclusion

When you code using return codes, you're preparing yourself for failure, and hope your fortress of tests is secure enough.

When you code using exception, you know that your code can fail, and usually put counterfire catch at chosen strategic position in your code. But usually, your code is more about "what it must do" then "what I fear will happen".

But when you code at all, you must use the best tool at your disposal, and sometimes, it is "Never hide an error, and show it as soon as possible". The macro I spoke above follow this philosophy.

Solution 2 - Language Agnostic

I use both actually.

I use return codes if it's a known, possible error. If it's a scenario that I know can, and will happen, then there's a code that gets sent back.

Exceptions are used solely for things that I'm NOT expecting.

Solution 3 - Language Agnostic

According to Chapter 7 titled "Exceptions" in Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, numerous rationales are given for why using exceptions over return values is necessary for OO frameworks such as C#.

Perhaps this is the most compelling reason (page 179):

"Exceptions integrate well with object-oriented languages. Object-oriented languages tend to impose constraints on member signatures that are not imposed by functions in non-OO languages. For example, in the case of constructors, operator overloads, and properties, the developer has no choice in the return value. For this reason, it is not possible to standardize on return-value-based error reporting for object-oriented frameworks. An error reporting method, such as exceptions, which is out of band of the method signature is the only option."

Solution 4 - Language Agnostic

My preference (in C++ and Python) is to use exceptions. The language-provided facilities make it a well-defined process to both raise, catch and (if necessary) re-throw exceptions, making the model easy to see and use. Conceptually, it's cleaner than return codes, in that specific exceptions can be defined by their names, and have additional information accompanying them. With a return code, you're limited to just the error value (unless you want to define an ReturnStatus object or something).

Unless the code you're writing is time-critical, the overhead associated with unwinding the stack is not significant enough to worry about.

Solution 5 - Language Agnostic

Exceptions should only be returned where something happens that you were not expecting.

The other point of exceptions, historically, is that return codes are inherently proprietary, sometimes a 0 could be returned from a C function to indicate success, sometimes -1, or either of them for a fail with 1 for a success. Even when they are enumerated, enumerations can be ambiguous.

Exceptions can also provide a lot more information, and specifically spell out well 'Something Went Wrong, here's what, a stack trace and some supporting information for the context'

That being said, a well enumerated return code can be useful for a known set of outcomes, a simple 'heres n outcomes of the function, and it just ran this way'

Solution 6 - Language Agnostic

Always use exceptions by default, but consider providing an additional tester-doer option (TryX)! For me the answer is really clear. When the context dictates a Try or Tester-Doer pattern (ie cpu intensive or public api), I will ADDITIONALLY provide those methods to the exception throwing version. I think blanket rules of avoiding exceptions are misguided, unsupported, and likely cause far more expense in terms of bugs, than any performance issues they claim to prevent.

No, Microsoft DOES NOT say to not use exceptions (common misinterpretation).

It says if you're designing an API provide ways to help a user of that API to avoid THROWING exceptions if they need too (Try and Tester-Doer patterns)

> ❌ DO NOT use exceptions for the normal flow of control, if possible. > > Except for system failures and operations with potential race > conditions, framework designers should design APIs so users can write > code that does not throw exceptions. For example, you can provide a > way to check preconditions before calling a member so users can write > code that does not throw exceptions.

What is inferred here is that the non-tester-doer/non-try implementation SHOULD throw an exception upon failure and then the user CAN change that to one of your tester-doer or try methods for performance. Pit of success is maintained for safety and the user OPTS INTO the more dangerous but more performant method.

Microsoft DOES say to NOT use return codes TWICE, here:

> ❌ DO NOT return error codes. > > Exceptions are the primary means of reporting errors in frameworks. > > ✔️ DO report execution failures by throwing exceptions.

and here:

> ❌ DO NOT use error codes because of concerns that exceptions might > affect performance negatively. > > To improve performance, it is possible to use either the Tester-Doer > Pattern or the Try-Parse Pattern, described in the next two sections.

If you're not using exceptions you're probably breaking this other rule of returning return codes or booleans from a non-tester/non-try implementation. Again, TryParse does not replace Parse. It is provided in addition to Parse

MAIN REASON: Return codes fail the "Pit of Success" test for me almost every time.

  • It is far too easy to forget to check a return code and then have a red-herring error later on.
    • var success = Save()? How much performance is worth someone forgetting an if check here?
    • var success = TrySave()? Better, but are we going to abuse everything with the TryX pattern? Did you still provide a Save method?
  • Return codes don't have any of the great debugging information on them like call stack, inner exceptions.
  • Return codes do not propagate which, along with the point above, tends to drive excessive and interwoven diagnostic logging instead of logging in one centralized place (application and thread level exception handlers).
  • Return codes tend to drive messy code in the form of nested 'if' blocks
  • Developer time spent debugging an unknown issue that would otherwise have been an obvious exception (pit of success) IS expensive.
  • If the team behind C# didn't intend for exceptions to govern control flow, execeptions wouldn't be typed, there would be no "when" filter on catch statements, and there would be no need for the parameter-less 'throw' statement.

Regarding Performance:

  • Exceptions may be computationally expensive RELATIVE to not throwing at all, but they're called EXCEPTIONS for a reason. Speed comparisons always manage to assume a 100% exception rate which should never be the case. Even if an exception is 100x slower, how much does that really matter if it only happens 1% of the time?

  • Context is everything. For example, A Tester-Doer or Try option to avoid a unique key violation is likely to waste more time and resources on average (checking for existance when a collision is rare) than just assuming a successful entry and catching that rare violation.

  • Unless we're talking floating point arithmetic for graphics applications or something similar, CPU cycles are cheap compared to developer time.

  • Cost from a time perspective carries the same argument. Relative to database queries or web service calls or file loads, normal application time will dwarf exception time. Exceptions were nearly sub-MICROsecond in 2006

  • I dare anybody that works in .net, to set your debugger to break on all exceptions and disable just my code and see how many exceptions are already happening that you don't even know about.

  • Jon Skeet says "[Exceptions are] not slow enough to make it worth avoiding them in normal use". The linked response also contains two articles from Jon on the subject. His generalized theme is that exceptions are fine and if you're experiencing them as a performance problem, there's likely a larger design issue.

Solution 7 - Language Agnostic

In Java, I use (in the following order):

  1. Design-by-contract (ensuring preconditions are met before trying anything that might fail). This catches most things and I return an error code for this.

  2. Returning error codes whilst processing work (and performing rollback if needed).

  3. Exceptions, but these are used only for unexpected things.

Solution 8 - Language Agnostic

I dislike return codes because they cause the following pattern to mushroom throughout your code

CRetType obReturn = CODE_SUCCESS;
obReturn = CallMyFunctionWhichReturnsCodes();
if (obReturn == CODE_BLOW_UP)
{
  // bail out
  goto FunctionExit;
}

Soon a method call consisting of 4 function calls bloats up with 12 lines of error handling.. Some of which will never happen. If and switch cases abound.

Exceptions are cleaner if you use them well... to signal exceptional events .. after which the execution path cannot continue. They are often more descriptive and informational than error codes.

If you have multiple states after a method call that should be handled differently (and are not exceptional cases), use error codes or out params. Although Personaly I've found this to be rare..

I've hunted a bit about the 'performance penalty' counterargument.. more in the C++ / COM world but in the newer languages, I think the difference isn't that much. In any case, when something blows up, performance concerns are relegated to the backburner :)

Solution 9 - Language Agnostic

I wrote a blog post about this a while ago.

The performance overhead of throwing an exception should not play any role in your decision. If you're doing it right, after all, an exception is exceptional.

Solution 10 - Language Agnostic

A great piece of advice I got from The Pragmatic Programmer was something along the lines of "your program should be able to perform all its main functionality without using exceptions at all".

Solution 11 - Language Agnostic

I have a simple set of rules:

  1. Use return codes for things you expect your immediate caller to react to.

  2. Use exceptions for errors that are broader in scope, and may reasonable be expected to be handled by something many levels above the caller so that awareness of the error does not have to percolate up through many layers, making code more complex.

In Java I only ever used unchecked exceptions, checked exceptions end up just being another form of return code and in my experience the duality of what might be "returned" by a method call was generally more of a hinderance than a help.

Solution 12 - Language Agnostic

With any decent compiler or runtime environment exceptions do not incur a significant penalty. It's more or less like a GOTO statement that jumps to the exception handler. Also, having exceptions caught by a runtime environment (like the JVM) helps isolating and fixing a bug a lot easier. I'll take a NullPointerException in Java over a segfault in C any day.

Solution 13 - Language Agnostic

I use Exceptions in python in both Exceptional, and non-Exceptional circumstances.

It is often nice to be able to use an Exception to indicate the "request could not be performed", as opposed to returning an Error value. It means that you /always/ know that the return value is the right type, instead of arbitarily None or NotFoundSingleton or something. Here is a good example of where I prefer to use an exception handler instead of a conditional on the return value.

try:
    dataobj = datastore.fetch(obj_id)
except LookupError:
    # could not find object, create it.
    dataobj = datastore.create(....)

The side effect is that when a datastore.fetch(obj_id) is run, you never have to check if its return value is None, you get that error immediately for free. This is counter to the argument, "your program should be able to perform all its main functionality without using exceptions at all".

Here is another example of where exceptions are 'exceptionally' useful, in order to write code for dealing with the filesystem that isn't subject to race conditions.

# wrong way:
if os.path.exists(directory_to_remove):
    # race condition is here.
    os.path.rmdir(directory_to_remove)

# right way:
try: 
    os.path.rmdir(directory_to_remove)
except OSError:
    # directory didn't exist, good.
    pass

One system call instead of two, no race condition. This is a poor example because obviously this will fail with an OSError in more circumstances than the directory doesn't exist, but it's a 'good enough' solution for many tightly controlled situations.

Solution 14 - Language Agnostic

I believe the return codes adds to code noise. For example, I always hated the look of COM/ATL code due to return codes. There had to be an HRESULT check for every line of code. I consider the error return code is one of the bad decisions made by architects of COM. It makes it difficult to do logical grouping of the code, thus code review becomes difficult.

I am not sure about the performance comparison when there is an explicit check for the return code every line.

Solution 15 - Language Agnostic

Exceptions are not for error handling, IMO. Exceptions are just that; exceptional events that you did not expect. Use with caution I say.

Error codes can be OK, but returning 404 or 200 from a method is bad, IMO. Use enums (.Net) instead, that makes the code more readable and easier to use for other developers. Also you don't have to maintain a table over numbers and descriptions.

Also; the try-catch-finally pattern is an anti-pattern in my book. Try-finally can be good, try-catch can also be good but try-catch-finally is never good. try-finally can often times be replaced by a "using" statement (IDispose pattern), which is better IMO. And Try-catch where you actually catch an exception you're able to handle is good, or if you do this:

try{
    db.UpdateAll(somevalue);
}
catch (Exception ex) {
    logger.Exception(ex, "UpdateAll method failed");
    throw;
}

So as long as you let the exception continue to bubble it's OK. Another example is this:

try{
    dbHasBeenUpdated = db.UpdateAll(somevalue); // true/false
}
catch (ConnectionException ex) {
    logger.Exception(ex, "Connection failed");
    dbHasBeenUpdated = false;
}

Here I actually handle the exception; what I do outside of the try-catch when the update method fails is another story, but I think my point has been made. :)

Why is then try-catch-finally an anti-pattern? Here's why:

try{
    db.UpdateAll(somevalue);
}
catch (Exception ex) {
    logger.Exception(ex, "UpdateAll method failed");
    throw;
}
finally {
    db.Close();
}

What happens if the db object has already been closed? A new exception is thrown and it has to be handled! This is better:

try{
    using(IDatabase db = DatabaseFactory.CreateDatabase()) {
        db.UpdateAll(somevalue);
    }
}
catch (Exception ex) {
    logger.Exception(ex, "UpdateAll method failed");
    throw;
}

Or, if the db object does not implement IDisposable do this:

try{
    try {
        IDatabase db = DatabaseFactory.CreateDatabase();
        db.UpdateAll(somevalue);
    }
    finally{
        db.Close();
    }
}
catch (DatabaseAlreadyClosedException dbClosedEx) {
    logger.Exception(dbClosedEx, "Database connection was closed already.");
}
catch (Exception ex) {
    logger.Exception(ex, "UpdateAll method failed");
    throw;
}

That's my 2 cents anyway! :)

Solution 16 - Language Agnostic

I prefer to use exceptions for error handling and return values (or parameters) as the normal result of a function. This gives an easy and consistent error-handling scheme and if done correctly it makes for much cleaner looking code.

Solution 17 - Language Agnostic

One of the big differences is that exceptions force you to handle an error, whereas error return codes can go unchecked.

Error return codes, if used heavily, can also cause very ugly code with lots of if tests similar to this form:

if(function(call) != ERROR_CODE) {
    do_right_thing();
}
else {
    handle_error();
}

Personally I prefer to use exceptions for errors that SHOULD or MUST be acted upon by the calling code, and only use error codes for "expected failings" where returning something is actually valid and possible.

Solution 18 - Language Agnostic

There is many reason to prefer Exceptions over return code:

  • Usually, for readibility, people try to minimize the number of return statement in a method. Doing so, exceptions prevent to do some extra work while in a incoorect state, and thus prevent to potentially damage more data.
  • Exception are generally more verbose arn more easilly extensible than return value. Assume that a method return natural number and that you use negative numbers as return code when an error occurs, if the scope of you method change and now return integers, you'll have to modify all the method calls instead of just tweaking a little bit the exception.
  • Exceptions allows more easilly to separate error handling of normal behaviour. They allows to ensure that some operations performs somehow as an atomic operation.

Solution 19 - Language Agnostic

I generally prefer return codes because they let the caller decide whether the failure is exceptional.

This approach is typical in the Elixir language.

# I care whether this succeeds. If it doesn't return :ok, raise an exception.
:ok = File.write(path, content)

# I don't care whether this succeeds. Don't check the return value.
File.write(path, content)

# This had better not succeed - the path should be read-only to me.
# If I get anything other than this error, raise an exception.
{:error, :erofs} = File.write(path, content)

# I want this to succeed but I can handle its failure
case File.write(path, content) do
  :ok => handle_success()
  error => handle_error(error)
end

People mentioned that return codes can cause you to have a lot of nested if statements, but that can be handled with better syntax. In Elixir, the with statement lets us easily separate a series of happy-path return value from any failures.

with {:ok, content} <- get_content(),
  :ok <- File.write(path, content) do
    IO.puts "everything worked, happy path code goes here"
else
  # Here we can use a single catch-all failure clause
  # or match every kind of failure individually
  # or match subsets of them however we like
  _some_error => IO.puts "one of those steps failed"
  _other_error => IO.puts "one of those steps failed"
end

Elixir still has functions that raise exceptions. Going back to my first example, I could do either of these to raise an exception if the file can't be written.

# Raises a generic MatchError because the return value isn't :ok
:ok = File.write(path, content)

# Raises a File.Error with a descriptive error message - eg, saying
# that the file is read-only
File.write!(path, content)

If I, as the caller, know that I want to raise an error if the write fails, I can choose to call File.write! instead of File.write. Or I can choose to call File.write and handle each of the possible reasons for failure differently.

Of course it's always possible to rescue an exception if we want to. But compared to handling an informative return value, it seems awkward to me. If I know that a function call can fail or even should fail, its failure isn't an exceptional case.

Solution 20 - Language Agnostic

I only use exceptions, no return codes. I'm talking about Java here.

The general rule I follow is if I have a method called doFoo() then it follows that if it doesn't "do foo", as it were, then something exceptional has happened and an Exception should be thrown.

Solution 21 - Language Agnostic

One thing I fear about exceptions is that throwing an exception will screw up code flow. For example if you do

void foo()
{
  MyPointer* p = NULL;
  try{
    p = new PointedStuff();
    //I'm a module user and  I'm doing stuff that might throw or not

  }
  catch(...)
  {
    //should I delete the pointer?
  }
}

Or even worse what if I deleted something I shouldn't have, but got thrown to catch before I did the rest of the cleanup. Throwing put a lot of weight on the poor user IMHO.

Solution 22 - Language Agnostic

My general rule in the exception vs. return code argument:

  • Use errorcodes when you need localization/internationalization -- in .NET, you could use these errorcodes to reference a resource file which will then display the error in the appropriate language. Otherwise, use exceptions
  • Use exceptions only for errors that are really exceptional. If it's something that happens fairly often, either use a boolean or an enum errorcode.

Solution 23 - Language Agnostic

I don't find return codes to be less ugly than exceptions. With the exception, you have the try{} catch() {} finally {} where as with return codes you have if(){}. I used to fear exceptions for the reasons given in the post; you don't know if the pointer needs to be cleared, what have you. But I think you have the same problems when it comes to the return codes. You don't know the state of the parameters unless you know some details about the function/method in question.

Regardless, you have to handle the error if possible. You can just as easily let an exception propagate to the top level as ignore a return code and let the program segfault.

I do like the idea of returning a value (enumeration?) for results and an exception for an exceptional case.

Solution 24 - Language Agnostic

For a language like Java, I would go with Exception because the compiler gives compile time error if exceptions are not handled.This forces the calling function to handle/throw the exceptions.

For Python, I am more conflicted. There is no compiler so it's possible that caller does not handle the exception thrown by the function leading to runtime exceptions. If you use return codes you might have unexpected behavior if not handled properly and if you use exceptions you might get runtime exceptions.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRobert GouldView Question on Stackoverflow
Solution 1 - Language AgnosticpaercebalView Answer on Stackoverflow
Solution 2 - Language AgnosticStephen WrightonView Answer on Stackoverflow
Solution 3 - Language AgnostichurstView Answer on Stackoverflow
Solution 4 - Language AgnosticJason EtheridgeView Answer on Stackoverflow
Solution 5 - Language AgnosticjohncView Answer on Stackoverflow
Solution 6 - Language Agnosticb_levittView Answer on Stackoverflow
Solution 7 - Language AgnosticpaxdiabloView Answer on Stackoverflow
Solution 8 - Language AgnosticGishuView Answer on Stackoverflow
Solution 9 - Language AgnosticThomasView Answer on Stackoverflow
Solution 10 - Language AgnosticSmasheryView Answer on Stackoverflow
Solution 11 - Language AgnosticKendall Helmstetter GelnerView Answer on Stackoverflow
Solution 12 - Language AgnosticKyle CroninView Answer on Stackoverflow
Solution 13 - Language AgnosticJerubView Answer on Stackoverflow
Solution 14 - Language AgnosticrpattabiView Answer on Stackoverflow
Solution 15 - Language AgnosticnoocyteView Answer on Stackoverflow
Solution 16 - Language AgnosticTrentView Answer on Stackoverflow
Solution 17 - Language AgnosticDaniel BruceView Answer on Stackoverflow
Solution 18 - Language AgnosticgizmoView Answer on Stackoverflow
Solution 19 - Language AgnosticNathan LongView Answer on Stackoverflow
Solution 20 - Language AgnosticSCdFView Answer on Stackoverflow
Solution 21 - Language AgnosticRobert GouldView Answer on Stackoverflow
Solution 22 - Language AgnosticJon LimjapView Answer on Stackoverflow
Solution 23 - Language AgnosticJonathan AdelsonView Answer on Stackoverflow
Solution 24 - Language Agnostic2ank3thView Answer on Stackoverflow