WHO DESIGNED THIS NIGHTMARE?
A Whirring, Bone-White Gleech, October 12, 2017, 06:13:41 pm
You've found the problem. No one designed it, many people designed it all at once, and whenever they disagreed they just made it more complicated to fix the problem.
See also: C++.
journeyman faguar, October 12, 2017, 06:24:20 pm
Consider the following:
def write(points, fname):
with open(fname, "w") as outfile:
for p in points:
outfile.write("<{}, {}>\n".format(p.x, p.y))
Wow, that's concise, innit? If you aren't familiar with python, the with-block will guarantee that my file gets closed when that block is exited, even if an exception is thrown, without me having to do anything. Note also that open() just kicks up a file-like object with a nice, tractable write method.
Now let's see that in C++.
void write(const std::vector<Point> & points, const std::string & fname) {
std::ofstream outfile(fname);
for(auto p: points) {
outfile << "<" << p.x << ", " << p.y << ">" << std::endl;
}
}
OK, so, unsurprisingly, it's a little uglier. Note the use of auto in that for-loop: type-declarations can get really ugly when you're using C++ templated containers, especially when it's a const-reference-to something. Auto doesn't really make that not true, it just makes it not my problem, which is good enough.
It's not obvious, but this also guaranteeably closes my output file, even if an exception is thrown. The
reason why would take some explaining, but it's true.
Now let's look at this trivial things in Java.
public static void write(Vector<Point> points, String fname) throws IOException {
BufferedWriter outbuffer = null;
try {
FileWriter outfile = new FileWriter(fname);
outbuffer = new BufferedWriter(outfile);
for (Point p: points) {
outbuffer.write("<" + p.x + ", " + p.y + ">\n");
}
} finally {
if (outbuffer != null) {
outbuffer.close();
}
}
}
I have so many questions. What are the responsibilities of those two classes, FileWriter and BufferedWriter? Doesn't FileWriter already have a write() method? Do I need the BufferedWriter? Is it providing buffering for non-buffered output? Why are those responsibilities split? Why doesn't the FileWriter just buffer by default and provide a flush() method like any reasonable implementation would? Why is this my problem as a user?
Why do I need a try/catch block if I marked the function as throwing? Well, that's for the finally block, to make sure the file is closed. But again, why the fuck is that even my problem? Why doesn't Java have a with() block or similar construct? Why does the close method itself throw an IOException? What the fuck am I supposed to do if that happens? Actually handling
that exception would make my code way more complicated, so I just gave up and marked the function as throwing. Why is the try block out-of-scope in the finally block? That makes using it for its intended purpose more annoying, to no benefit.
Many of these complaints are small things, but they add up, and they add up more in non-trivial cases.
My answer to all these questions: the java developers are a) way, way too conservative, refusing to implement features (like with blocks) that are common-place in every other language in 2017, or b) they're way to enamored with the whole "a clean object model as the only metaphor for programming, period" ethos that sort of defined the early Java community, or c) they're lazy idiots and just don't give a fuck. Or maybe some combination of all three.