• dkf (unregistered) in reply to noname

    Oh gee, someone who doesn't get it...

    noname:
    Are you really that dumb???
    No but you are!!! (See, I can do ad hominem attacks too!)
    If you don't have a convenient scope, where the heck are you going to place your finally???
    If there's no convenient scope, a finally wouldn't help either. Don't think that just because I'm not on your side, I'm on the other side. Instead, I'm in the peanut gallery, and both C++ and Java are painful, though admittedly in different ways.
    And are you arguing for or against C++ with that last comment? Why should so many random finally blocks need to know the (easy to forget) cleanup details when the objects themselves can handle it?
    One advantage of a finally clause over the RAII style is that it is simpler when the conditions on cleanup are more complex, since finally clauses permit arbitrary code. You can do similar things with the RAII style, but you all too easily end up with a "fun trip" through reference management and copy constructors. Getting that sort of thing right and efficient can be interesting, and is really tricky to justify for a one-off case.

    Do I have a point? It's late but I suppose so; it is that resource management sucks in both Java and C++. We should try for something better, and it's a WTF that we don't...

    captcha: pirates (and vikings and knights, but no ninjas)

  • (cs)

    This is possible in Python as well:

    try:
        dangerous_code()
    except:
        pass
  • noname (unregistered) in reply to dkf
    dkf:
    Oh gee, someone who doesn't get it...
    noname:
    Are you really that dumb???
    No but you are!!! (See, I can do ad hominem attacks too!)
    If you don't have a convenient scope, where the heck are you going to place your finally???
    If there's no convenient scope, a finally wouldn't help either. Don't think that just because I'm not on your side, I'm on the other side. Instead, I'm in the peanut gallery, and both C++ and Java are painful, though admittedly in different ways.
    And are you arguing for or against C++ with that last comment? Why should so many random finally blocks need to know the (easy to forget) cleanup details when the objects themselves can handle it?
    One advantage of a finally clause over the RAII style is that it is simpler when the conditions on cleanup are more complex, since finally clauses permit arbitrary code. You can do similar things with the RAII style, but you all too easily end up with a "fun trip" through reference management and copy constructors. Getting that sort of thing right and efficient can be interesting, and is really tricky to justify for a one-off case.

    Do I have a point? It's late but I suppose so; it is that resource management sucks in both Java and C++. We should try for something better, and it's a WTF that we don't...

    captcha: pirates (and vikings and knights, but no ninjas)

    I need to apologize for that. No excuses really, but all the WTF's around my job had me in a poor mood.

  • noname (unregistered) in reply to dkf

    One advantage of a finally clause over the RAII style is that it is simpler when the conditions on cleanup are more complex, since finally clauses permit arbitrary code. You can do similar things with the RAII style, but you all too easily end up with a "fun trip" through reference management and copy constructors. Getting that sort of thing right and efficient can be interesting, and is really tricky to justify for a one-off case.

    I wanted to keep this separate from the apology, but I think you might have won me over. For a complex one-off case I would prefer a finally block.

    I guess I've just spent too much time lately in Java reimplementing the same pattern in finally block over and over. I've definitely missed RAII more in Java than I felt the lack of finally in C++.

  • yy2bggggs (unregistered) in reply to noname

    For those who do not yet understand RAII's utility, consider a case like this:

    try
    {
       File file1("x.dat");
       ... (point 1)
       File file2(name_from_x_dat);
       ... (point 2)
       {
          MutexLock process(mtx);
          Queue(data);
       }
    } catch (...){...}
    

    If an exception occurs at point 1, the RAII file object closes file1. If it happens at point 2, the RAII file object closes file2, then file1. If it happens when queueing data, the mutex is unlocked, file2 is closed, then file1 is closed.

    What would you have to do to code this correctly in java?

  • (cs) in reply to Artemus Harper
    Artemus Harper:
    Using a constructor and destructor to do more than the initialization of the object is an anti-pattern.

    Not in C++. There it is an accepted idiom.

    Many C++ programmers who are actually able to take advantage of the expressiveness of the language (as opposed to being restricted by compatibility with C code, with being portable across old compilers, or by habits or ignorance of the programmer) use RAII for non-trivial tasks such as exactly that.

    dkf:
    Do I have a point? It's late but I suppose so; it is that resource management sucks in both Java and C++. We should try for something better, and it's a WTF that we don't...

    There are some languages that have better support for this sort of matched behavior thing (lock/unlock, open/close, disable/enable, etc.). In fact a couple of friends of mine just did a class project on this very topic.

    I agree with the other poster who said that while it would be nice to have finally in C++ for one-off things, given a choice between the ability to properly do RAII and finally and I'll pick RAII in an instant.

  • Matt (unregistered) in reply to yy2bggggs

    In Java you'd do this (assuming that I understand what you're using the Mutex for) - more wordy than your example, but it gets the job done.

    File file1 = null;
    File file2 = null;
    Object mutexLock = new Object();
    
    try
    {
        file1 = new File("x.dat");
        ....
        file2 = new File(name_from_x_dat);
        ....
        synchronized (mutexLock)
        {
            // Process the queue
        }
    }
    catch (IOException ioe)
    {
        // Deal with exception
    }
    finally
    {
        // Mutex is automatically unlocked when execution leaves
        // the synchronized block either natuarlly or via an exception
        
        if (file2 != null)
        {
            try
            {
                file2.close();
            }
            catch (Exception e)
            {
                // Log warning that cannot close file
            }
        }
    
        if (file1 != null)
        {
            try
            {
                file1.close();
            }
            catch (Exception e)
            {
                // Log warning that cannot close file
            }
        }
    }
    
  • David D (unregistered) in reply to john
    john:
    the thing that disturbs me the most is that the coder didn´t use a "big" try, finally block but made many of them.

    He wants to ignore every exception anyway so what´s the point in making a try, finally around every single method that could through an exception?

    Perfectly sensible when you want to allow each block to execute. A single try block would abort the whole statement sequence if any one of them threw.

    I'm not saying the code is good or bad, but I do understand why there could be a need for separate try blocks as opposed to a single big one.

  • Clark Cox (unregistered) in reply to aquanight
    aquanight:
    Derrick Pallas:
    The reason C++ doesn't have this block is because it's unnecessary: since acquisition is initialization, most resources are local.

    IMHO C++ does need a finally thanks to the new/delete operators.

    That's what smart pointers are for (auto_ptr, shared_ptr, etc.)

  • yy2bggggs (unregistered) in reply to Matt
    Matt:
    In Java you'd do this (assuming that I understand what you're using the Mutex for) - more wordy than your example, but it gets the job done.
    "Gets the job done" isn't quite the point. It looks like you have to worry about: (1) cleaning up each file (code duplication), and (2) order.

    As for assuming something to make it easier for java, bah! The mutex here is a mutex--that is all you know. To make it work in java, you must use that mutex. The mutex may not be one of your nice program specific object locks--it could be a mutex obtained from the OS (e.g., it could be that you're queueing to a resource shared outside of your program, and thus beyond your program's control).

    captcha = gotcha

  • Miral (unregistered)

    I'm firmly of the opinion that RAII came about as a result of the language's lack of finally clauses, rather than the reverse. Without one of the two, you can't write exception-safe code without wasteful duplication.

    Personally I prefer finally clauses, since (a) it makes it clear that you're expecting exceptions to get thrown sometimes and (b) writing an extra class just for lifecycle management always seems heavy-handed to me. But on the other hand the RAII pattern is safer as that way you don't have to think about exit paths or need to remember to protect each use of the resource with a finally block (which is very useful if you have third-party clients using your objects).

    I think the latter has produced a real problem in .NET, where you have to rely on your consumers to call the Close/Dispose method of an object to clean up in a timely fashion. If they forget, you're SOL.

  • yy2bggggs (unregistered) in reply to Miral

    Still don't understand! "Wasteful code duplication" isn't the point either. It's not about the waste--it's about BUGS. Let's take memory leaks as an example.

    In C++, you have new and delete. There's a problem here because you have to pair new and deletes. This is known, historically, to be a pretty big problem. Let me emphasise, however, that this is ONLY a problem if you forget the delete.

    What makes this a problem is that programs are complicated. Resources need to be managed, to help the programmers make code that has no errors. This is the goal! This is the point!

    Okay, so let's switch to java now. Java has a nice method of handling resource leaks due to new and delete--it's not entirely novel, but it's a pretty decent solution. The solution is garbage collection. Here, the language itself worries about deleting objects, by keeping track of references. If an object can no longer be referenced, it is a candidate for deletion.

    This solves the new/delete problem by removing the need to delete. It's a fairly good solution, but it has a major flaw. Let's explore that flaw. Suppose I make a library, and that library has a dynamic data structure in it--let's say a list. This library may do something like keep track of objects that can listen to a particular event. Note that this isn't even too contrived of a thing--it's a very ordinary scenario, and is very likely to exist in a real life situation.

    Now, the library has a method--called register. When you register an object, the library knows that it should receive notification of the event, when it happens. But what if the object is no longer needed? GC doesn't work any more, because the library stores the object, and that is a reference. So you need another method--let's call it unregister. When you are done with the object, you call unregister on it, and that removes the object from the library's internal list.

    Sound familiar? If not, you're not reading closely enough. We have now reimplemented the memory leak: register is your new, and unregister is your delete. As such, you've inherited the same exact problems gc is supposed to solve for you. I must reemphasize, to make sure you really understand--this is NOT an obscure example--this is something you see "in the wild" quite often, and is a very realistic scenario.

    But what about C++, where you have to worry about the delete? Well, in C++, you can use RAII. The disadvantage is that you have to use it, but the advantage is that you can. RAII, in C++, is a programmer's responsibility to use. But when it is used, it solves a bigger class of problems.

    Need to allocate memory? Use a smart pointer. Need to write a library that keeps track of events for an object? Write an RAII manager for object registration--and suddenly your library manages registration!

    But wait--there's more. Need to lock an OS Mutex? RAII. Need to close a file in a custom filesystem you implement for an embedded system? RAII. Need to render your bitmap after making a whole set of changes? Write an end tag? Unset your cursor from a busy cursor? RAII.

    You see, the new/delete problem is a lot bigger than just new/delete--it's really an acquire resource/release resource problem. GC only partially handles the new/delete problem. Try/finally doesn't handle it at all. RAII handles this. try/finally is just a workaround, which must be customized in every combination of resource cleanup code you come up with, and must be handled correctly there, and even then only works with scope! (Note that RAII can be tied to object lifetime as well as code scope).

    I can see that try/finally may have other uses besides making sure things are cleaned up; however, I've never found a situation where I needed something like this since discovering RAII. I would welcome someone giving me a real use for try/finally. As for resource cleanups, RAII wins hands down, due to your NOT having to worry about every little detail of how and where you acquired resources.

    captcha = burned

  • yy2bggggs (unregistered) in reply to Miral

    Oh, one more thing. RAII takes less effort than try/finally. I know that is counter intuitive--it always is for those new to RAII. I suppose the reason is because, mentally, there's more to do ("go off and write class to handle resource"). But TRY it! If you use a resource twice, you'll write less code; furthermore, even when it is written once, RAII separates business logic (logic written as part of the normal par of programming to make sure things get done) from domain logic (logic associated with the precise thing you are doing). As such, it makes your code easier to read, and understand.

  • (cs) in reply to Miral
    Miral:
    I'm firmly of the opinion that RAII came about as a result of the language's lack of finally clauses, rather than the reverse. Without one of the two, you can't write exception-safe code without wasteful duplication.

    It very well may have been a result of not having finally and thus not having much of an alternative, but I think that this is for the better.

    Personally I prefer finally clauses, since (a) it makes it clear that you're expecting exceptions to get thrown sometimes and (b) writing an extra class just for lifecycle management always seems heavy-handed to me.

    But duplicating code every time you have to manage the same resource (e.g. writing 10 calls to close() at various points through your program) doesn't?

    Especially because it's often the case that you don't need another class just for resource management, you can just add a destructor. You already have a File class (or FileStream, or whatever you call open() on), wouldn't it be nice to have a destructor on that class to automatically call close? No need to make a new class... just a new method.

    But on the other hand the RAII pattern is safer as that way you don't have to think about exit paths or need to remember to protect each use of the resource with a finally block (which is very useful if you have third-party clients using your objects).

    I think the latter has produced a real problem in .NET, where you have to rely on your consumers to call the Close/Dispose method of an object to clean up in a timely fashion. If they forget, you're SOL.

    Why's that not a problem in Java?

  • (cs) in reply to yy2bggggs

    Do you have to do memory management or garbage collection in VB.Net? I know there are try{}catch{} blocks, but i don't think the classes need an explicit destructor, do they?

    I'm just curious.

  • Steve (unregistered) in reply to Mr. Nice Guy
    Steve:
    aquanight:
    it's a pain the ass to remember a bunch of deletes before every exit point from the function
    no 'properly' written function should have multiple exit points - in theory, at least...
    I was unaware that people took theories about 'properly' (note the quotes) written functions so seriously. WTF?

    I wonder if there's a smiley for tongue-in-cheek...

    Mr. Nice Guy:
    And why not? I use this idiom all the time:

    example skipped

    How else would you handle such a situation?

    I'm actually fine with that (multiple returns), but you make the mistake of assuming that everybody else also writes code which is sensible.

    See the original quote to which I made my comment (above). You know that sooner or later, somebody is going to forget, and you will end up having to fix it. Do that a few times, and then a few times more. I'm sure that eventually you too will be telling people not to go there.

    brazzy:
    IMO a very, very stupid theory that leads to horribly unmaintainable code in many cases.
    It may only be my experience, but I've found the opposite to be true. I've yet to see a case where a single exit point was the real cause of somebody writing unmaintainable code! Those who really understood the theory will know when to ignore it.
    MrBester:
    Without multiple exit points you have to nest if blocks that easily get overly complicated. Far simpler to have:
    if (test1) { return true; } 
    if (test2) { return false; } 
    if (test3) { return FILE_NOT_FOUND; } 
    return NO_QUACK;
    Just to be pedantic and annoying, I'll show my overly complicated version which is a whole line longer:
    retVal = NO_QUACK;
    if (test1) { retVal = true; } 
    else if (test2) { retVal = false; } 
    else if (test3) { retVal = FILE_NOT_FOUND; } 
    return retVal;
    Unfortunately for me, the code I end up fixing looks nothing like the simple examples I've seen here. Being overly complicated is a problem that is in no way limited to code with a single exit point.

    Of course, if you reaaaally want to cut out all those complex 'if' statements, you can always use the elevenary operator! :-)

    Aaron:
    Honestly, if this had any grounding in reality then don't you think the compilers would explicitly disallow it?
    Haven't you ever told somebody not to use "GOTO"?

    -- Steve

  • James D (unregistered) in reply to Steve

    In languages with exceptions, any function that can either throw or return "normally" has multiple exit points, and once you accept that, there's actually almost zero additional complexity in returning when it's appropriate; it can twist code to make it into SESE style.

    For plain C, that doesn't hold, and single exit can help to ensure resource cleanup and allow hooks for function end. For languages with deterministic destructors and exceptions it's a different world.

  • (cs) in reply to Steve
    Just to be pedantic and annoying, I'll show my overly complicated version which is a whole line longer:<snip/>
    Except your version has implicit nesting that isn't reflected by the code wholly due to the fact that code block encapsulation isn't required. This makes it look like 3 tests at the function scope, rather than what it actually is; 1 at function scope, with 1 child and 1 grandchild. Not that this is wrong, per se, it can just be confusing if you are just relying on a spot of indentation (that doesn't come across in this forum s/w) to denote whereabouts you are in the Grand Scheme Of Things[tm]
    Haven't you ever told somebody not to use "GOTO"?
    Not in as many words. In any case, that's what GOSUB ... RETURN (optional!) is for ;)
  • nelle (unregistered) in reply to GeneWitch

    Do you have to do memory management or garbage collection >in VB.Net? I know there are try{}catch{} blocks, but i >don't think the classes need an explicit destructor, do >they?

    No they don't ...

    You can write a Finalize method that does the cleanup, but it gets called by the GC and not when you are done with the object ...

    (In C# the Finalize can be declared just like C++ destructor)

  • (cs) in reply to brazzy
    brazzy:
    Steve:
    One more thing: no 'properly' written function should have multiple exit points - in theory, at least...
    IMO a very, very stupid theory that leads to horribly unmaintainable code in many cases.
    Why? As a last resort, you can always "goto" a label immediately preceding the single exit point... ;-)
  • mister bean (unregistered) in reply to balu

    ROFL! That's very funny!

  • mister bean (unregistered) in reply to balu

    [quote user=balu]
    JonR said: i'm working with a codebase that is littered with

    try
    {
    // blah
    }
    catch(Exception e) { throw; }
    
    this makes me SO ANGRY
    

    Yeah, usually such things are written by people who don't understand that comments don't throw exceptions. Sorry, I couldn't resist...[/quote]

    ROFL! That's very funny!

  • Stupid (unregistered)

    Call me stupid but isn't it obvious the programmer(?) has left that part to be "cleaned up" by Dave?

  • Wulf (unregistered) in reply to Look at me! I'm on the internets!

    There are exactly two ways in which a sane program should respond to an InterruptedException:

    1. yawn, stretch and get to work
    2. ignore it

    The exception is thrown after the Thread's sleep() has been interrupted by a call to Thread.interrupt(). In other words it can be treated like semaphore that tells your thread to go back to work. If you had a worker deamon that has to process a queue of workitem you put this in your run(): ... try{ Thread.sleep(Long.MAX_VALUE) } catch(Throwable t){ /let's go to work!/ } .. Now the controller or whoever generates workitems just calls

    workerThread.interrupt();

    whenever new workitems have been added and off your thread goes.

    Rethrowing it is actually quite the "WTF!?" ...

  • Opinionated Idiot (unregistered) in reply to yy2bggggs
    yy2bggggs:
    Matt:
    In Java you'd do this (assuming that I understand what you're using the Mutex for) - more wordy than your example, but it gets the job done.
    "Gets the job done" isn't quite the point. It looks like you have to worry about: (1) cleaning up each file (code duplication), and (2) order.

    As for assuming something to make it easier for java, bah! The mutex here is a mutex--that is all you know. To make it work in java, you must use that mutex. The mutex may not be one of your nice program specific object locks--it could be a mutex obtained from the OS (e.g., it could be that you're queueing to a resource shared outside of your program, and thus beyond your program's control).

    captcha = gotcha

    I would use this error handling style as a C# (not Java as you asked) equivalent to the C++ example provided. I agree that this is still a little more coding (with explicit calls to Dispose) than the C++ example. [Sorry, I'm not sure what's up with my missing indents.]

    try { File file1 = new File("x.dat"); try { ... (point 1) File file2 = new File(name_from_x_dat); try { ... (point 2) MutexLock process = new MutexLock(mtx); try { Queue(data); } finally { process.Dispose(); } } finally { file2.Dispose(); } } finally { file1.Dispose(); } } catch(...){...}

  • (cs) in reply to Alan
    Alan:
    C++ code: try { acquireResource(); doSomethingRisky(); disposeResource(); } catch(...) { disposeResource(); throw; }

    C++ implementation produces duplicate code, but allows for greater flexibility.

    What you suggest is another anti-pattern. The idiomatic way to do it in C++ is:

    --snip--

    That's right, but I just wanted to show what is the difference between catch(...) and finally. I would use auto objects too.

    BTW, this should be r.doSomethingRisky(); or doSomethingRisky(r); :P

Leave a comment on “Nothing Final”

Log In or post as a guest

Replying to comment #:

« Return to Article