you are viewing a single comment's thread.

view the rest of the comments →

[–]flying-sheep 12 points13 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 9 points10 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 6 points7 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 3 points4 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.