My argument has always been and still is...a language x written in language y cannot by definition be faster than language y.
I understand that languages by themselves aren't fast, but it seems that point should be clear.
My argument has always been and still is...a language x written in language y cannot by definition be faster than language y.
I understand that languages by themselves aren't fast, but it seems that point should be clear.
That’s just.. false. Languages compile to machine code, one way or another. Java’s JIT compiler doesn’t create C code, it creates machine code. So it could very well be written in brainfuck, it could still be theoretically better than C.
In the Java case, the JIT performs a runtime analysis. Without wanting to making any assertions about overall performance here, there exists a non-zero set of programs for which runtime optimisation is superior to static compiler analysis.
What JVM wins in PGO, it loses in other areas, and the end result is often still much slower.
No matter PGO these and similar examples can’t be done without self-modifying code, while java with JIT is sort of that in a way.
Anyway, that's what a JIT is.
Do you actually write C programs that profile themselves and tune their code according to the input data? If not, then the fact that it's theoretically possible to do that seems pretty irrelevant.
However, I would also argue that C cannot be faster than ASM, if that's what you're asking.
And yes, I agree it's pretty irrelevant.
In fact, your parent comment are running into the same issue, Java is essentially a interpreted language running a compiler facade.
But when it gets to the compiled languages, all speed comparisons are now property of the specific compiler, and not the language.
I know it's a pedantic point, but one I stand by...that there's literally nothing Java can do that C cannot because C can write Java!
When talking about performance you say that “there's literally nothing Java can do that C cannot because C can write Java” but other than the tautology that they are both Turing machines, your conclusion doesn’t follow.
The Java runtime dynamically optimises based on the currently executing code, but C compiles to static CPU instructions. A C program is statically optimised so it’s possible that some optimisations in C will perform worse than those in Java because Java knows more about the actual code paths taken at runtime, and this can change between executions.
For C to be able to optimise itself the same way that Java does, it would need its own heavyweight runtime and bytecode, like Java does (as I think you suggest). But C doesn’t actually have such a runtime, and although I’m certainly no expert on the C language spec, I assume it has all sorts of runtime guarantees and a memory model that would preclude arbitrarily rearranging the executable code at runtime, so it arguable that the resulting system wouldn’t actually be “C” if it did this.
Put another way: although Java is/was written in C, the way Java works is fundamentally different to C, and because of this, certain optimisations are available to Java that are not available to C.
(All of that said, in my experience C code is always faster than Java code, these days I use Go and Swift, and I’m very happy to have seen the back of the JVM.)
So, consider a perfectly spherical Java language… :)
----
Also, by the same argument you're using, git should be faster if written in assembly; since assembly can do more than C can.
The tradeoff between performance and easiness to write the program has already been made by writing git in C. The only difference in using Java is a different point in that tradeoff.
I'd also contend that Java gives you much more bang for the buck in that tradeoff than C. Java is stupidly easy to write, especially if you want to do multithreading. With C you'd have to start writing some form of primitive GC, or have the disciplined paranoia of Rust's borrow checker yourself.
I don't go around saying C is faster than Java. I just say Java cannot be faster than C.
You could maybe write some kind of translator in C to emit JVM bytecode, and have it recompile itself at runtime. The problem with that line is that it is a lot of work and then to be fair we should allow a similar effort to be applied to a JVM like HotSpot for an apples-to-apples comparison.
Then remember the original thesis, which is that we claimed Java was only faster for specific usecases. That is a very wiggly claim that I bet could nearly always be found true.
Anyway, fun to think about either way.
A C compiler can be written in Java. Therefore, by "definition", Java is faster than C.
Whereas Java written in C could run Java code.
What's your point?
I was merely pointing at a hole in your argument: the language of the compiler has absolutely no influence in the quality of it's output (again: the JVM compiles to assembly, not to C++).
A compiler written in brainfuck could write code that is more performant than gcc does.
The language does have an influence on compilation speed, though. But that matter in your argument?
Also, there are AOT compilers that can make use of profile information.
Once I implemented a simple pool allocator in C++, it ran circles around Java.
Something tells me that didnt happen because you saw "cpp running circles around Java" so you got the result you wanted and just stopped there.
If you did, you wouldn't be making this comment.
In the specific case I don't think you need to; I've seen generated code (from java sources) simply reuse an object in a tight loop. IOW, it doesn't allocate new memory for the instance within a loop, for each invocation of the loop. The memory for the instance is allocated once and then reused.
(For a small allocation (a small instance) I would expect a smart compiler to not allocate anything and simply create the for-loop instance on the stack).
Size plays a part: it determines whether or not an instance first gets allocated on the heap or the stack[1]. Heap allocation gets expensive in a tight loop.
> If the object reference escapes, it has to be allocated on the heap. Value semantics could/will help here.
The assumption is that we are talking about local-only data objects (not returned or outliving the scope). Forgive (and correct) me if I am under the incorrect assumption.
[1] I'd expect a smart compiler to do this: a data object that requires 1MB should at no point be on the stack, while a data object that requires 32 bytes has no business starting the allocator, causing a context switch to the kernel that faults a new page. The specific thresholds are dependent on the runtime and OS support.
This is a bizarre (and entirely incorrect) definition.
Have you heard of JIT?
While this may be true in theory, in practice it is often not true as usually there are time constraints.
Working in a low level language Y can take much more time & effort than a high level language X. This can mean you can profile and iterate the program design to improve performance much faster in X than in Y. Worse, if you have optimized a program in Y following algorithm A, it would be much harder to switch to optimizing following algorithm B. Because almost always "optimization" makes program logic more complex and removes clarity. Some time so much so that you may not even try an alternative! Such increased complexity can also happen in an HLL program but a modular program can often be rewritten more easily.
That's not true - ITYM "A byte-code interpreted runtime X written in language Y cannot be faster than Y"[1]
[1] Although some would say that that is wrong too.
If you implement, say, a Pascal compiler in C, it can be faster than C because Pascal keeps the length of the string with the string.
A language that does not permit pointer arithmetic can optimize the memory layout on the fly, based on real world program performance and that may be faster than a language it is written in.