So I'm thinking about things I love about C++ and those 3 come up. I kind of love operator overloading, but I agree it made the code somewhat difficult to read. This isn't a "JAVA SUCKS!!!111ONEONE!11" post, I'm just curious about java's reason for not having them.

1) Default function arguments:

Well the thing about this I miss most is the "..." so I could define a function max that would go max(1,2) and max(1,2,3,4,56,8) and so on. I know I could define a max(int[]) function but sometimes my variables don't come to me as an array. I also miss being able to define functions that can

void incrCount(int count=1){myCount+=count;}

2) Preprocessor commands

This was used in c++ more to figure out which OS it was being compiled on (something java doesn't need), but I could also very easily insert the time I compiled my program and the line number. Maybe a better question would be "How do I easily do those in java" with easily being a key word :)

3) natives by ref

int i=3,y=8;swap(i,y);

I could do that in c++, but not java. I understand it has to be wrapped in an Integer in java, but is there a reason why we can't pass natives by ref at all, not even the option?

1) The interaction of defaults and overloading makes it difficult in C++ to identify which method is actually going to be called. Nothing stops you defining 3, 4 or 5 argument versions of max (and beyond that you should probably do something else anyway).

2) If you want the compilation time for a class, you could try to identify the class file and then just obtain its modification time. Alternatively, this sort of information could be added by a post process that modified strings found in the byte code. This would be simpler to implement and not have the awkward side effects of a pre processor.

3) To pass primitives by reference you would need to pass a reference to the containing object (or stack frame) plus the offset of the field. In the case of the stack frame this then might allow such a reference to escape and be accessible beyond the validity of the stack frame.It is much safer to encapsulate the primitive in an object which is presumed to be allocated on the heap. A smart JIT might then recognise those cases where the object could be safely allocated on the stack --- i.e. where references to the object do not escape.Unfortunately most current JVMs do not do escape analysis.

1) Default function arguments:...I know I could define a max(int[]) function but sometimes my variables don't come to me as an array.

In the kindest possible tone: welcome to the real world.

This exact problem is responsible for most of the programming effort that end users have to do in the mainstream IT world (particularly at the high-end corporate/enterprise level). So much so that IBM has long prioritized "making it simpler to get systems to talk to each other" (and, according to some, is the reason IBM became Java's champion in the early days - more than beating windows, they wanted to be able to keep selling new machines that could talk to their old mainframes without bankrupting them when it came to inter-machine communication layers).

There are easy solutions to this at the language level, but they basically boil down to the compiler rewriting your code to convert your args into an int[] before sending them :).

Quote

2) Preprocessor commands

This was used in c++ more to figure out which OS it was being compiled on (something java doesn't need)

That's a gross under-estimation of what this feature is used for in C++.

The short answer here is that the pre-processor in C++ is a HACK to work around inadequacies in C++, and that it is simply a secondary (or "meta") programming language which C++ compilers happen to be able to compile (if you look at how it's implemented, you'll find you typically have two compilers - one from "preprocessor to C++" and one from "C++ to linker").

As it happens, there are a wide array of meta-languages that are in use with java, you just need to go looking for them. Obviously, since Sun doesn't support any of them, you have to use special / custom javac compilers, or else write a script that runs the preprocessor compiler first, then invokes javac on the output.

For an example, look at aspectj, which adds extra features to the java language by imposing a meta language on top of java.

Quote

3) natives by ref

int i=3,y=8;swap(i,y);...is there a reason why we can't pass natives by ref at all, not even the option?

I think you are effectively saying there is that C++ allowed pointers (although I'm suspicious I'm missing the point); the reasoning behind "no pointers" is covered extensively elsewhere, but there are two main things:

1. Compilers can create faster executables if you do not allow pointers and do not allow goto

2. Pointers are a source of huge amounts of lost development time because humans are so error-prone when developing with them

3. There's no pressing *need* for pointers except in a subset of cases where your compiler isn't smart enough.

With 3, the java compiler still isn't as smart as every C++ programmer put together, but it's close enough that in the majority of cases you can get away with it. There are still areas where a lot of us could really do with access to pointer programming (c.f. all the lengthy discussions on the Structs RFE), but in all honesty we're talking about niche uses.

It was probably better to get rid of pointers, all things considered, but it was a brave move and I'm not sure I'd have had the courage to do it if it had been my decision!

"The interaction of defaults and overloading makes it difficult in C++ to identify which method is actually going to be called"

Fair enough, I see that.

"In the kindest possible tone: welcome to the real world."

Thanks? But you didn't really give a reason java didn't do it. I assume it's the same as Mark's?

"The short answer here is that the pre-processor in C++ is a HACK to work around inadequacies in C++, and that it is simply a secondary (or "meta") programming language which C++ compilers happen to be able to compile"

Yeap. It's a secondary programming language. I understand I could make some "script" to do the same, but I isn't there an advantage of a 'standard' way to do the same? I would assume it goes along with the whole java philosophy.

"...pointers..."

I don't think of by ref as the same as pointers, as far as what it's "supopse" to do. We pass Object by ref automatically. I am thinking why not the option to do the same with primitive data types.

1) Default function args...Sort of nice - but only really used if you went and added an arg to a function later which in most cases was a default, & you couldn't be arsed with finding all the previous uses of the function. At leats thats how I used them mostly

2) PreprocessorMost useful use for this is debug/release coding - Asserts! (see 'Writing Solid Code' by Steve Macguire, published by Microsoft) #defines and #ifdefs are fabulous when debugging stuff. Most of my C++ libraries are full of various debug defines & logging functions that in a release build get preprocessed to nothing.However, as Blah^3 says, there are ones available, and you can even just run the java files through your favourite C++ preprocessor with the right makefile before submitting them to javac.

3) Referencing natives (ints, floats, etc.)...Yes, oh yes - I totally agree.This isn't 'pointers' issue per se. it is being able to affect multiple arguments that have been passed to a function without having to wrap them in a temporary object - irrespective of efficiency, it makes longer & messier source code without it.The use of the reference on the function can essentially tell the caller that it should read an extra value back off the stack after the function, and the callee that it should write the extra value back to the stack before returning. Any attempt to further pass the referenced variable involves another stack on/stack off operation which should prevent unwanted escape.

Thanks? But you didn't really give a reason java didn't do it. I assume it's the same as Mark's?

I was pointing out that your only cited objection to the standard way of dealing with the problem is actually a generic problem that would not be solved by the C++ approach.

Quote

"The short answer here is that the pre-processor in C++ is a HACK to work around inadequacies in C++, and that it is simply a secondary (or "meta") programming language which C++ compilers happen to be able to compile"

Yeap. It's a secondary programming language. I understand I could make some "script" to do the same, but I isn't there an advantage of a 'standard' way to do the same? I would assume it goes along with the whole java philosophy.

If you've not read about java 1.5 yet, go and have a look at that - it may be that the metadata system is the "standard" you're looking for. However, c.f. below for why I think this is a BAD idea. NB for the following paras I had assumed you were thinking of a standard beyond simple metadata embedding...---

Think about what you're saying: you're asking that java (a single language) be turned into a two-language system, e.g.: become "Perl-Java" or "Python-java" or "VisualBasic-Java" or "Eiffel-java" or something.

Java doesn't have the same problems as C did which required the hack of a secondary programming language.

More useful for you would probably be to list the set of things you want to use a preprocessor for, and then look to see which of those are NOT already solved by java if you know java well enough. Since Java is a different language to C/C++ it has extra features that mean there will be java-only ways of dealing with some of those situations that already exist. Others (like AOP) fundamentally require the use of a custom secondary language. There are many ways you can implement custom secondary languages, and one of those is to type meta-data directly into java source as comments ( so the java compiler doesn't see them). You don't have to, though - there are plenty of other ways of achieving this.

Personally, IMHO, I'm sceptical that this was a good idea, but for 1.5 there is some extra formality introduced to support that kind of thing. The history of attempts to do such hackery on existing languages does not bode well (IMHO) for the future of the metadata system, although I am probably misunderstanding how Sun expects it to be used. To me, it seems like they're just opening up the JSP can of worms all over again, as if someone important at Sun simply can't get into their head the concept of M/V/C-like separation: they seem determined to write entire systems in as few source files as possible, which to a certain extent is the opposite of what OOP was invented for.

Quote

"...pointers..."

I don't think of by ref as the same as pointers, as far as what it's "supopse" to do. We pass Object by ref automatically. I am thinking why not the option to do the same with primitive data types.

To help me understand, could you list the situations where this is desirable, or provide some non-trivial examples (your first example was illustrative but not persuasive).

1) Default function args...Sort of nice - but only really used if you went and added an arg to a function later which in most cases was a default, & you couldn't be arsed with finding all the previous uses of the function. At leats thats how I used them mostly

Chuckle. You ought to get a better IDE, which handles the refactoring effortlessly - so that there's no benefit from the multi-arg stuff.

This matters because there are inherent disadvantages to multi-args, mostly to do with reducing the compiler's ability to verify your code for you.

Although, since I can't get eclipse to run, I know what it feels like to be stuck in a no-man's land without a decent refactoring IDE .

Quote

2) PreprocessorMost useful use for this is debug/release coding - Asserts!

Of course, we know you do lots of 1.1 coding, which means you don't have access to the java assert keyword (not added until 1.4)

Interesting idea; however, I've never found a need for this. For the majority of debug, the log4j/java.util.logging API's base assumption seems correct: the slowdown induced by ALWAYS having the logging data in is negligible. In fact, as they do, I challenge you to produce a real program where you ever find debug statements showing up as a bottleneck in the profiler (slightly rhetorical - obviously CS can't do this since he doesn't use them that way but perhaps someone else can?)

I said "majority" above because if you ever work with particularly complex or nasty algorithms then you are inserting debug statements into ultra-tight loops which DOES show up on benchmarking. But, fundamentally, these situations only ever need debugging rarely, and at a time when you will of necessity already be recompiling (I've found that in the last 5 years I only do intensive performnance/correctness debugging of tight loops, rather than any debugging of user problems).

EDIT: there shouldn't be a space between "verbose" and "BLAH" below...

If you already are recompiling, then the use of

1

staticfinalbooleanverboseBLAH = false; // true;

variables is perfect - when false, they are NOT compiled, and any if statements on them are NOT compiled, but you can easily uncomment them when you want to do some intensive work.

Quote

3) Referencing natives (ints, floats, etc.)...Yes, oh yes - I totally agree.This isn't 'pointers' issue per se. it is being able to affect multiple arguments that have been passed to a function without having to wrap them in a temporary object - irrespective of efficiency, it makes longer & messier source code without it.

Do you mean the old "ah, come on - do I HAVE to use OOP *all* the time? I just want to return a simple two-tuple, man! Please don't force me to make an entire class just to hold two references as a temporary return code!" problem.

variables is perfect - when false, they are NOT compiled, and any if statements on them are NOT compiled, but you can easily uncomment them when you want to do some intensive work.

Well I never! Only time I tried doing anything like that I had compile errors for 'code never reached' or something so I gave up. Is it the 'verbose' bit that tells it not to complain?

The real killers are not the asserts (although would be nice in 1.1), but the 'full debug - so do a dump of this enormous data structure each frame till it buggers up' type debug sections.

Quote

Do you mean the old "ah, come on - do I HAVE to use OOP *all* the time? I just want to return a simple two-tuple, man! Please don't force me to make an entire class just to hold two references as a temporary return code!" problem.

Thats the one.This is exacerbated excacerbated made worse by the 'MS JIT decides not to compile large function' problem I found earlier, hence the need to 'de-inline' some blocks of code

Well I never! Only time I tried doing anything like that I had compile errors for 'code never reached' or something so I gave up. Is it the 'verbose' bit that tells it not to complain?

Yeah, it's a secret undocumented keyword...

/me hides in shame, because the space between "verbose" and "BLAH" was a typo

I believe your compiler error was an unfortunate co-incidence of a typo in your code. I've used static final booleans in the same way that you might use #ifdef's for years, without problems. IIRC it works with 1.1.x although I'm not sure about 1.0.x...

Quote

The real killers are not the asserts (although would be nice in 1.1), but the 'full debug - so do a dump of this enormous data structure each frame till it buggers up' type debug sections.

Where the Trace.getEnabled method computes the value based on entries in a config file or arguments on the command line (like the -ea arguments in 1.4). Although this means the byte code is still in the class file, when a method using TRACE is compiled the value is known and if false, the code will be omitted from the compiled form. As a result the insertion cost of such code is essentially zero when not enabled.This is far better than C/C++ style #ifdef debug code, because it can be enabled in the field and you don't need a special debug build. The only penalty is slightly larger class files.

Although this means the byte code is still in the class file, when a method using TRACE is compiled the value is known and if false, the code will be omitted from the compiled form. As a result the insertion cost of such code is essentially zero when not enabled.

To clarify, when you say "compiled" you presumably mean when it's JIT/hotspot/runtime (re-)compiled?

Usually you want to pass back multiple values instead of just a single primitive return value. If you are using pass-by-ref to modify actual input values I find that dangerous. Mainly because when you read the code it is often completely hidden that such a side effect is happening with one of the input parameters.Wrap the value(s) with an Object maybe even just a simple primitive Array in the cases where you really need this, but it doesn't come up all that often and care needs to be taken with the design when you do need it.

To clarify, when you say "compiled" you presumably mean when it's JIT/hotspot/runtime (re-)compiled?

Correct. So there is still some overhead as the larger class file will take silghtly longer to load, while interpreted the if test will still be evaluated, and the jit compiler will take silghtly longer, but once the JIT compiler has done its job the overhead has gone.

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org