Java – Why Java does not allow function definitions to be present outside of the class

classfunctionsjava

Unlike C++, in Java, we cannot have just function declarations in the class and definitions outside of the class. Why is it so?

Is it to emphasize that a single file in Java should contain only one class and nothing else?

Best Answer

The difference between C++ and Java is in what the languages consider their smallest unit of linkage.

Because C was designed to coexist with assembly, that unit is the subroutine called by an address. (This is true of other languages that compile to native object files, such as FORTRAN.) In other words, an object file containing a function foo() will have a symbol called _foo that will be resolved to nothing but an address such as 0xdeadbeef during linking. That's all there is. If the function is to take arguments, it's up to the caller to make sure everything the function expects is in order before calling its address. Normally, this is done by piling things onto the stack, and the compiler takes care of the grunt work and making sure the prototypes match up. There is no checking of this between object files; if you goof up the call linkage, the call isn't going to go off as planned and you're not going to get a warning about it. Despite the danger, this makes it possible for object files compiled from multiple languages (including assembly) to be linked together into a functioning program without a lot of fuss.

C++, despite all of its additional fanciness, works the same way. The compiler shoehorns namespaces, classs and methods/members/etc. into this convention by flattening the contents of classes into single names that are mangled in a way that makes them unique. For example, a method like Foo::bar(int baz) might get mangled into _ZN4Foo4barEi when put into an object file and an address like 0xBADCAFE at runtime. This is entirely dependent on the compiler, so if you try to link two objects that have different mangling schemes, you're going to be out of luck. Ugly as this is, it means you can use an extern "C" block to disable mangling, making it possible to make C++ code easily accessible to other languages. C++ inherited the notion of free-floating functions from C, largely because the native object format allows it.

Java is a different beast that lives in an insulated world with its own object file format, the .class file. Class files contain a wealth of information about their contents that allows the environment to do things with classes at runtime that the native linkage mechanism couldn't even dream about. That information has to start somewhere, and that starting point is the class. The available information allows the compiled code to describe itself without the need for separate files containing a description in source code as you'd have in C, C++ or other languages. That gives you all of the type safety benefits languages using the native linkage lack, even at runtime, and is what enables you to fish an arbitrary class out of a file using reflection and use it with a guaranteed failure if something doesn't match up.

If you haven't figured it out already, all of this safety comes with a tradeoff: anything you link to a Java program has to be Java. (By "link," I mean anytime something in one class file refers to something in another.) You can link (in the native sense) to native code using JNI, but there's an implicit contract that says that if you break the native side, you own both pieces.

Java was big and not particularly fast on the available hardware when it was first introduced, much like Ada had been in the prior decade. Only Jim Gosling can say for sure what his motivations were in making the class Java's smallest unit of linkage, but I'd have to guess that the extra complexity that adding free floaters would have added to the runtime might have been a deal-killer.