10 ms·
It is a recurring theme for people to point out how verbose a hello world program is in Java: class HelloWorldApp { public static void main(String[
by nayuki 8y ago
It is a recurring theme for people to point out how verbose a hello world program is in Java:
class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
For argument sake, let's compare it not to Lisp but to Python instead:
print("Hello World!")
Once you get proficient in a language and start writing larger programs, your perspective can change entirely. What appears to be verbose in the Java version starts to make sense. For example:
* In Java the top level only contains classes and interfaces. All functions must be put inside a class, and I believe this design simplifies conceptual understanding. Whereas in Python, you have a distinction between top-level variables and functions versus fields and methods bound in classes.
* Python always executes the top level, so you end up with awkward idioms like: if __name__ == "__main__": main(sys.argv)
* Static typing versus dynamic typing. We all know this debate, so I won't repeat it. (This is regarding void and String[].)
* The "public" keyword might seem like noise, but in Python you denote private by prefixing the name with one or two underscores.
* Do you really want print() to be so easily accessible in the top-level namespace? It seems to me that the bigger an application gets, the worse it is to easily litter the codebase with print statements.
* You still eventually need to learn what "@staticmethod" means in Python. Java just forces this learning early on.
- saagarjha 8y ago> Do you really want print() to be so easily accessible in the top-level namespace? It seems to me that the bigger an application gets, the worse it is to easily litter the codebase with print statements. Yes? It's great for debugging, which is generally what you'd use a print for anyways in a large application.
- judgardner 8y agoWhats even better than print for debugging is using a debugger...
- ggambetta 8y agoDoesn't quite work when debugging a distributed system, though. You end up adding a lot of "distributed print", AKA logging.
- judgardner 8y agoFair enough, but attaching multiple debuggers across several interacting components with conditional breaks gets me there faster than incrementally inserting progressively more print statements, in a dev environment. Proper logging is a given doping out problems in a production system to then verify and correct in dev.
- sieabahlpark 8y agoLogs aren't a bad thing and they aren't going away. Whoever let's you setup debuggers on prod should be fired.
- judgardner 8y agoAgreed, great logs are great. My comment explicitly stated dev environment, not prod, for debugger usage.
- canhascodez 8y agoNo one said otherwise, and the comment you replied to specifies "in a dev environment". The language you are using is unnecessarily combative: this is likely to inhibit the adoption of your ideas.
- rurban 8y agoOnly with python. With LISP it's the common case to debug prod. I would rather argue that such incompetent managers who speak such nonsense need to be fired.
- protomyth 8y ago
- rococode 8y agoYou really should be using a logging framework instead though, if you're working on a large application.
- akvadrako 8y agoYou use logging for production, but if you just want to see what a value is while when you run your program in the IDE and might not for a logger imported, print is handy.
- rpeden 8y agoIf you're running from an IDE and want to inspect values, why not just set a breakpoint?
- tormeh 8y agoDoesn't work with multithreaded applications and works poorly with non-deterministic behavior, so sometimes you just have to print lots of info and see if anything interesting pops up. It also requires knowledge about tooling for the language you're working on right now, which as a polyglot you might not care to learn.
- all2 8y agoComing from python I like to set a breakpoint, and dive in with pdb. It's super easy to navigate through the stack frame and poke around to see what all the variables are. I get more out of inspecting state from inside of pdb than I do out of print statements. On the other hand, I tend to use only print statements when I'm roughing in a program in an iPython Notebook. This gives a sort of visual documentation when navigating a library that I'm new to, and allows me to glance back at a verbose description of otherwise opaque data structures.
- LoSboccacc 8y agoNah there's debugging for that
- WaxProlix 8y ago
- smacktoward 8y agoBut “forcing learning early on” is exactly the problem. Approachable languages lead you up their learning curves in small, easy steps. The more knowledge you require newbies to swallow in one bite, the greater the number that will choke. (Not that anyone would call Lisp approachable either, of course.)
- kungtotte 8y agoAgreed. I went back and read the original discussion on HN about this blog post and one commenter phrased it as such: You need to learn and memorise 15 facts to fully grok the Java Hello World snippet (including how to compile and run it), for Python it's only four facts. That's a big difference in cognitive load.
- TeMPOraL 8y agoAgreed. When asked, I keep saying that Java is not the best "first language" to teach to a person, because it overwhelms people with concepts from the get-go. A normal person who's sincerely trying to learn, when shown the Hello World will ask about everything - what is this "class" and why it's needed? What does "public", "static" and "void" mean, and why they're written. What "System.out" is? Not to mention, the package declaration at the top of the file. All of those things have reasons for them, but when explaining this to a novice, you'll have to initially handwave most of those reasons away. That seems very uncalled for, especially when the basic abstraction you're trying to teach is that "computer executes simple instructions top to bottom, one at a time, and everything is built out of those simple instructions".
- xiaq 8y ago> In Java the top level only contains classes and interfaces. This design makes sense from conceptual purity, but Java is never a conceptually pure language. It distinguishes value types and object types, for instance. Not allowing free functions is really just a poor design choice. Worse, the proliferation of single-method interfaces (which are really just functions) and static methods (which are in most cases really just free functions) really prove that free functions are useful. Java just makes it harder to use them.
- jayd16 8y ago>Not allowing free functions is really just a poor design choice. I don't see why. The verbosity is pretty minimal and you enforce the availability of a privacy scope you wouldn't have had. ie private static methods and members that your public statics can use. Although, pure functions are nice if you can't trust the code you're calling won't surprise you.
- tasuki 8y agoI think this has to do with naming. Naming is generally hard, with free functions you must name the function, in Java you must also name the class. If you could show some examples of single method interfaces whose naming makes sense, I'd be delighted!
- rococode 8y agoTotally agree with you - I like Java precisely because it's so verbose. I'd rather have to type 20% more than spend 20% more time figuring out other people's code. And honestly, I always feel that the Hello World example is kind of biased. It's more an example of Java's way of launching a program being verbose because every program requires a certain minimal structure. But for the rest of the entire Java language that's not the main method, the only real "verbosity" comes from having to declare types, which is pretty much just a requirement of statically typed language and isn't so specific to Java itself. I've written reasonably large amounts of code in Python, Javascript, Ruby, Racket, StandardML, etc. Every language has its own little forms of "beauty" - chunks of code that are particularly short and pretty to write in those languages. And I do get a certain amount of satisfaction doing trickier operations in a couple lines in languages like Python. But I always end up preferring Java's more verbose style because I don't want to have to think about the correct syntax to maximize my code's stylishness.
- sidlls 8y agoThe kind of verbosity you describe isn't really the issue in my view. The contentious verbosity is theKindWhereVariableNamesLookLikeThis and "fluent" programming style that turns "assert(testRes == expected)" into "assertThat(testRes).isEqualTo(expected)". It's excessive and removes value most of the time.
- jimmyspice 8y agoWell the fluent style is more verbose, but has the advantage of telling you more information about what went wrong. You get a report telling you that "x was not equal to y" rather than "expected true". The verbosity is way more helpful to me.
- polityagent 8y agoor you can use a language with macros, then a testing library can report the code being evaluated and the values in it.
- sidlls 8y ago
- globuous 8y agothere is a lot more structure in this java snippet though. At equivalent structure, the python code isn't that much shorter. It's just convenient for a scripting language to be able to print stuff without any code structure. Something that Java enforces. I've concluded it's because Java isn't designed for scripting that it doesn't allow scripting practices in its code bases. I just started learning Java and I guess if I use a class that could throw an exception I have to catch it (or transfer it to my class' user it seems). In this particular test I knew it wasn't gonna throw but it wouldn't compile: I was opening a file I knew existed for some quick test - instead of 1 python line I got 7 java ones. But with exception / catch structure. It's an enterprise language, I'm all for the code structure enforcement. Help a dev catch an exception, so many things could already go wrong on larger codebases ;)
- diebir 8y agoJava's insistence on using one class to one file, naming files with class names and placing everything in a class is extremely helpful in industrial software engineering. When you pile up devs with different backgrounds, some bright, some bad, the rules that force everyone to follow some standard are great. This also helps with creating IDEs and refactoring tools. If your area is to play with math, go use whatever you want. Java is not that, it's sweet spot is different. Why is thislink here? There's literally nothing smart or useful in it.
- j88439h84 8y agoFrom the perspective of a python programmer, I must say this is an interesting list. I'm rather convinced by your points on print and public. On the other hand, "__name__ == __main__" is just a convenience for debugging and small scripts. I wouldn't use it in real programs. I dont use @staticmethod, or find it useful. If I want a function, I use a function.
- lou1306 8y ago> I dont use @staticmethod, or find it useful. If I want a function, I use a function. In principle, it makes sense to "bundle" functions that are strictly related to a class within the class itself (i.e. as static methods). Of course, the benefits viz. top-level functions are only noticeable if your codebase is big enough.
- j88439h84 8y agoWhat are those benefits?
- lou1306 8y agoOf course it's just better organization of the codebase and a less-polluted namespace. Also, if you're writing a library, it may affect the API you give to the user. If you move a function to a static method, the end user only needs to import the desired class. But again, they are "usability" benefits. I'm no CPython expert but I don't think that a static method would have noticeably worse (or better) performance than a function.
- on_and_off 8y agoYou can have your cake and eat it though thanks to kotlin. It is way more concise than java but does not become ambiguous because of it.
- GlennS 8y agoThese criticisms look to me like you are trying to use your Java programming style in Python. Prefer to use modules and tables of functions as an organising principle instead of classes. Use inheritance rarely, and method overriding almost never. Otherwise you can make a really big mess (see Django's Form class hierarchy). This sort of bad design where you have the flow of control jumping up and down the inheritance hierarchy happens in Java too, but the `abstract` keyword and static typing makes it easier to avoid. In Java, make your code regular, so someone can understand the piece they're looking at without too much context. In Python, make your code interesting. Factor out the unimportant repetitive parts, so someone can see a lot of the big picture all at once. Incidentally, I'm quite happy with print() in the top-level namespace. Java's logging situation (5 widely used logging frameworks and a 6th to abstract over them all) is not better.
- devxpy 8y ago> Django's Form class hierarchy I personally liked it. It is a little overwhelming at first, but after you get used to it, it's actually quite powerful.
- eismcc 8y agoIMO, it’s a balance of entropy with maintainability. The amount of info I a line of java is likely lower than lisp, so the cognitive load is likely lower and the code reviews of diffs are spread out over more lines. Generally less value per line but more decomposed.
- TeMPOraL 8y agoHaving done both Java and Lisp for years (both professionally), I agree that in general Lisp requires more cognitive effort to read per line, but I disagree about the reason. Cognitive load vs. verbosity can be visualized with something like Laffer curve - sure it's easier to read a couple lines of Lisp than one line of APL, but when you get into situations like one line of Lisp (or Python) gets expanded into 30 lines of Java, then the former is much easier. Terse languages make you pay cognitive cost for unpacking meaning, verbose languages make you pay for keeping track of what all these lines of code are doing. Ever had this situation when you read two pages of a book and realized you didn't really read anything, and have to re-read it (and 3 pages prior) to understand what's the point? That's Java in a nutshell, especially pre-1.8. As for Lisp and cognitive load, the difficulty comes from a) dynamic typing, and b) macros. The former makes bad naming choices much more painful, as you can easily lose track of what's the code doing, and to what data. The latter are fine when written well, when written badly, your problem suddenly explodes in complexity as you have to peel off a layer of syntactic abstraction, and fix the underlying mechanism.
- coldtea 8y ago> Python always executes the top level, so you end up with awkward idioms like: if __name__ == "__main__": main(sys.argv)* And that's more "awkward" than the idea of a "public static void main" and a MANIFEST file because?
- paavoova 8y agoYou wouldn't be able to write linear scripts in Python if it were so restrictive, or execute the interpreter from the command line with the -c command. You'd be forced to use OOP patterns for trivial code, whereas Python as it is now doesn't require any OOP at all. I really don't understand why you'd want to force everything into OOP doctrine.
- tasuki 8y ago> Do you really want print() to be so easily accessible in the top-level namespace? Not necessarily, but I definitely want functions to be accessible in the top-level namespace. Not everything is an object.
- RyanHamilton 8y agoI've made an attempt at a java scratchpad/REPL that guesses what imports you want. It allows just print by itself but Dump("Hello World!") is better in most cases as it handles collections well and outputs to tables/HTML as well as text. Example: http://jpad.io/example/1y/test-different-output http://jpad.io/example/1y/test-different-output
- fantispug 8y agoThe "top level" problem is real in Python and in Lisps; but in practice it's not a huge issue (if you really don't like __name__ == "__main__" you can create your main app as a separate script to your library). main in Java is as magical as __name__ in Python. Python now has type hints and good static checking libraries so you can add as much type checking as your want. Java's type system is atrocious (c.f. Haskell, OCaml); it doesn't check nulls (a common bug), making simple constructs (tuples, unions) often requires a new class file of boilerplate. The HelloWorldApp is a bad fit for objects. All the functions are static. This confused me for a long time learning Java. You can get a very long way in Python without knowing @staticmethod. The static nature of Java does make it easy to know where to look for things and introspect code; there tends to be less magic.
- lmm 8y ago> In Java the top level only contains classes and interfaces. All functions must be put inside a class, and I believe this design simplifies conceptual understanding. Strongly disagree. (Traditional) Java has no way to represent a function or a class as a first-class entity and it suffers for it. In Python functions and classes are plain old values (and indeed objects) and any value can live at top level in the module. > * Python always executes the top level, so you end up with awkward idioms like: if __name__ == "__main__": main(sys.argv) How is that any more "awkward" than the Java way? It's fewer lines of ceremony in all cases as far as I can see. > * The "public" keyword might seem like noise, but in Python you denote private by prefixing the name with one or two underscores. So Python has a) a better default (it's not that Java doesn't have a default visibility level, it's just such a spectacularly useless one that it never sees use) b) a concise symbolic syntax for something that's used extremely commonly, which is the right approach: http://www.lihaoyi.com/post/StrategicScalaStyleConcisenessNames.html http://www.lihaoyi.com/post/StrategicScalaStyleConcisenessNa... > * Do you really want print() to be so easily accessible in the top-level namespace? It seems to me that the bigger an application gets, the worse it is to easily litter the codebase with print statements. Big applications will always have their own frameworks and no possible default set of imports makes sense for big applications (Java's default imports from java.lang. get in the way for big applications too). But a good language should work for small scripts as well as big applications, so having print in there by default makes sense. (I can sympathise with having a no-default-imports option or something like Haskell's custom preludes). > * You still eventually need to learn what "@staticmethod" means in Python. My 10+ years of Python say otherwise. You really don't.
- LoSboccacc 8y agoAnd all the verbosity disadvantage almost goes away anyway once you get outside default functions and stop using globals