Why I love everything you hate about Java
magicscalingsprinkles.wordpress.com
magicscalingsprinkles.wordpress.com
Java's been out and big for 15 years -- every bad idea has had a big push for it in Java.
But the language? Something like a dozen keywords. With some really nice libraries like java.util.concurrent and the Collections API. Just because lousy designs have been written in Java doesn't mean it's a lousy language. It may be starting to get a little dated, but that's a different matter. It's basically becoming the C of the JVM at this point, with higher level languages like JRuby and Clojure to run in application space and Java as your platform space.
Also, all the nice libraries have been updated to use the new language features like generics and annotations.
Generics and annotations are pretty useful. What's the matter with them? Have you spent time developing with them? They're certainly better than having to cast all over the place.
RE: functions as parameters.. yeah that's kinda annoying. You can always do new Runnable() { void run() { doSomeStuff; }} but that's ridiculous. So you have a point there. Aside from that though, the language is suitable for most tasks, and requiring a little extra syntax when you want to pass functions around isn't the end of the world.
Anyways, I'm sure I'm arguing against the trendy masses here, and I have a clojure book too, just trying to set up the opportunity to use it for something real.. but there's a reason why most "real" back-end stuff that has to be performant, stable and reliable winds up getting written in Java these days. That includes Hadoop, Lucene and half of the NoSQL key-value stores that you're excited about :)
Anyway, be careful when using "big and accepted" projects to indicate ideal platforms. It takes 5-10 years for a project to become big and accepted. In the process, its technology platform has probably become obsolete, but continues on because of inertia. Your goal should be to shoot for what your role models would do now, with the benefit of 10 years of additional technical development, and not where they were 10 years ago.
1. Software projects have increasingly moved from the desktop (where having a complicated runtime is a non-starter) to the server (where you can control everything).
2. Failover and hot swap capabilities are increasingly demanded for consumer apps.
3. It's now viable, from an efficiency standpoint, to have a language that copies data structures around instead of mutating them.
4. There's been a groundswell of interest in new programming languages, probably mostly because of #1. This has opened the door for old languages that previously lacked mainstream acceptance. (See also Python for an example.)
I would suggest that you have focused on consumer apps you may want to look up the rest of the industry because much of the new hotness is really old news. There seems to be a trend where people pull out an old idea, give it a new name and start hyping it, but new ideas are uncommon in computing.
Factories == constructors meet partial application and functions passing. They seem to be objects only because Java lacks nice support for bare functions...
DI / IoC == ... well ... good design. You're simply limiting the amount of state and coupling.
Decorators, proxies, etc. - duck-typing and metaclasses are a bit more flexible here.
And the first example is just passing a function to a threadpool - there's nothing very tricky about it either...
It seems to me that author never used a dynamic language properly :(
f() { return x; }
g() { x=1; return f(); }
f() returns x it inherits from g(). A spectacular way to shoot yourself in the foot.Pre-CL Lisps had this by default. defvar is, as far as I can tell (still learning!) how you get at it now.
Here's what the classic problem of "how do I test my code using a fake service?" would be solved with dynamic scoping:
(defvar service <default service>) ;; in Common Lisp you have to declare that certain variables will have dynamic scope, otherwise they would be lexical
(defun some-function () (use service))
(defun test () (let ((service <fake-test-service>)) (do-something (some-function))))
This is more than global variables, because now you can plug in any service you want in any runtime context you need without affecting other code.
If this looks a bit like AOP, it's because applying dynamic scope to functions is the actual underlying mechanism behind AOP: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.113...
It could have been something similar to XML (like JSON or YAML), but that is not the point. Also, the verbosity of XML aligns itself well with the Java mindset.
"the Java mindset" - more utter BS. There isn't a 'Java mindset' unless you're a bad programmer who is ruled by his language instead of using languages as tools.
The "mindset" you have depends on how good a coder you are. Which is the same regardless of which language you decide to use to solve a particular problem.
As for the mindset, it seems to me that at least SUN was very busy churning out cookbooks for a lot of things. Mostly Enterprise Java - if you managed to avoid that, more power to you. But I think most people tried to do things the "official" way.
And the Java language is a pretty sane general purpose language. It's fairly easy to spot all the crap and avoid it.
In a very dynamic language like Ruby, open classes and method aliasing (e.g., alias_method_chain) mitigate this problem, but they don’t solve it. If you manipulate a class to add logging, all instances of that class will have logging; you can’t take a surgical approach and say “just objects instantiated in this context”.
This is not true in Ruby!
myinstance = MyClass.new
def myinstance.special_method()
puts "only on these instances!"
end
myinstance.special_method()
The author's point about avoiding unnecessary binding is well taken, but he should refrain from declaiming on languages he doesn't know that well.The part that Python/Ruby got right is that their culture says don't parameterize until you have to. While Java culture tends to build in generality for the sake of generality, whether or not the actual system needs it. Many systems don't, but if you use typical Java libraries, you need to pay the costs for it regardless.
There was a red-flag in one of your comments above: "since you don't control the code, this technique doesn't work". If you don't control the code enough to make necessary modifications, you have a cultural problem, not a technical problem. Fix the culture, not the code. You should be building the simplest system that possibly works, not hacking around code ownership restrictions.
Parameterization is useful when you have one piece of code that you know needs to work in multiple contexts, not when you're trying to make sure a piece of code will work in all possible contexts a priori.
http://www.lispworks.com/documentation/HyperSpec/Body/f_chg_...
http://transfixedbutnotdead.com/2009/07/07/moose-singleton-m...
At least I didn't until I monkeypatched MyClass#initialize at runtime. cackles
Seriously, don't do that. But it is fun to contemplate.
And you can always open the eigenclass of any object in ruby for the ultimate surgical operation (THIS INSTANCE, RIGHT HERE!). It's pretty much the ultima ratio regum of special casing in any object oriented language.
The main problem is that this encourages cargo-culting. Once someone has something working, they will just cut-n-paste-n-modify it in similar situations. Better to cargo-cult 10 lines of code than to write 5 of your own, right? The moving parts won't cut off your fingers as long as your fingers don't get too close.
(Normally I would rant about how "proper abstraction is not possible with Java", but it actually is. It just seems that the majority of libraries and programmers would rather cargo-cult than to design proper abstractions. And no, "proper abstraction" is not always "cut-n-paste from GoF".)
string fileContent = System.IO.File.ReadAllText(); Want to read it into lines? string[] fileLines = System.IO.File.ReadAllLines();
Want fine tuned byte by byte access? var fs = new System.IO.FileStream(path);
They certainly looked long and hard at Java before writing .net, and covered many of the sore points carefully.
Here's Ruby for comparison:
file_content = IO.read(filename)
file_lines = IO.read(filename).split("\n") file_lines = File.readlines(filename)
Not that it matters hugely :-)Microsoft was a lot more aggressive in how they extended the core libraries post-2.0. There was an amazing amount of baggage in the language by the time 2.0 came out.
FWIW, you can do the first two items you mention using the Apache Commons IOUtils class in Java. The latter is part of Java:
http://java.sun.com/j2se/1.4.2/docs/api/java/io/FileInputStr...
SingleFilenameFilter myFilenameFilter = new SingleFilenameFilter()
List myList = new File("/tmp").listFiles(myFilenameFilter)
Why should I have to create a class that implements FilenameFilter, just to filter on some file names? Especially in a one-off instance, why should I have to create a class that I will only ever use once?Why isn't there a default implementation? Something like:
public class RegexFilenameFilter implements FilenameFilter {
private String regex;
public RegexFilenameFilter(String re) {
this.regex = re;
}
public accept(File dir, String name) {
// matching here
}
}
Then I could just write: List relevantFiles = new File("/tmp").listFiles(new RegexFilenameFilter("^tmp\\.[a-z0-9]+$"))
Why should I have to create this class for every project (or create my own little 'utils' library)? It's easily one of the simplest usages of a FilenameFilter. File[] textFiles = directory.listFiles(new FileFilter() {
public boolean accept(File file) {
return file.isFile() && file.canRead() && file.getName().endsWith(".txt");
}
});And this doesn't even begin to cover everything I dislike about Java.
Well once you define the "java way" to be "build highly configurable code by providing a way to combine small granular pieces of code into larger chunks of functionality" (which is just Programming 101 , See SICP for e.g) it probably still makes sense to write the "java way" programs in Scala ;-)
Makes sense to me! :-P
As nostrademons says elsewhere on this thread ,"Parameterizing behavior is usually a good thing in any language, yes..."
Eclipse can make so many things in java drastically fast and easy. And I think that's where java shines. I'm yet to see as powerful an IDE for any other language. (Although I admit, I do not program for msft platforms and hence, never used msft ides)
Yes, Eclipse and IntelliJ do some pretty amazing things. I wish I had a toolset that nice for C/Python/whatever. By contrast, without the toolset in Java, you're sunk.
Then again, I wouldn't imagine or expect some types of development to be achievable without a rich toolset (FPGA work comes to mind). I just like to think of Java as a more general purpose language.
FWIW I hate IDE's, and the code produced by people using them gives Java a bad name for its verbosity and idiocy.
>> without the toolset in Java, you're sunk.
No, you're not. Try it. Use an editor, write some code. It's not rocket science.
(I also use "perl -d" as a REPL for Perl, which it does quite well)
And sometimes it's just not worth testing, because it's something like ``hmm, I wonder if 'intercalate ", " ["foo", "bar", "baz"]' returns 'foo, bar, baz'; ahh yes, it does.'' The only reason to test that is because you want your test suite to run slower.
Why write a unit test for a feature of the language? The Language designer probably already did that and all you need to do is write unit tests for your own code. I do a fair amount of clojure code now and find it highly useful for just running java code to see how it behaves. Which then helps me figure out how to code my actual code, which then will pass the test that I've already written.
I use vim, which when coupled with the right configuration and plugins can do most things your fancy IDE's can do, plus run in a temrinal over ssh.
For the record, in work I program a lot of Java and some C++, outside this, I work a lot in Clojure and Python, amongst other things (assembly, Boo, Yeti and recently F#).
Ideally languages and tools would allow you to begin with concrete & explicit code and gradually introduce increasing layers of abstraction as necessary. The problem I have with most Java frameworks is that they assume you're going to need a lot more abstraction than you likely need, so just getting an idea off the ground takes a lot of extra work.
It's really just worse is better all over again. The reason things like Ruby and Rails are so popular is that they let you toss together something that "works" so much faster. It's a lot easier to rewrite a good first-mover app than it is to try to hoist all that Java baggage into a new problem space you don't understand.
Come to think of it, isn't this exactly what Twitter did? If Twitter had been written as the article suggests would it have ever taken off?
Can we just get a moratorium on usage of "hipster" now? Everybody's using it wrong.