13 ms·
A similar pattern that blew my mind when I first saw it was ruby's scoped open(). instead of f = open "test.txt" print f.read f.close You can write
by sgentle 15y ago
A similar pattern that blew my mind when I first saw it was ruby's scoped open().
instead of
f = open "test.txt"
print f.read
f.close
You can write
open "text.txt" do |f|
print f.read
end
The file is automatically closed at the end of the block, and it also handles exceptions and so on. I find it also lines up better semantically with how I think about opening handles to things.
I believe Python also added something similar via the 'with' syntax. Not sure about other languages.
- derleth 15y agoCommon Lisp has had with-open-file for a long time now. The great thing about with-open-file is that it ensures the file gets closed regardless of what the code in the scope does, using unwind-protect. This implies you can use the same method to create your own with-held-resource macros that work the same way.
- drewrv 15y agoI believe c# has something similar too, "using" using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.None)) { Byte[] info = new UTF8Encoding(true).GetBytes("This is some text in the file."); // Add some information to the file. fs.Write(info, 0, info.Length); }
- kenneth_chau 15y agoI was about to put this down. Although, the C# world requires an IDisposable interface and implies that you're operating on a resource. Ruby has similar concept when you open a file and pass in a block to operate on the File object. I'm pretty sure the author is just excited about the language and failed to recognize that this pattern is everywhere in different programming languages.
- ansgri 15y agoThe author is excited that functions have their inverses by default, I think. Analogous construct in Python would be somethoug like: with_under do_something() as f: ... translated to f = do_something() ... f.undo_something() With do_something automatically matched to undo_something.
- noblethrasher 15y agoYou can do the same thing in C# that you can in Ruby new FileEx (SOME_PATH, () => ConsoleEx.ReadLine (), () => ConsoleEx.CurrentLine != "QUIT").WriteAll (); is equivalent to using (var file = new File(SOME_PATH)) { string line = null; try { while((line = Console.ReadLine) != "QUIT") { file.WriteLine(line); } } catch (Exception ex) { throw; } finally { sw.Close(); } }
- darklajid 15y agoFor a second I was intrigued and tried to find that FileEx class that I obviously missed to notice before. It doesn't seem to be part of the framework though? Homegrown and _you_ expand it to something that is equivalent to the second code snippet?
- noblethrasher 15y agoYes, it is homegrown[1]. I have quite a few little utilities that use (or abuse) iterators to get something like RAII in C# (I don't like relying on using/IDisposable and I especially don't like requiring it in my public types). Another one that I use a lot [2]: SqlCommandEx sql = "select * from person"; foreach (dynamic result in sql) { var full_name = result.first_name + " " + result.last_name; DateTime dob = result.dob; //do other stuff } //connection automatically disposed. [1] Relevant source: http://pastebin.com/LwHD8MHc http://pastebin.com/LwHD8MHc [2] https://github.com/noblethrasher/Prelude/blob/master/SQL.cs https://github.com/noblethrasher/Prelude/blob/master/SQL.cs
- masklinn 15y agoI'm going to assume I missed something, because from what I'm reading: 1. You're avoiding IDisposable for reasons you don't explain and I fail to see 2. You replace it with an idiom which is supposed to do the same thing (except abusing iterators instead of using tools dedicated to that job) and which I don't believe works, as your connection will not (as far as I can see) be disposed of if there's an error in the foreach block. And the code you linked does not seem to use this "pattern" anywhere
- yread 15y agoYes, you can do this but I usually just end up using the helper functions i.e System.IO.File.AppendAllText(path, "This is some text in the file."); Also, why are you writing text to binary file instead of just writing the text as a text file?
- repsilat 15y agoIn languages in which you can count on the timely cleanup of objects this can be done with the destructor. In C++, for instance, file handles are typically closed when the file object goes out of scope. Moreover, if an object has a file as a member variable, the object's default destructor will dispose of the file. IIRC: { ifstream file("text.txt"); copy(istream_iterator<string>(file), istream_iterator<string>(), ostream_iterator<string>(cout, "\n")); }//file automatically closed here and class ThingWithFile { ifstream file; public: ThingWithFile(const char *filename) : file(filename) {} }; void func() { ThingWithFile thing("file.name"); //file is opened } //file is closed
- evincarofautumn 15y agoDeterministic destruction is an excellent language feature. I really wish there were a garbage-collected language that separated destruction from deallocation, because the two are completely orthogonal. When an object goes out of scope, the destructor should run immediately; then, when the garbage collector wants to actually deallocate destroyed objects, it can go right ahead. No idiocy like in C# with “using” blocks.
- alok-g 15y agoI totally wonder why do they not have it this way. I have posted the same question on various forums but have never heard any real answer.
- richdougherty 15y agoWell, deterministic deallocation is difficult to combine with non-deterministic garbage collection. Going out of scope is deterministic, but the object that has gone out of scope might still be referenced from somewhere if the reference has "escaped". Sometimes automatic escape analysis can work when references escape, but not always. Would you like the object to have its destructor called even though it might be still be accessible? What would happen if the program subsequently tries to access the object? Most languages are naturally uncomfortable with tidying up some resoure while it still might referenced. For this reason languages prefer to leave it up to the programmer to explicitly manage destruction themselves. A perfect example is C#'s IDisposable interface. The language obviously "knows" that a disposable object needs cleaning up after it is used - that's what IDisposable means - but it cannot work out when this should happen. So it lets the programmer decide when that actually happens. If a programmer wants destruction based on scope then she should use the using statement. If she wants destruction based on some other condition then that is possible too. The language cannot make this decision. I hope that answers your question.
- michaelochurch 15y agoClojure has with-open, to the same effect. I don't think Scala has one natively but the Odersky book covers how to make one using a by-name parameter and an anonymous class.
- jlarocco 15y agoYeah, Python has "context managers" that let you do the same thing. Here's the Python equivalent: with open("text.txt") as inf: print(inf.read()) User defined classes that implement special methods __enter__() and __exit__() can be used as context managers. More info: http://www.python.org/dev/peps/pep-0343/ http://www.python.org/dev/peps/pep-0343/ For just file output/input Scheme has the "with-output-to-file" and "with-input-from-file" macros which redirect output and input to a given file. I vaguely remember Common Lisp having a similar thing, but I can't remember the name off hand.
- pjscott 15y agoCommon Lisp has with-open-file for reading and writing files. It works pretty much the same way as everything else in this thread, so I won't post example code, but you can see some here: http://www.lispworks.com/documentation/HyperSpec/Body/m_w_open.htm http://www.lispworks.com/documentation/HyperSpec/Body/m_w_op...
- Luyt 15y agoI often use: for line in open("name.txt"): print line # Or do something else with it.
- reinhardt 15y agoMe too when I'm lazy but we shouldn't; it happens to work fine on CPython but on implementations use garbage collection instead of reference counting (e.g. Jython) it leaks file handlers. The "with" statement is the right cross-platform way to handle resources.
- spullara 15y agoJava 7 has a implementation pattern built in for this now: String readFirstLineFromFile(String path) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); } } Anything that implements the AutoCloseable interface gets this behavior for free.
- draegtun 15y agoIn Perl you can just use scope: { open my $fh, '<', "text.txt"; print scalar <$fh>; } # $fh goes out of scope so file handle is closed
- piranha 15y agoThat's a bit different, Python without `with` does the same, but that's just property of garbage collector in this case.
- draegtun 15y agoCorrect. To mimic it exactly is straightforward though: sub with_open_file { my ($filename, $code) = @_; open my $fh, '<', $filename or die $!; $code->($_) for <$fh>; close $fh; } with_open_file 'text.txt' => sub { my $f = shift; print $f; }; And to add to my original answer it's not just the effects of GC that are handy but also arbitrary scoping. Here is an example of what you can do with nested dynamic scoping: our $rake = "in shed"; sub where_is_rake { say $rake } where_is_rake; # => in shed { # take rake out of shed local $rake = "rake in hand"; where_is_rake; # => rake in hand { # pile up leaves local $rake = "using rake"; where_is_rake; # = using rake } where_is_rake; # => rake in hand } where_is_rake; # => in shed
- WalterBright 15y agoIn D, this is done with scope guard (or you can use destructors): f = open("test.txt"); scope(exit) f.close(); print(f.read()); The scope(exit) causes the following statement to be executed at the exit of the scope, regardless of how it leaves (return, goto, fall through, throw, etc.). The advantage over try-finally is the 'finally' statement is associated with the open, rather than some arbitrary distance away.
- masklinn 15y ago> In D, this is done with scope guard Which is nowhere near as good, as the closing operation has to be setup explicitly. Go has the same issue with `defer`.
- WalterBright 15y agoThe various tradeoffs between try-finally, RAII, and scope guard is discussed here: http://www.d-programming-language.org/exception-safe.html http://www.d-programming-language.org/exception-safe.html Scope guard has a number of distinct advantages.
- stevecooperorg 15y agoC# and VB have the `using` statement; using(var db = OpenDbConnection()) { // read from db, connection closed on next curly. }