|
|
Subscribe / Log in / New account

A little OO goes a long way

A little OO goes a long way

Posted May 3, 2013 13:00 UTC (Fri) by jwakely (subscriber, #60262)
In reply to: A little OO goes a long way by hummassa
Parent article: Go and Rust — objects without class

Also, you'll be writing the same code everywhere you want to clean up a resource of that type. Why repeat yourself, why not associate the cleanup code with the type and make it run automatically?

I'm baffled why any self-respecting programmer would want to duplicate all that cleanup logic in every finally block or why they'd question the advantage of destructors.

Python's with statement is the right idea, the object's scope is limited and its type has some predefined cleanup code that runs automatically when the scope ends. Bingo.


to post comments

A little OO goes a long way

Posted May 3, 2013 14:18 UTC (Fri) by ehiggs (subscriber, #90713) [Link] (1 responses)

To bring it back on topic, Go has 'defer'[1] which is a bit of try-finally and with/destructors by putting the deferred call near the construction site.

It's still not as good as Python's 'with' in my opinion because you have to be explicit about the cleanup call in Go and in Python it's not cluttering up the code (aside from the indent level).

[1] http://golang.org/doc/effective_go.html#defer

A little OO goes a long way

Posted May 4, 2013 5:37 UTC (Sat) by danieldk (subscriber, #27876) [Link]

And it's by for not as good as destructors:

- It puts the burden on the programmer and not the type.
- defer only works when leaving the scope of the function calling it. A type's destructors are called when going out of any scope in C++, e.g. when an instance of a class is used as a (non-pointer) member variable.

A little OO goes a long way

Posted May 3, 2013 15:53 UTC (Fri) by hummassa (subscriber, #307) [Link] (4 responses)

Oh, the duplication is the least of the problems. A bigger one would be the combination of optimization by the programmer and external changes. So, the following code:
try {
  f = open(...)
  f.x()
  f.y()
  if( z ) f.writeCheckSumAndLastBuffer() else f.writeLastBuffer()
} finally {
  f.close()
}
generates a hidden bug when f.y(), that calls a w() function from an external library, starts seen some exception and the last buffer is not written. Bonus points if the "if(z)" thing was put by another programming, in the run of the normal maintenance of the program.

A little OO goes a long way

Posted May 4, 2013 5:45 UTC (Sat) by danieldk (subscriber, #27876) [Link] (3 responses)

I don't see how that is a problem of try/finally. Consider this C++
{
   Resource someResource(...);
   resource.x();
   resource.y(); // throws
   resource.writeLastBuffer();
}

If y() throws here in C++, writeLastBuffer() is never called either. I if you always want to write something, add it to close() or ~Resource().

Also, Java 7 has a nicer try-with-resources statement, like Python's with, for classes that implement AutoClosable:

try (Resource r = new Resource(...)) {
  // Do something with r...
}

A little OO goes a long way

Posted May 4, 2013 10:21 UTC (Sat) by hummassa (subscriber, #307) [Link]

It still burdens the "client" programmer on remembering to use the new try thingy. Destructors have zero client programmer overhead.

A little OO goes a long way

Posted May 4, 2013 10:26 UTC (Sat) by hummassa (subscriber, #307) [Link]

> I don't see how that is a problem of try/finally.

You are right, of course. But using destructors you have a lot more chances that discovering that some code belong in an destructor and putting it there because in the client code the WriteLastBuffer thing sticks out like a sore thumb. :-D

Ah, and once you wrote it, all call sites are correct from now on.

A little OO goes a long way

Posted May 7, 2013 14:52 UTC (Tue) by IkeTo (subscriber, #2122) [Link]

Consider this C++
{
   Resource someResource(...);
   resource.x();
   resource.y(); // throws
   resource.writeLastBuffer();
}

C++ programmers are accustomed to a concept called RAII, Resource Acquisition is Initialization. So if they always want the last buffer written, they tend to write something like:

class LastBufferWriter {
public:
  LastBufferWriter(Resource resource): resource_(resource) {}
  ~LastBufferWriter() { resource_.writeLastBuffer(); }
private:
  Resource resource_;
};

... {
   Resource resource(...);
   LastBufferWriter writer(resource);
   // Anything below can throw or not throw, we don't care
   resource.x();
   resource.y();
}

Not to say that everybody like having to define a class for every cleanup, though. But with C++0x lambda expression, the above can easily be automated.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds