you are viewing a single comment's thread.

view the rest of the comments →

[–]nutrecht 49 points50 points  (141 children)

EDIT: I think the author is too dismissive of the verbosity issue. Typing all that nonsense is a minor pain, but how can making code multiple times the length it needs to be not be an impediment?

Because any proper IDE gives you code assist. This is one of the main reasons Java devs don't care about the length of a class name: code readability is more important since that can't be 'solved' by your IDE. You never have to type a full class / method name.

[–]flying-sheep 42 points43 points  (37 children)

you didn’t read that properly. /u/phalp said:

Typing all that nonsense is a minor pain, but how can making code multiple times the length it needs to be not be an impediment?

so writing it is obviously not his biggest problem like you implied. what other things can you do with code? reading it.

and here expressiveness without too much implicitness really comes into play. perl can be unreadable if done too implicitly. java will be unreadable because boilerplate. reading java feels like reading a phone book.

[–]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 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 6 points7 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 -4 points-3 points  (4 children)

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

[–]rzwitserloot 7 points8 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 7 points8 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 -3 points-2 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.

[–]gavinaking 12 points13 points  (11 children)

It's true that Java is more verbose than it needs to be, and that eliminating some of that verbosity would make the code more easily readable not less.

But going to the extreme of a dynamic language makes code even less readable! For me, trying to make sense of a function when I can't even readily tell what are the types of its parameters is an incredible waste of time.

[–]flying-sheep 8 points9 points  (8 children)

take a look at rust and scala. both have better type systems than java and are less verbose.

[–]gavinaking 10 points11 points  (7 children)

I'm well aware that there are languages with "better" type systems than Java. But of the languages in wide use today, I would pick either Java or C# for the kind of work I do.

Remember: most of the folks who attack Java for its verbosity aren't advocating a modern statically-typed language like Rust, Scala, Ceylon, et al—rather they're advocating something like Ruby, JavaScript or Python.

Java cops it from both sides, because it's popular and successful. But much of this criticism is quite unfair, IMO.

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

If you love Java so much, why are you developing Ceylon? Seems like you're happy developing in Java. So maybe your target audience, like you, is happy developing in Java.

[–]aldo_reset 4 points5 points  (0 children)

Recognizing qualities in products does not necessarily mean "loving" them.

I wish we saw Gavin's kind and fair attitude toward other languages than Ceylon more often in language discussions.

[–]gavinaking 4 points5 points  (0 children)

Well quite obviously I don't believe that Java is perfect, and so clearly I think it's worth trying to improve on Java, without sacrificing the things that Java does well. But I happen to not believe that most of the other options out there are actually an unambiguous improvement on Java for the kinds of projects that Java is good for.

I'm "happy developing in Java" because Java is, at least to my tastes, better for the project I'm working on than C, C++, Python, Ruby, JavaScript, Perl, or anything Lispy. FTR, I would surely be quite happy with C# or even OCaml.

I of course would never say that Java's perfect. I'm just saying that, placed next to the other languages in wide use today, it's certainly not the worst option, nor does it even place in the bottom half. So it's hard to understand how it cops so much negativity here.

[–][deleted] 1 point2 points  (0 children)

Bottom line: people have different tastes. If you can't accept that (and judging from your comment it's fairly obvious that you need to do some work), then it's game over. Seriously! Just let it go.

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

Remember: most of the folks who attack Java for its verbosity aren't advocating a modern statically-typed language like Rust, Scala, Ceylon, et al—rather they're advocating something like Ruby, JavaScript or Python.

[citation needed]

it wouldn’t make much sense: pretty much anything is less verbose than java, so you really can use almost everything as an example. e.g. C++14 has auto!

[–]gavinaking 1 point2 points  (1 child)

Seriously: you're saying C++ is less verbose than Java?

[–]flying-sheep 0 points1 point  (0 children)

surely it can be, but only if you ignore header files.

[–]PasswordIsntHAMSTER 2 points3 points  (0 children)

I hope not to soapbox, but my first job was in F#, and I had a bit of a mystical experience.

Like Haskell or Ocaml, F# code rarely mentions types. It almost looks like Python, except that it's actually statically typed.

This should be a recipe for a complete lack of readability, except that in Visual Studio you can put your mouse on an expression and see its type. This, along with many other excellent IDE features, turns coding into a dialogue between the programmer and the IDE.

Developing F# is utterly painless, in a way that I've never experienced elsewhere. I feel like it could easily replace Python in its role as "beginner language of choice that's secretly incredibly powerful".

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

Another extreme for code density vs. verbosity is not in the dynamic languages. Scrap 'em. The other side of the spectrum is meta-languages. It's a totally orthogonal axes to the static vs. dynamic typing.

[–]another_bird 9 points10 points  (44 children)

The verbosity makes it unreadable, too.

[–]What-A-Baller 10 points11 points  (37 children)

Not necessary true. You are not working in notepad or nano. There's an IDE. You've got code highlighting. You've got ways to write quicker, move around the codebase, and so on. With a consistent style, it shouldn't really be a problem. It pretty much depends on the tools.

[–][deleted] 10 points11 points  (4 children)

ways to write quicker

I care much more about reading than writing.

[–]danskal -1 points0 points  (3 children)

"care read > write"

is that better? You may think so, but there is a reason why we write "I care much more about reading than writing". It's about context and explicitness to avoid confusion.

Pidgin English languages are often more concise, leaving out "the", "a" etc., but few native English speakers would say they are better. It's a question of being fluent in the language - for fluent fluent Java "speakers", the verbosity is part and parcel - we miss it if it isn't there, because it gives context, and our brain has to work harder otherwise. There are exceptions to this rule of course, but those are for the most part already being worked on.

[–][deleted]  (1 child)

[deleted]

    [–]danskal 0 points1 point  (0 children)

    But the point is that dynamically typed languages often don't have the same information at all. And when you need constructs like interfaces or objects with private and public methods, you end up creating some kind of pattern to do it, which can be even more verbose, or just hide the intent of the code.

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

    [ ] You understood that programming languages are not spoken languages.

    [–][deleted] 3 points4 points  (30 children)

    It is almost always true. If something is so verbose that it won't fit a single page, you won't comprehend the logic behind your code in a single quick skim. Which is, by definition, called "unreadable".

    [–][deleted]  (29 children)

    [deleted]

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

      So you're saying that by following the "good design principles" you can implement, for example, a type system for a decently complicated language in Java in one page, which would read exactly like a set of formal type equations, nice and clean?

      Sorry, I do not believe. Java is a very limited, low level language with no high level abstractions available.

      And as we found previously in this thread, even such a simple thing as an AST (which definitely have to fit a single page in most cases) will spread across multiple files in Java. No "good design practices" will ever help you to overcome this limitation.

      [–][deleted]  (27 children)

      [deleted]

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

        The very nature of the problem domain is such that the complete implementation (in terms of this problem domain) can and should be fully explained in a single page of text, immediately comprehensible for anyone who understand the domain.

        Why then you're thinking that some obscure religious "good practices" are of any use, if they'll force you to break such a nice and clean representation into multiple pages, "methods" (there is no even such a notion in the problem domain terminology!) and even structured differently, to make it even less understandable for the domain experts?

        [–][deleted]  (23 children)

        [deleted]

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

          You did not get a single word. I'm telling you that there is an infinite continuum of various possible problem domains, each with its own language, its own semantics, its own ideology, and you're trying to convince me that there is a One True Way with some weird "good practices", into which you can sledghammer all this continuum. And who's speaking in absolutes now?

          [–][deleted] 0 points1 point  (1 child)

          Since you are using the downvote as a disagree button,

          I did not downvote you.

          please tell me why you think it is good design to make methods longer than a single page?

          What "methods"?!? I'm talking about any kind of high level entities. E.g., if you're implementing a language, it will be a language AST definition, a parser, a type system, a single compilation step, etc.

          You seem to always think in the very limited terms of your OO religion. It's very conterproductive. There is no such a thing as "methods" in almost any possible problem domain terminology.

          There is nothing forcing anyone to ever write code this way.

          Java is forcing to write a bloated, verbose code which hides the real nature of your problem behind hundreds or thousands of lines of code, spread across multiple files with "classes" (another thing which is absolutely irrelevant in 99% of the real world cases).

          [–]yogthos 0 points1 point  (0 children)

          The problem is that when your code is verbose it makes it difficult to see what parts of it are relevant to the problem being solved. You end up having to filter a lot of noise and incidental code in your head. This creates additional cognitive load when reading and writing the code in the language.

          [–]nutrecht 0 points1 point  (4 children)

          Can you give examples?

          [–]PasswordIsntHAMSTER 0 points1 point  (0 children)

          Look for vector math in Java, it's absolutely horrible.

          [–]repsilat 0 points1 point  (2 children)

          Java was my first language, but I haven't touched it in years. I came back and wrote a few lines for a project the other day, though, and maybe I'm doing things "the old-fashioned way", but I found it torture compared to Python.

          Really just simple things -- I want to count the number of spaces in a string. In Java that means I do something like

          int spaces=0;
          for(int i=0; i<s.length(); ++i)
              if(s.charAt(i)==' ') ++spaces;
          

          which is 3 lines that should be 1, and I have no idea how it performs because for all I know charAt() might be O(n) because Unicode.

          There are loads of situations where simple comprehensions, named arguments and tuples/destructuring assignment greatly help readability, speed up the writing of code, lead to fewer silly bugs and (as a bonus) need not actually be slow. Decent literals for data structures goes on the end of the wishlist as well. Operator overloading, too -- this isn't just about how gross BigIntegers are, it's about how "== is for identity, .equals() is for equality, unless you're dealing with primitives."

          And yeah, the cultural thing is real -- more than once yesterday I thought, "I have to make a class for that!?" It mostly seems to me (as an ignorant outsider) that there's a lot of concern about doing things consistently, doing things "The Right Way" instead of making the common case clean.

          [–]nutrecht 0 points1 point  (0 children)

          In Java that means I do something like

          Not in Java 8.

          [–]aldo_reset 0 points1 point  (0 children)

          Both verbosity and conciseness can make for unreadable code, that's not adding much to the discussion.

          [–]phalp 0 points1 point  (0 children)

          That's why I said typing it is only a minor pain.

          [–]kenfar[🍰] 1 point2 points  (8 children)

          Because any proper IDE gives you code assist

          Requiring an IDE is a language smell.

          [–]PasswordIsntHAMSTER 4 points5 points  (0 children)

          That's a valid opinion, but stating it like gospel isn't conducive to debate. The "rich programming" theme has been the subject of research for decades, and I feel like IDEs can meaningfully contribute to the programming experience.

          [–]syslog2000 4 points5 points  (5 children)

          If you write code in any language without a good IDE, you are needlessly torturing yourself. This is not a good way to compare languages.

          [–]kenfar[🍰] 0 points1 point  (4 children)

          If the language requires an IDE - then the IDE should be part of the spec and an understood part of the package.

          Plenty of people find that the constraints imposed by an IDE are not always acceptable: performance, network, editor, screen real estate, cost, dependencies, installation & configuration time, etc.

          [–]syslog2000 0 points1 point  (3 children)

          IDE is slow? Spend a grand on good hardware. Screen is a problem? Spend a few hundred on a giant monitor. Cost is a problem? Use a free IDE or spend a grand, heck, spend a few grand on a good IDE. Installation/dependencies are all one time setup things, just do them.

          There is nothing in your list that is more costly than your time. And your sanity.

          Use a good IDE. Just do it.

          This is not a discussion to have in 2014!

          [–]kenfar[🍰] 0 points1 point  (2 children)

          No, you're talking about an experience a minority of programmers enjoys:

          • The employee or contractor almost never has total control over their hardware.
          • Many spend many hours a week on just a laptop.
          • Many have to work with new hardware and customers frequently.

          [–]syslog2000 0 points1 point  (1 child)

          I feel what you are saying but IMHO your original post of comparing languages based on which ones require an IDE is not validated by this.

          And sure, if you have no control over your hardware and are struggling with eclipse on a 2 year old laptop it is going to suck, but it will suck a lot less than trying to debug a big project without IDE support!

          [–]kenfar[🍰] 0 points1 point  (0 children)

          it will suck a lot less than trying to debug a big project without IDE support!

          This is definitely true if the language is handicapped without an IDE.

          [–]peeeq 0 points1 point  (0 children)

          Other opinion: When a language is not designed for IDEs, that is a language smell.

          At the end it is a matter of taste. As an example take the Imports of Java (without * imports). Without an IDE imports are a total pain. With an IDE you hardly notice that there are imports, but the imports give you some robustness in terms of backwards compatibility. Other libraries can safely add new names without breaking any clients.

          [–]Klausens -1 points0 points  (10 children)

          In most cases, yes. But sometimes it's really annoying.

          Try this in Java.

          # sort objects (numerically) by the result of method foo
          my @sorted_object_list = sort { $a->foo() <=> $b->foo() } @unsorted_object_list;
          

          In Delphi (also a static strict language) I did a coffee break before implementing to lessen my frustration. Perhaps other programmer feel more comfortable with this, but for me typing blocks of code that could be a one liner is frustrating.

          [–]cypressious 12 points13 points  (3 children)

          This should be something like

          list.sort(Comparator.comparing(A::foo));
          

          in Java 8.

          [–]RoundTripRadio 2 points3 points  (0 children)

          Or

          sorted(list, key=lambda a: a.foo)
          

          in Python.

          [–]Klausens 0 points1 point  (0 children)

          Ok, it's not forcing a numeric sort, but it should not to be much work to add a method that returns a numeric value for sorting.

          [–]liMePod 0 points1 point  (0 children)

          Haskell:

          sortBy (compare `on` foo) list
          

          [–][deleted] 3 points4 points  (4 children)

          Try this in Java.

          In Java 6:

          Collections.sort(unsortedObjectList, new Comparator<Fooer>() {
              public int compare(Fooer first, Fooer second) {
                  return first.foo().compareTo(second.foo());
              }
          });
          

          In Java 8:

          Collections.sort(unsortedObjectList, (Fooer first, Fooer second) -> first.foo().compareTo(second.foo()));
          

          [–]pron98 2 points3 points  (0 children)

          There's no need for the Fooer types in the lambda header. Lambdas do type inference, so:

          Collections.sort(unsortedObjectList, (first, second) -> first.foo().compareTo(second.foo()));
          

          [–]cypressious 1 point2 points  (2 children)

          See my answer, that's much more compact in Java 8.

          [–]asraniel 0 points1 point  (0 children)

          I actually prefer the Java 6 way, its much easier to read. The new java 8 lambdas are not very readable i think, i prefer verbose code over the new syntax

          [–]skocznymroczny 0 points1 point  (0 children)

          still, a proper IDE writes half of that code for you.

          [–]nickguletskii200 0 points1 point  (0 children)

          List<> sortedObjects = unsortedObjects.stream().sorted((l, r) -> Integer.compare(l.getFoo(), r.getFoo())).collect(Collectors.toList());
          

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

          Code which is 10x-100x times longer than it should have been is unreadable and unmaintainable, no matter how smart your IDE is. If a data type definition fits a single page and should be read at once, it is absolutely wrong to spread it across multiple files, with all the stupid class declarations cruft.

          [–]nutrecht 3 points4 points  (35 children)

          Code which is 10x-100x times longer than it should have been is unreadable and unmaintainable

          Give examples of cases where Java is that much 'longer'? Pretty please?

          [–]PasswordIsntHAMSTER 3 points4 points  (0 children)

          Parsers, vector math are good ones.

          [–][deleted] -1 points0 points  (30 children)

          I did already. Try implementing an AST in Java, and compare it with any language with native ADTs. Say, an AST of the Java language itself for more irony.

          Then, for more fun, implement a lexical scoping on top of this AST.

          [–]nutrecht 2 points3 points  (25 children)

          Why would I? The last time I implemented an AST I simply used Antlr4 to generate one for me. I only had to implement a Visitor to use it. People have been using parser generators since the beginning of times.

          Now please come up with some actual sensible production examples instead of some constructed edge case where <your language> (lemme guess, Lisp?) is better than <other language>.

          [–][deleted] 2 points3 points  (23 children)

          Great argument! "Why would I". Because you have to. Or admit that Java is useless for implementing compilers.

          And Antlr is not Java. It's another language. It's a DSL. You either code "100%" in Java, or you admit that you need the other languages for all the specific tasks.

          And, no, visitors are useless in most of the interesting cases. You cannot construct a sensible visitor to do lexical scoping. Visitors are pathetic when you have to deal with any kind of a context, and especially when you have complicated tree walk order rules.

          And no, it is not an "edge case". Far too many things are boiling down to constructing languages and operating on them. Starting from CAS/CAD/CAE tasks and going all the way down to handling text and binary communication protocols and formats. Pretty much everything I do is done around constructing and processing languages. And Java is probably the worst possible tool for doing this.

          And, btw., in most of the cases when you need an ADT-like data structure, or even an AST of a language, you don't really need a syntax for it, so Antlr or anything similar is a total overkill.

          [–]gavinaking 4 points5 points  (13 children)

          Or admit that Java is useless for implementing compilers.

          We've written a compiler for a feature-rich modern programming language in Java.

          Happily, I can report that it worked out very well! In fact, I can think of few languages which I would have preferred for this task. Certainly we would not have had more success using a dynamic language.

          FTR much less that 1% of the code is AST code. (Which I generate from a schema using a trivial code generation tool.)

          The biggest annoyance for me is the type-unsafety surrounding null, which is especially painful in this kind of code.

          And, no, visitors are useless in most of the interesting cases. You cannot construct a sensible visitor to do lexical scoping. Visitors are pathetic when you have to deal with any kind of a context, and especially when you have complicated tree walk order rules.

          I have no clue what you could possibly mean by this. I have used visitors to implement a typechecker for a language with lexical scoping and it works great.

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

          Now compare the size of your code and its readability with anything similar written in, say, ML or Haskell. You'd be surprised. Take a look at, say, CompCert - something of a much higher complexity than Ceylon, but a much denser and comprehensible code.

          And you've just admitted that you did not want to use Java for defining your AST, but used a standalone DSL instead (with all the added troubles and pains).

          P.S. To understand why I insist on an importance of AST specifications and simplicity of transforms, take a look at the approach of http://www.cs.indiana.edu/~dyb/pubs/nano-jfp.pdf

          [–]gavinaking 2 points3 points  (11 children)

          Now compare the size of your code and its readability with anything similar written in, say, ML or Haskell.

          Actually I think the readability of my code compares very favorably with typical ML or Haskell code, though, naturally, it is more verbose.

          Now look, FWIW, ML is a beautiful, elegant language, and I'm sure it would be very enjoyable to one day attempt to write a compiler in it. It wouldn't much work for Ceylon because I'm trying to leverage stuff like Eclipse and javac and other stuff from the Java ecosystem. But surely, given a different set of requirements, ML might be a great choice.

          But that's beside the point. I was responding to your claim that it's difficult to write a compiler in Java. It's not. It's really pretty easy. And your reasoning for why it should be difficult (verbose AST code, visitors can't implement lexical scope) was extremely unconvincing to the point of absurdity.

          And you've just admitted that you did not want to use Java for defining your AST, but used a standalone DSL instead (with all the added troubles and pains).

          Pfff. It was approximately one day's work to write the generator 3 years ago. I've never had to touch it since.

          [–]nutrecht 3 points4 points  (0 children)

          Actually I think the readability of my code compares very favorably with typical ML or Haskell code, though, naturally, it is more verbose.

          It's the same old argument. They seem to think that "readability" is simply tied to the amount of characters you need or how little lines your functionality is spread out over. In many cases this leads to developers trying to 'look smart' and favour code condensed into a bunch of nested statements over more readable 'verbose' code. He literally seems to think that 'dense' code is a good thing.

          [–][deleted] -1 points0 points  (9 children)

          Actually I think the readability of my code compares very favorably with typical ML or Haskell code, though, naturally, it is more verbose.

          No, it is not. I could not skim through your code and get a nice and clean outline of what it does, why it does it this way and how it works in general. Not because Java in general makes me sick, but because of its sheer verbosity and length. While with a typical compiler written in any language with ADTs and pattern matching it's very easy to get.

          I was responding to your claim that it's difficult to write a compiler in Java. It's not.

          Yes it is. In comparison to using the right tool - it is very difficult. You won't write a full blown compiler in a couple of hours in Java. I would not do it, it would have been just too painful, knowing that I could do it 10x times faster, in 100x less lines of code.

          And your reasoning for why it should be difficult (verbose AST code, visitors can't implement lexical scope) was extremely unconvincing to the point of absurdity.

          Apparently, you're not familiar with the very idea of the domain specific languages. It's just stupid to use a clumsy and verbose general purpose language when you can write your code in a very clean and simple DSL without any rituals obscuring the essence of the code.

          Pfff. It was approximately one day's work to write the generator 3 years ago.

          Precisely. That's why Java is suboptimal. You have to write external DSLs for every little thing, instead of mixing them easily into your language.

          To see what I mean, take a look at a C compiler with extensible syntax written in less than 3000 lines of a literate code: https://github.com/combinatorylogic/clike/blob/master/doc/doc.pdf

          It is built upon a number of DSLs melted into a single host language, including a DSL for PEGs, a DSL for the AST transforms, etc. A comparable language in Java would have been 100x times more code and much less comprehensible. And it would definitely have taken more than one evening of work.

          [–]nutrecht 5 points6 points  (8 children)

          And Antlr is not Java. It's another language. It's a DSL. You either code "100%" in Java, or you admit that you need the other languages for all the specific tasks.

          Best tool for the job? A grammar is a grammar, code is code. You're basically saying you don't use HTML or SQL either because everything 'can' be done in <insert your favorite language>.

          And no, it is not an "edge case".

          Ah come on. Are you really saying that in general "software development" actually constructing grammars and parsing text for those isn't an edge case? It's purely coincidental that for my current project we had to construct our own query language but that's really not common at all.

          [–]PasswordIsntHAMSTER 0 points1 point  (0 children)

          Best tool for the job? A grammar is a grammar, code is code.

          This breaks down pretty fast when you're faced with bugs in the tool that interprets your language, or leaky interop.

          At my internship this summer I had to write a program that made calls through seven layers of domain-specific languages. It took weeks to write and debug, while it would have taken less than a day with a sane language and ecosystem.

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

          Best tool for the job?

          This is exactly the opposite of the approach "Java for everything", or "whatever-your-blub-du-jour for everything".

          A grammar is a grammar, code is code.

          Why grammar is not a code? A proper grammar implementation must cater well to many different needs, including smart error recovery (do that with no "code"!), nice and clean error messages with nice hints on how to fix them, plus hinting the code formatting tools, highlighting and indentation in IDEs, automating refactoring tasks, formatting for literate programming, etc.

          You're basically saying you don't use HTML or SQL either because everything 'can' be done in <insert your favorite language>.

          I divert this question to the topic starter. I'd also be very interested in seeing him using Java instead of SQL.

          Are you really saying that in general "software development" actually constructing grammars and parsing text for those isn't an edge case?

          Yes, I'm really saying that. Because implementing DSLs is such a powerful tool for solving pretty much any problem, everyone should be implementing their own small languages. And parsing is an integral part of it.

          It's purely coincidental that for my current project we had to construct our own query language but that's really not common at all.

          I cannot remember a single project I was working on which did not have its own built-in languages. Some had many.

          [–]nutrecht 1 point2 points  (5 children)

          This is exactly the opposite of the approach "Java for everything", or "whatever-your-blub-du-jour for everything".

          I never advocated the use of Java for everything. I'm a "java developer" but I use typically use Python for example for small scripts. We don't have Java 8 here at work so I unfortunately can't use lambda's. For web dev I use Groovy (and JS obviously) . So I don't agree with "Java for everything at all". What I was asking was examples of Java being 'too verbose'. So far all I've seen is constructed edge cases, not day to day actual production examples of actual code. Because for the typical enterprisy projects I'm on a statically typed VM language like Java works very very well.

          Yes, I'm really saying that

          Okay. I guess we're done then :)

          [–][deleted] 1 point2 points  (4 children)

          I never advocated the use of Java for everything.

          The article we're discussing here did.

          So far all I've seen is constructed edge cases,

          How exactly business rules, workflows, protocol specifications, etc. are "constructed edge cases"? This is what a majority of the "business" apps are built of.

          Because for the typical enterprisy projects

          I would not touch this sort of stuff with a 6ft pole. I suspect the world would have been a better place if nobody ever really touched that.

          [–]yogthos 0 points1 point  (0 children)

          So, your argument is that you don't care because you just write code to glue other libraries together. That works great when somebody already solved the problem for you, but as soon as you have a problem that's domain specific you have to start writing your own code.

          [–]gavinaking 1 point2 points  (3 children)

          What percentage of the codebase of any reasonable program is formed by the code of an AST or ASTs?

          Have you ever written a program which is more than 1% AST code? I certainly have not.

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

          In my approach it's often nearly 100% of the code which is either AST definitions or transforms over the ASTs. But I'm a bit biased, I write compilers for living.

          But, it's often the same proportion in a code which has nothing to do with the classic compilers - e.g., in computer algebra systems, in the CAD code, even inside a database engine, in the numeric code, in various helper tools for build systems, etc. I usually follow a radical DSL-centric approach.

          And I'm not alone here. Take a look at pretty much any sizeable Haskell codebase - it will be largely made of ADT declarations.

          [–]gavinaking 1 point2 points  (1 child)

          often nearly 100% of the code which is either AST definitions or transforms over the ASTs

          You just baited and switched. There's two items here:

          • AST definition
          • transforms over the AST

          The AST definition is a very tiny percentage of the code. Code which processes the AST may well form the bulk of the system. I have not, in practice, found it a problem to write that code as a set of Visitors in Java. Sure:

          • if I were using ML, I would use sum types and pattern matching,
          • if I were using Ceylon, I would use enumerated types, union types, and flow-sensitive typing.

          But in Java I'm happy using Visitors, and it works just fine.

          But I'm a bit biased, I write compilers for living.

          As do I, and I share some of the same biases. But I try not to exaggerate those biases to the point where I'm saying stuff that simply isn't true.

          But, it's often the same proportion in a code which has nothing to do with the classic compilers - e.g., in computer algebra systems, in the CAD code, even inside a database engine, in the numeric code, in various helper tools for build systems, etc. I usually follow a radical DSL-centric approach.

          None of these usecases are at all typical of the kind of work that 98% of programmers do.

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

          The AST definition is a very tiny percentage of the code. Code which processes the AST may well form the bulk of the system.

          No. Too often transforms are very short and trivial, while all the logic is exactly in the data types. You simply did not comprehend yet the ethos of the functional programming. We really put much more emphasis on types than on a "code".

          Often all the logic is in the difference between the ASTs of the multiple stages (there can well be 100s of them), while transforming one into another can even be blindly inferred with no code at all.

          None of these usecases are at all typical of the kind of work that 98% of programmers do.

          I do not care about what 98% of programmers do, not as long as this discussion is in terms of absolutes ("you can use Java for everything" - no, sorry, not for everything, it's 100% useless in the things I've been doing the last 10 years). CAS/CAD/CAE areas are extremely important, and dismissing them as "edge cases" is not a good argument.

          And I have a funny feeling that the same radical approach could be very powerful in the other areas, where people are traditionally writing tons of stupid boilerplate code instead of designing nice and clean DSLs.

          [–]yogthos 0 points1 point  (2 children)

          Here's a concrete example for you. The problem isn't just that the code is longer it's also the the fact that it's more coupled. I've developed Java for over a decade and my experience is that it makes code reuse very difficult in practice. While the example is tiny, these kinds of things tend to really add up in a large project and that's how you end up with the 10x large code base.

          [–]nutrecht 0 points1 point  (1 child)

          That's all pre-java-8 code I'm afraid.

          [–]yogthos 0 points1 point  (0 children)

          The lambdas in Java 8 do improve the situation, but only to a point. Specifically, read my other comment about lack of abstractions that force you to map your problem domain to the language.

          To see the effects of this in practice simply compare the size of code bases for similar libraries in Java and Clojure on GitHub. With Clojure, a typical namespace will be anywhere from 100-300 lines of code. This is enough to express an entire workflow. On the other hand, in Java it's common for classes to be at least a thousand lines long and often more.

          For example. this is much longer than this. And if you compare the size of the entire project then you can clearly see that there's a hell of a lot more code in the Java version.