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.
A return statement passes a value back to the immediate caller of the current function's call-frame. In the case of recursion, this immediate caller can be another invocation of that same function.
In most languages, if you don't use the return value of a function you called (recursively or not), either that return value gets discarded or it is a diagnosable error. There are some languages where the return value of the last function call gets automatically re-used as the return value of the current function invocation, but they don't differentiate between normal and recursive function calls.
Assuming unused return values get silently discarded, if you had written the code like this:
list *search_list(list *l, item_type x) {
if (l == NULL) return(NULL);
if (l->item == x)
return(l);
else
search_list(l->next, x); // no return!
}
then search_list
would only return a defined value for an empty list (NULL) or if the first item matches the value you are searching for. As soon as the function goes into the recursive call, you don't know what the result will be, because the result of the recursive call gets discarded.
Additionally, you promise to return a value from your function, but you have a path (the recursive one) where you don't specify what value to return. Depending on the language you use, this usually results either in a mandatory diagnostic or in undefined behaviour (which is shorthand for: anything can happen and that can change at any time without notice. Don't hold anyone but yourself liable if it screws up your most important presentation). There are some situations where the missing return value might appear to work, but that might change the next time you run the program (with or without recompilation).
Best Answer
You can also just store the referenceNode in a variable as it is constant per
GraphDatabaseService
.You can also declare it as a
final
instance variable in the constructor of your service to document that.