Exception Safety and Garbage Collection and Some Other Stuff

Document Sample
Exception Safety and Garbage Collection and Some Other Stuff Powered By Docstoc
					A Moderately Directed Rant
   It’s very likely that you’ve been writing totally
    incorrect code without realizing it
     Once you do realize it, it’s usually not too hard to
      fix the problem, depending on the language
   This is information that isn’t all that widely
    known, for whatever reason
   You can use it to show off at interviews!
   You can use it to start arguments about which
    programming language is the best!
   We need to define a couple basic things at the
    beginning so everybody’s on the same page
     It’ll be quick, I promise
   Garbage collection is a method of managing
    dynamic (heap-allocated) memory
     It’s non-deterministic, and there is usually no
      guarantee that memory is cleaned up at all
     Most modern languages use garbage collection
   A resource is anything you need to return to
    the system once you’re done using it
     File handles, dynamic memory, locks, etc.
   Exception safety means that you can throw
    an exception in the middle of your function
    without bad things happening
     There’s a complicated formal definition with
     degrees of exception safety but this is good
     enough for our purposes
   Let’s look at some C code so we can figure out
    what this talk is even about
void example() {
  lock(&g_mutex);
  int* my_int_pointer =
  (int*)malloc(sizeof(int));
  do_something_with(my_int_pointer);
  free(my_int_pointer);
  unlock(&g_mutex);
}

   This is fairly reasonable, safe C code. It executes
    deterministically and everyone is happy
   Let’s see that exact same code, but now we’ll pretend
    that it was compiled as C++
void example() {
  lock(&g_mutex);
  int* my_int_pointer =
  (int*)malloc(sizeof(int));
  do_something_with(my_int_pointer);
  free(my_int_pointer);
  unlock(&g_mutex);
}

   Catastrophe! This is going to compile and run without
    warnings, but be completely and totally unsafe!
     Why? Exceptions!
   Yes, it does suck! It’s such a problem that
    people were motivated to go try to solve it
   Bjarne Stroustrup (C++ language creator)
    came up with a solution which he named
    Resource Acquisition Is Initialization (RAII)
     Incidentally, in addition to providing exception
     safety, RAII made C++ way easier to use
   Let’s look at a correct C++ version of our code
    example, using RAII
void example() {
  Lock my_lock(&g_mutex);
  auto_ptr<int> my_int_pointer(new int());
  do_something_with(my_int_pointer);
}

   Thanks to RAII this example is exception safe,
    and we don’t have to worry about cleanup.
   auto_ptr<T> is part of the C++ standard library,
    but we’ve just made up Lock
     Let’s look at the code for our made-up Lock class so
      we can see how RAII actually works
class Lock {
private:
   mutex* m_pMutex;
public:
   Lock(mutex* pMutex) : m_pMutex(pMutex) {
      lock(m_pMutex);
   }
   ~Lock() {
      unlock(m_pMutex);
   }
};

   In C++ a stack-allocated object’s destructor is always
    called once it goes out of scope, whether due to a
    function returning, due to normal code execution, or
    due to stack unwinding caused by a thrown exception
   That’s understandable. We are (for better or
    worse) a Java school, so let’s see if we can’t
    make RAII work in Java
   Immediately we run into some problems
     Java doesn’t have destructors
     Java doesn’t have stack allocation for objects
   So RAII won’t work with Java, then. What else
    have we got?
     For dynamic memory we have garbage collection, but
      that’s a special case of the problem that doesn’t really
      need (or provide) determinism
     The best we can do is the Dispose pattern
void example() {
  Integer myInteger = new Integer(0);
  Lock lock = new Lock(g_mutex);
  try {
     doSomethingWith(myInteger);
  } finally {
     lock.dispose();
  }
}

   While rewriting this every time gives you exception
    safety, it’s really easy to forget it
     If you forget to do this, your program will still compile and
      run with no warnings, despite being wrong. Awesome!
   This is more verbose than even the C example, yet is
    the minimum amount of code required for Java
void example() {
  File myFile = new File(filename);
  try {
      DBConnection dbConn = new DBConnection(credentials);
      try {
          Lock myLock = new Lock(g_mutex);
          try {
              doSomething(myFile, dbConn);
          } finally {
              myLock.dispose();
          }
      } finally {
          dbConn.dispose();
      }
  } finally {
      myFile.dispose();
  }
}

   This is again the minimum code required to be correct
void example() {
  File myFile(filename);
  DBConnection dbConn(credentials);
  Lock myLock(&g_mutex);
  doSomething(myFile, dbConn);
}
void example() {
  scope myFile = new File(filename);
  scope dbConn = new
  DBConnection(credentials);
  scope myLock = new Lock(g_mutex);
  doSomething(myFile, dbConn);
}
“You can take my deterministic resource
 management when my cold dead hand
       goes out of scope.” -- Anon
   By choice. You can have deterministic resource
    management alongside garbage collection, but the
    Java guys specifically chose not to
     The D programming language supports RAII and has a
      garbage collector, so it’s definitely possible
     Java, C#, Python, Ruby all screw this up to varying degrees
      ▪ The latter three have some syntactic sugar for resource
        management, but the onus is still on you to remember to use it
      ▪ Java 7 catches up with C# and adds the same syntactic sugar, but
        still doesn’t solve the problem
     Perl, PHP, C++ and D all get it right to varying degrees
      ▪ If PHP gets something right before your language does, you should
        reassess your life goals
   My (unpopular) answer? Use C++ and Perl/PHP
    for everything until the D ecosystem matures a
    bit, then switch over to D entirely
     C++ has its own set of problems, but it’s my opinion
      that they’re exaggerated and the benefits far
      outweigh them
   If you’re stuck using a broken language like Java,
    I really don’t know what to tell you
     I guess you could cry a little bit, but I don’t think it
      would solve the problem
     Learn the Dispose pattern, always remember to use it
   I wish I had more helpful advice for Java, C#, Python, Ruby
    users, but this is the unfortunate state we find ourselves in
   If you want more information about anything mentioned:
     The D Programming Language by Andrei Alexandrescu is an
      excellent D introduction
     If you want to learn how to code modern C++, you should read
      Effective C++ by Scott Meyers
     The Boost website has good information about exception safety
      and reference-counted smart pointers, which I didn’t really talk
      about (Scott Meyers does in Effective C++)
     Google knows all

   Questions?