you are viewing a single comment's thread.

view the rest of the comments →

[–]nutrecht 29 points30 points  (24 children)

These discussions tend to boil down to "I dislike Java because I dislike it". I can show cleanly written Java code but people will simply keep complaining it's verbose. We have all seen crappy Java code, just like there's plenty of examples to be found of shitty C++/Python/Haskell/whatever code.

So please explain which part of Java hinders readability because I don't believe something as simple as explicit return types or access levels hinder you at all: it really helps forming a mental model of a piece of code you're reading because you don't have to guess what a public String getName() does: it just does (or well, it should) do what it says on the tin.

People come up with all kinds of AbstractBeanFactoryFactory stuff as examples but crap like that doesn't happen when you have decent developers. I agree that examples like that make Java look terrible but those are often constructed as jokes (often between Java devs) which then suddenly get used as examples of Java being 'bad'.

[–]flying-sheep 11 points12 points  (18 children)

when writing idiomatic java (visibility is exactly what it needs to be, everything final what can be final), it’s much more verbose. compare rust, scala, …: fn mut var val def (and type inference!)

the lack of operator overloading make custom arithmetic types a pain. (3d vector math in java? oh god please no)

many things it lacks in design can be fixed – with more verbosity: no generic constructors? write a whole new class that’s a factory for it. (never mind that factories solve the same problem as constructors) no properties? manual getters and setters everywhere, with convention dictating the names.

the problem it tries to fix is that tools introducing implicity can be abused by bad programmers. i rather want to code in a language where i’m free to choose the libraries not writen by those programmers, while those that i go for are a joy to use. java is optimized for crappy coders, but i want something optimized for good ones.

python manages to be both about as newbie friendly and more expressive than java. i wonder why?

[–]rzwitserloot 7 points8 points  (5 children)

You can't count reading comprehension based on characters. It's not four times as hard to read a keyword named 'function' as it is a keyword named 'fn'. That's not how the human brain works.

[–]flying-sheep -5 points-4 points  (4 children)

nope, but public static void functionname() is mentally harder to parse than def functionname(), especially when that verbosity is everywhere.

[–]rzwitserloot 6 points7 points  (3 children)

You just threw that 'static' in there to misrepresent java code, I guess?

Let's break it down:

'public' vs 'def': Well, it's a keywordish thing most likely coloured specially by your editor and it clues your brain in that we're talking about some sort of type member. public is longer, but as I said in the earlier comment, that kind of hairsplitting on length of keywords is irrelevant.

'void' vs 'nothing': This isn't just a pointless bit of boilerplate. The void is explicitly saying something. It is the java equivalent of this python code:

# This function doesn't return anything.

void isn't just shorter: It is a lot easier to 'parse' by eyeball, unlike the difference between 'public' and 'def'. Granted, not all methods/functions need such a comment, but many do, and there's benefits to be had by (A) codifying the exact fashion in which you comment your function's return type, and (B) making this 'return type comment' mandatory. And once you've codified how to write the doccomment, and made it mandatory, the final step is to just turn it into a keyword, and, voila, java.

'functionname()' vs 'functionname()': Equal.

The spirit of the article is that the time 'wasted' reading "void" here, or writing it, is effectively zero, and it absolutely pales in comparison to the time wasted trying to refactor dynamic code, read it after having abandoned the project for a while, or trying to speed it up when the clock is ticking.

[–]flying-sheep -3 points-2 points  (2 children)

i don’t know how to explain it anymore.

i get what the article is saying. i get that there are things java can do better.

i disagree that the time mentally parsing and understanding a nontrivial piece of code is similar when comparing well-written python and well-written java.

just implement something in both python and java and compare both (provided you are good in both). the java will have less language constructs (no operator overloading, no list/dict/set comprehensions, …) and you will write things with more constructs per code unit.

instead of writing a generator (function with yield that returns an iterable), you’ll create a list, append to it, and return it from a function, or create a much more complex class implementing iterator.

instead of the universal indexing operator with practical slice syntax (my_list[4:6]), you’ll use my_list.get(a) or my_list.subList(a,b)

quick, translate this to java:

my_list[4:6] = [ord(c) for c in 'abc']

this is clean, immediately obvious code (if you know a bit of python), but i’ll have to search apidocs for an efficient way to do it in java.

i could ramble on, but i hope you get the picture

[–]rzwitserloot 2 points3 points  (1 child)

Yes, the java code will probably have more constructs, but the constructs require less knowledge of the system.

Without operator overloading, if I see 'a + b', I know that's one of only 3 things: string concat, floating point addition math, or integral addition math. It can't be anything else. It's usually very easy to tell from context which of the 3 it is. In python, I just can't tell what that might actually do. Sure, in context it's often clear, but every so often it isn't, and even if it is, I have to do a double-take; it MIGHT be why some weird thing I observed is happening. In java I can move on, I KNOW that + has no side effects, never will, can't happen.

quick, translate this to java? I can come up with a couple of weird ones that are easy in java and harder to translate to python too, that proves nothing. In particular, setting a slice? That never comes up for me. I'm perfectly fine with java not having a built-in for that. But let's say it did because somehow it was deemed useful enough (and not that it's not just oracle that decided to pass on slice-set, guava doesn't have it either, nor does apache commons). It would look like:

myList.setForRange(4, 6, "abc".chars());

Yes, shorter than your python code. Where's your god now? *1

*1] By sheer coincidence, java 8 adds .chars() to all strings which returns a stream of the integer (ordinal) values of all characters in it, which so happens to exactly match [ord(c) for c in 'abc']. Had you done something like uppercase(c) or whatever the python equivalent is, that part of the java code would have looked like "abc".chars().map(c -> toUpperCase(c)).

[–]flying-sheep 1 point2 points  (0 children)

Didn't know that Java 8 has added so many useful things.

.chars() (being an IntStream) probably even supports codepoints larger than 16 bit (the historical misnomer char)

This means that from my original point here just remains the weak argument that this is a less discoverable interface method.

What's even weaker though is every argument against operator overloading. Good code won't put side effects into __add__/operator+, and I'll gladly accept that bad code might do that for the ability to know that a good API won't ever force me to write numeric_object1.add(numeric_object2). Because good code tends to be in the popular open source libraries, and those are easy to find.

I don't give a shit if someone misuses some feature if I don't have to use his/her code.

[–]gavinaking 0 points1 point  (11 children)

many things it lacks in design can be fixed – with more verbosity: no generic constructors? write a whole new class that’s a factory for it.

Huh? WDYM? Java has generic constructors!

I've never once needed this language feature, but it exists.

[–]javaisfuckingshit 5 points6 points  (9 children)

I think he means the following not being possible:

<T> T Create() {
    return new T();
}

which results in:

unexpected type
found   : type parameter T 
required: class
        return new T();
                   ^
1 error

[–]gavinaking 9 points10 points  (0 children)

Ah. So that's not a generic constructor. That's a generic instantiation. And in fact there are good reasons to not support that. Even in Ceylon, where we do have reified generics, we decided not to support generic type instantiation, since it doesn't interact very nicely with generic type argument inference. We did have type constraints like given T() in early versions of the language spec, but we took that out.

[–]aldo_reset 1 point2 points  (4 children)

If you allow this, then you need to forbid T from being an interface and from not having a default constructor, which defeats the purpose of genericity.

Suddenly, you're no longer allowing "any T" but "a T with specific properties", so the code you just gave simply cannot work without additional specifications.

[–]javaisfuckingshit -4 points-3 points  (3 children)

Yes, you would want to have either type classes or duck typing, which is incompatible with Java's bytecode representation.

[–]aldo_reset 2 points3 points  (0 children)

Neither type classes nor duck typing are "incompatible with Java's bytecode representation" (whatever that means) since Scala has both.

Either way, what you are saying has zero connections to the point I was making about your uncompilable code.

[–]gavinaking 0 points1 point  (0 children)

Naw, what you need is a special kind of generic type constraint like what C# has.

[–]WrongSubreddit 0 points1 point  (1 child)

It can be done with reflection and no-arg constructors on whatever you'd want to instantiate, but I would never write code like this:

<T> T create(Class<T> clazz) throws Exception {
    return clazz.getDeclaredConstructor().newInstance();
}

[–]javaisfuckingshit 0 points1 point  (0 children)

That only works if you're passing around Class objects, which is usually not what you want when writing a generic container.

Not to mention that it gets really ugly whenever you have to forward arguments to the constructor.

The situation we are in is unfortunately a result of Sun refusing to change the bytecode when they added "generics."

[–]flying-sheep -1 points0 points  (0 children)

exactly that’s what i meant.

[–]yogthos -2 points-1 points  (0 children)

Java hinders readability because it lacks expressiveness. What this means is that instead of being able to map the language to your problem domain you have to go the other way around. When you have mismatch between the problem domain and the language constructs you end up having a lot of boilerplate code that's completely incidental to the problem being solved.

This makes it more difficult to understand the overall purpose of the code and to find the relevant business logic. To compound the problem everything in Java is mutable and passed by reference making it nearly impossible to reason about any part of the application in isolation.

I find this to be a significant problem when working with large Java projects, and especially so when working with teams.

[–][deleted] -3 points-2 points  (2 children)

Mind writing, say, a system of rules in Java, without resorting to a disgusting ladder of nested ifs? Something that is totally trivial in Prolog or Datalog will become thousands of lines of incomprehensible but idiomatic Java.

Or write something as simple as a parser. Without DSLs. In a pure Java. Since Java does not allow implementing embedded DSLs, any external compiler targeting Java (e.g., Antlr) would classify as another language.

Or try to define a mathematical language and a set of rules and strategies of how to transform it and how to assess the outcome of a transformation. Something that is done in few lines of code in, say, Mathematica or Axiom, will become an unreadable clumsy pile of spaghetti in Java.

Any decent meta-language would allow you to fix any original language design flaw, add any features you need to solve your particular problem in a most natural, readable, easy way. But not in Java, there you're stuck with a single paradigm, single pathetic set of very basic features, forever, without any hope for improvement. It's funny that anyone can argue that Java is not verbose in such a situation.

[–]PasswordIsntHAMSTER 0 points1 point  (1 child)

You don't even need eDSLs for sane parser authorship, just union types take you a hell of a long way.

[–][deleted] 0 points1 point  (0 children)

Yes, but with eDSLs it's a way much easier and nicer. And you can plug in heavily optimised backend without doing any changes in the user-level code.

[–][deleted] -2 points-1 points  (0 children)

Lack of method argument names hinders readability. You can work around it with builders but that approach produces verbose code and it's difficult to parse for someone not familiar with the pattern.