Lazarus (FPC) is faster than most languages. Not necessarily C or C++ but faster than all those popular ones: PHP, Python, JavaScript, Java.
Thats not necessarily true, I guess you base that on the idea that pascal is natively compiled while these others are interpreted/emulated? But thats not really true, first these languages use JIT compilation, so code that is run frequently is as much compiled to machine code as your pascal code is, often with better optimization because it's based on observed behavior. Second those languages use different architectures with different design decisions that make certain things faster and others slower. Take the following two equivalent programs, one in Java:
public class Main {
private final int adder;
Main(int a) {
adder = a;
}
int add(int i) {
return i+adder;
}
public static void main
(String args
[]) { long startTime
= System.
currentTimeMillis(); int accum = 0;
for (long i=0;i<1000000000l; ++i) {
Main m = new Main((int)i);
accum=m.add(accum);
}
long endTime
= System.
currentTimeMillis(); System.
out.
println("Total execution time: " + (endTime
-startTime
) + "ms"); }
}
And one in Pascal:
program Project1;
{$mode objfpc}{$H+}
uses SysUtils;
type
TTest = class
private
adder: Integer;
public
function Add(i: Integer): Integer;
constructor Create(a: Integer);
end;
function TTest.Add(i: Integer): Integer;
begin
Result:=i+adder;
end;
constructor TTest.Create(a: Integer);
begin
adder:=a;
end;
var
i: Int64;
accum: Integer;
start: QWord;
t: TTest;
begin
start:=GetTickCount64;
accum:=0;
i:=0;
while i<1000000000 do
begin
t:=TTest.Create(Integer(i));
accum:=t.Add(accum);
t.Free;
Inc(i);
end;
WriteLn('Total execution time: ', GetTickCount64-start, 'ms');
ReadLn;
end.
Let's run them:
Java: Total execution time: 200ms
Pascal (-O3): Total execution time: 22657ms
So java is around a factor 100 faster.
The reason for that is the garbage collector. Java uses a generational mark and sweep garbage collection, so (VERY OVERSIMPLIFIED) when a new object is created it is just pushed on a stack, which is just a single pointer operation (add stackptr, sizeof(object)). Then the function is called on that object and the object is left alone. When the stack is full, the garbage collector will jump in and do a quick reachability analysis, which in the example above is trivial because they all were local variables. The garbage collector will move all the objects that are still reachable to the next generation stack, which in this example are none, and then clear the gen1 stack, which also is just a single operation (set stackptr, 0).
So for each iteration there is one add and after a certain number of iterations there will be a single reset. Thats really fast.
Take the pascal code on the other hand. With each allocation the memory manager is called, which performs some rather complex allocation lookup. It's not like crazy much effort, but it's certainly orders of magnitude more operations than 1. Then the instantiation code needs to be executed (
See TObject.InitInstace) which besides this function also contains a few virtual function calls with need to chase pointers, potentialy have cache invalidation and all that fun stuff.
After the method is called on the object, it is freed, which contains a call to the destructor, then the deinitalization code (
see TObject.CleanupInstance) before calling the memory manager again.
When it comes to creating a lot of small objects Java is much faster than Pascal, if we assume that in this very simple example above the JIT kicks in reasonably early, so the code executed is natively compiled as the FPC code, we can see that initiating and freeing a class in Pascal is roughly 100 times slower than it is in Java.
Does this mean Java is in general faster than Pascal? Well it highly depends on the code you write, as I wrote above with the example of linked lists in C, if you create a bunch of throwaway classes in Pascal it's gonna be slow, not because the compiler is slow, but because your code is slow.
A disadvantage to this is btw that Idiomatic Pascal code often involves creating temporary objects. If we look for example at the EncodeStringBase64 function in the base64 unit:
function EncodeStringBase64(const s:string):String;
var
Outstream : TStringStream;
Encoder : TBase64EncodingStream;
begin
if Length(s)=0 then
Exit('');
Outstream:=TStringStream.Create('');
try
Encoder:=TBase64EncodingStream.create(outstream);
try
Encoder.Write(s[1],Length(s));
finally
Encoder.Free;
end;
Result:=Outstream.DataString;
finally
Outstream.free;
end;
end;
You can see that it creates two temporary objects just to immediately throw them away. So if you call this function in an inner loop, it's gonna be really slow. Meanwhile if you'd do the same in Java it would be blazingly fast.
Lastly, I made a tiny adjustment to the pascal code:
program Project1;
{$mode objfpc}{$H+}
{$ModeSwitch advancedrecords}
uses SysUtils;
type
TTest = record
{...}
function Add(i: Integer): Integer;inline;
class function Create(a: Integer):TTest;static;inline;
end;
{...}
class function TTest.Create(a: Integer): TTest;
begin
Result.adder:=a;
end;
{...}
t:=TTest.Create(Integer(i));
accum:=t.Add(accum);
//t.free <-- not needed anymore
Inc(i);
{...}
I get:
Total execution time: 359ms
Which is nearly as fast as Java. By changing the class to a record, most of that overhead is now gone. Additionally I made both functions inline because the JIT compiler of Java does this as an optimization as well, so it's just fair if we want to compare those two. It's still not as fast as Java which is simply because Javas JIT compiler is crazy good, like seriously on repetetive tasks it usually produces much more optimized assembly than even most current C compilers, let alone the FPC.
So yeah, Java can easily be faster than FPC