180 likes | 304 Views
A Moderately Directed Rant. Exception Safety and Garbage Collection and Some Other Stuff. Why should I care about this?. It’s very likely that you’ve been writing totally incorrect code without realizing it
E N D
A Moderately Directed Rant Exception Safety and Garbage Collection and Some Other Stuff
Why should I care about this? • 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!
Boring Definitions • 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
More Boring Definitions • 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
Reasonable Code Example (C) • Let’s look at some C code so we can figure out what this talk is even about voidexample() { 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
Terrible Code Example (C++) • Let’s see that exact same code, but now we’ll pretend that it was compiled as C++ voidexample() { 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!
That Sucks! • Yes, it does suck! It’s such a problem that people were motivated to go try to solve it • BjarneStroustrup (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
Modern Code Example (C++) voidexample() { Lockmy_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
How RAII Actually Works classLock { 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
Sure, but I don’t use C++ • 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
The Dispose Pattern (Java) voidexample() { IntegermyInteger = newInteger(0); Locklock = newLock(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
More Dispose Loveliness (Java) voidexample() { FilemyFile = newFile(filename); try { DBConnectiondbConn = newDBConnection(credentials); try { LockmyLock = newLock(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
Again, but with RAII (C++) voidexample() { FilemyFile(filename); DBConnectiondbConn(credentials); LockmyLock(&g_mutex); doSomething(myFile, dbConn); }
One More Time (D) voidexample() { scopemyFile = newFile(filename); scopedbConn= newDBConnection(credentials); scopemyLock = newLock(g_mutex); doSomething(myFile, dbConn); }
“You can take my deterministic resource management when my cold dead hand goes out of scope.” -- Anon
Why does Java suck so bad? • 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
So what should I do? • 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
Okay, done ranting • 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?