26

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?

3

9 Answers 9

36

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.

1
14

I believe the answer is, per Wikipedia, that Java was designed to be simple and object oriented. Functions are meant to operate on the classes they are defined in. With that line of thinking, having functions outside of a class doesn't make sense. I am going to leap to the conclusion that Java doesn't allow it because it didn't fit with pure OOP.

A quick Google search for me didn't yield much on Java language design motivations.

11
  • 6
    Doesn't the existence of primitive types exclude Java from being "pure OOP" ? Jan 29, 2013 at 10:07
  • 5
    @SoboLAN: Yes, and adding functions would make it even less "pure OOP".
    – Giorgio
    Jan 29, 2013 at 13:08
  • 8
    @SoboLAN that depends on your definition of "pure OOP". At some point everything is a combination of bits in computer memory after all...
    – jwenting
    Jan 29, 2013 at 13:18
  • 4
    @jwenting: Well, the purpose of abstraction in programming languages is to hide the underlying bits as much as possible. The more you can see those bits in your program, the more you should start to think that your programming language offers leaky abstractions (unless it is built close to the metal on purpose). So, yes, everything boils down to manipulating bits, but different languages do offer different levels of abstraction, otherwise you would not be able to distinguish assembly from a higher-level language.
    – Giorgio
    Jan 29, 2013 at 14:45
  • 3
    Depends on your definition of "pure OOP": every data value is an object, and every data operation is the result method invocation obtained through message passing. As far as I know there is nothing more to it.
    – Giorgio
    Jan 29, 2013 at 14:49
11

The real question is what would be the merit of continuing to do things the C++ way and what was the original purpose of the header file? The short answer is that the header file style allowed for quicker compile times on large projects in which many classes could potentially reference the same type. This is not necessary in JAVA and .NET due to the nature of the compilers.

See this answer here: Are header files actually good?

9
  • 1
    +1, though I have actually heard people say they like having the separation between public interface and private implementation that header files provide. Those people are wrong, of course. ;) Jan 29, 2013 at 9:35
  • 6
    @Baqueta In Java you can achieve this with interface and class :) No need for headers!
    – Andres F.
    Jan 29, 2013 at 13:19
  • 1
    I will never understand the desirability of having to look at 3+ files to understand how a simple class instance works. Jul 11, 2013 at 7:07
  • @ErikReppen typically, the interface (or header file in C) is the thing that customers get in user readable form to write their solutions to, the rest being provided in binary form only (of course in Java, there's no need to provide the sources of the interfaces, classfiles and javadoc will do).
    – jwenting
    Feb 5, 2014 at 10:59
  • @jwenting I hadn't thought of that case. I'm used more to thinking of the next poor bastard who has to maintain this silly code base, because all too often that's me at the next job stabbing my eyes out after spending hours looking at some sort of bizarre interface and sub/superclass merry-go-round architecture. Feb 6, 2014 at 15:14
3

A Java file represents a class. If you had a procedure outside the class, what would the scope be? Would it be global? Or would it belong to the class that Java file represents?

Presumably, you put it in that Java file instead of another file for a reason - because it goes with that class more than any other class. If a procedure outside a class was actually associated with that class, then why not force it to go inside that class where it belongs? Java handles this as a static method inside the class.

If an outside-class procedure were allowed, it would presumably have no special access to the class whose file it was declared in, thus limiting it to a utility function that doesn't change any data.

The only possible down-side to this Java limitation is that if you truly have global procedures that are not associated with any class, you end up making a MyGlobals class to hold them, and import that class in all your other files that use those procedures.

In fact, the Java importing mechanism needs this restriction in order to function. With all the API's available, the java compiler needs to know exactly what to compile and what to compile against, thus the explicit import statements at the top of the file. Without having to group your globals into an artificial class, how would you tell the Java compiler to compile your globals and not any and all globals on your classpath? What about namespace collision where you have a doStuff() and someone else has a doStuff()? It would not work. Forcing you to specifiy MyClass.doStuff() and YourClass.doStuff() fixes these issues. Forcing your procedures to go inside MyClass instead of outside it only clarifies this restriction and does not impose additional restrictions on your code.

Java got a number of things wrong - serialization has so many little warts that it is almost too difficult to be useful (think SerialVersionUID). It can also be used to break singletons and other common design patterns. The clone() method on Object should be split into deepClone() and shallowClone() and be type-safe. All the API classes could have been made immutable by default (the way they are in Scala). But the restriction that all procedures must belong to a class is a good one. It serves primarily to simplify and clarify the language and your code without imposing any onerous restrictions.

3

I think most of the people who answered and their voters have misunderstood the question. It reflects that they don't know C++.

"Definition" and "Declaration" are words with a very specific meaning in C++.

The OP does not mean to change the way Java works. This is a question purely about syntax. I think it is a valid question.

In C++ there are two ways to define a member function.

First way is the Java way. Just put all code inside the braces:

class Box {
public:
    // definition of member function
    void change(int newInt) { 
        this._m = newInt;
    }
private:
    int _m
}

Second way:

class Box {
public:  
    // declaration of member function
    void change(int newInt); 
private:
    int _m
}

// definition of member function
// this can be in the same file as the declaration
void Box::change(int newInt) {
    this._m = newInt;
}

Both programs are the same. The function change is still a member function: it does not exist outside of the class. Furthermore the class definition MUST include the names and types of ALL member functions and variables, just like in Java.

Jonathan Henson is right that this is an artifact of the way headers work in C++: it allows you to put declarations in the header file and implementations in a separate .cpp file so your program doesn't violate the ODR (One Definition Rule). But it has merits outside of that: it allows you to see the interface of a large class at a glance.

In Java you can approximate this effect with abstract classes or interfaces, but those cannot have the same name as the implementation class, which makes it rather clumsy.

2
  • and that shows you both don't understand people nor Java. You can use the same name for interface and implementation, as long as they're not in the same package.
    – jwenting
    Feb 5, 2014 at 11:00
  • I consider the package (or namespace, or outer class) to be part of the name. Feb 10, 2014 at 14:36
2

I think it's an artifact of the class loading mechanism. Each class file is a container for a loadable object. There is no place "outside" of class files.

4
  • 1
    I don't see why organizing the source code in separate units would prevent keeping the class file format as it is.
    – Mat
    Jan 29, 2013 at 8:04
  • there is a 1:1 correspondence between class files and source files, which is one of the better design decisions in the overall system.
    – ddyer
    Jan 30, 2013 at 3:21
  • @ddyer You've never seen Foo$2$1.class then? (see Java inner class class file names)
    – user40980
    Jan 30, 2013 at 3:56
  • Would that make it an "onto" mapping ? in any case, each class is generated from compiling exactly one source file, which is a good design decision.
    – ddyer
    Jan 30, 2013 at 4:39
1

C#, which is very similar to Java, does have this kind of feature through the use of partial methods, except that partial methods are exclusively private.

Partial Methods: http://msdn.microsoft.com/en-us/library/6b0scde8.aspx

Partial Classes and Methods: http://msdn.microsoft.com/en-us/library/wa80x488.aspx

I don't see any reason why Java couldn't do the same, but it probably just comes down to whether there is a perceived need from the user base to add this feature to the language.

Most code generation tools for C# generate partial classes so that the developer can easily add manually written code to the class in a separate file, if desired.

1

C++ requires that the entire text of class be compiled as part of every compilation unit which uses any members thereof or produces any instances. The only way to keep compile times sane is to have the text of the class itself contain--to the extent possible--only those things which are actually necessary to its consumers. The fact that C++ methods are often written outside the classes that contain them is a really nasty vile hack motivated by the fact that requiring the compiler to process the text of every class method once for every compilation unit where the class is used would lead to totally insane build times.

In Java, compiled class files contain, among other things, information which is largely equivalent to a C++ .h file. Consumers of the class can extract all the information they need from that file, without having to have the compiler process the .java file. Unlike C++, where the .h file contains information which is made available to both the implementations and clients of the classes contained therein, the flow in Java is reversed: the file the clients use isn't a source file used in the compilation of the class code, but is instead produced by the compiler using information the class code file. Because there is no need to divide class code between a file containing information clients need and a file containing implementation, Java doesn't allow for such a split.

-1

I think part of it is that Java is very much a protectionist language that concerns itself with usage on large teams. Classes can't be overwritten or redefined. You have 4 levels of access modifiers that define very specifically how methods can and can't be used. Everything is strong/statically typed to protect devs from type mismatch hijinx caused by others or themselves. Having classes and functions as your smallest units makes it a lot easier to reinvent the paradigm of how to go about architecting an app.

Compare to JavaScript where dual-purposed noun/verb first-class functions rain down and get passed around like candy from a busted-open pinata, the class-equivalent function constructor can have its prototype altered adding new properties or changing old ones for instances that have already been created at any time, absolutely nothing stops you from replacing any construct with your own version of it, there's like 5 types and they auto-convert and auto-evaluate under different circumstances and you can attach new properties to damn near anything:

function nounAndVerb(){
}
nounAndVerb.newProperty = 'egads!';

Ultimately it's about niches and markets. JavaScript is about as appropriate and disastrous in the hands of 100 (many of which will likely be mediocre) devs as Java once was in the hands of small groups of devs trying to write web UI with it. When you're working with 100 devs the last thing you want is one guy reinventing the damned paradigm. When you're working with UI or rapid development is a more critical concern, the last thing you want is to be roadblocked on doing relatively simple things quickly simply because it would be easy to do them very stupidly if you aren't careful.

At the end of the day though, they're both popular general use languages so there is a bit of a philosophical argument there. My biggest personal beef with Java and C# is that I've never seen or worked with a legacy codebase where the majority of the devs seemed to have understood the value of basic OOP. When you come into the game having to wrap everything in a class, perhaps it's just easier to assume you're doing OOP rather than function spaghetti disguised as massive chains of 3-5 line classes.

That said, there's nothing more awful than JavaScript written by somebody who knows only enough to be dangerous and isn't afraid to show it off. And I think that's the general idea. That guy supposedly has to play by roughly the same rules in Java. I would argue that the bastard will always find a way though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.