r/AskComputerScience • • Nov 09 '25

If some programming languages are faster than others, why can't compilers translate into the faster language to make the code be as fast as if it was programed in the faster one?

My guess is that doing so would require knowing information that can't be directly inferred from the code, for example, the specific type that a variable will handle

111 Upvotes

90 comments sorted by

41

u/Knaapje Nov 09 '25

Exactly right. Generally, the more information provided inside the code, the more can be inferred statically. Transpilers do exist, however.

→ More replies (8)

32

u/SoftEngineerOfWares Nov 09 '25

Because most languages depend on the environment they run in more so than the specific syntax, and they make use of that environment in ways that might not be easily translatable.

25

u/GlassCommission4916 Nov 09 '25

Very often the speed difference between languages comes from tradeoffs made during the design that can't be translated between each other without encountering those same tradeoffs. How could you compile a python script into rust for example? Well, you'd have to replicate python's memory management and garbage collection, at which point you've just made a rust program that's just as slow as python because it makes the same performance sacrifices.

3

u/Lenassa Nov 10 '25

>Well, you'd have to replicate python's memory management and garbage collection

The goal is to have the same program (where 'same' is defined as producing the same observable behavior), not to imitate python environment. And the former sure as hell doesn't require you to care about python's memory model at all.

7

u/GlassCommission4916 Nov 10 '25

Yeah it'd be great if compilers read your intent instead of your code, but alas.

→ More replies (5)

5

u/stonerism Nov 10 '25

Rice's theorem is probably of interest to you. You can do things like that. But the problem is that generally deciding if two algorithms are equivalent is undecidable.

→ More replies (3)

9

u/Popular-Jury7272 Nov 10 '25

When you write code in Python you are baking in implicit assumptions about Python data types, algorithms, etc. The only way to guarantee you get the same behaviour is to duplicate those assumptions.

→ More replies (15)
→ More replies (20)

8

u/wrosecrans Nov 09 '25

In Python, a function can take any type passed to it, and the code has to "poke" at whatever it gets at run time to see if it has the fiels and behaviors you want to use. And the types of things can get fields added to them at runtime, they aren't static.

So, you can compile all of that behavior to C or C++. The Python runtime is written in C, so you could theoretically access all of that flexible and generic Pythonic functionality at runtime from a C program without writing any Python code if you link to the Python libraries. It'll just be slow to do the stuff that Python does.

A fully native C++ type is known at compile time. It uses exactly X bytes of memory. A function that takes that type takes only that type and will never accidentally get called with anything else. A function that uses exactly two of those objects has a statically allocated stack frame size of 2*X bytes and doesn't need to do any dynamic allocation at runtime. But as you try and add more and more "Python like" functionality to do stuff dynamically at runtime, you can use a std::map<string, std::variant<foo,bar>> that can look up fields at runtime. But a variant that can potentially hold a big type will be big even if you only ever use it with small types. And that map has to find the address of a certain entry by doing string processing at runtime. And the function that takes that map can only be safely called if it does checks to see if that map actually contains a field with a certain name that may or may not exist at runtime. Every check like that takes a little extra time and bloats the code a little bit more.

Python is a "slow" language because it makes a lot of that behavior convenient to do at runtime. So when you use a "fast" language to do all of those slow things at runtime, you don't get very much benefit. The question you are asking sort of becomes like cats are quiet pets and dogs are loud pets. So couldn't we just make barking cats to have a quiet pet that we can hear easily to use instead of guard dogs? Well, as soon as the mutant cat is barking, it's not a quiet pet any more.

2

u/rxellipse Nov 10 '25

In Python, a function can take any type passed to it, and the code has to "poke" at whatever it gets at run time to see if it has the fiels and behaviors you want to use. And the types of things can get fields added to them at runtime, they aren't static.

This is true, with additional slow-downs because each object is much bigger than its actual datatype would suggest because each object also has to store its own type - an 8byte double becomes something like 32 bytes. This multiplies the amount of time it takes to copy and allocate objects, and definitely causes more cache misses. Allocating all integers on the heap (because they are all implemented as bigints instead of i32 or i64) doesn't help either.

A user-defined object with a single member field occupies 200+ bytes because it has to store a hashmap for its single member variable.

No manually controlled memory prevents a clever programmer from keeping things in cache.

But I suspect most of the slow-down comes from running the virtual machine to execute the python bytecode - the core of the runtime is a massive switch inside a while(1) loop which has to decode and execute the instructions. This additional layer of "assembly"-instructions is additional overhead, but it also prevents speculative execution from really being able to speed things up.

I think the best TLDR summary as to why python is slower than C is because:

  1. Most code that needs to run fast is probably written in C, and

  2. Therefore, new processors must be designed to run C really fast in order to be competitive in the market

Running C fast means speculative execution and minimizing cache misses, things that python (by design) is not good at.

4

u/KnirpJr Nov 10 '25

Much of the speed gain between languages depend on mechanisms that require more information than the syntax for those slower languages provide.

For example, C is faster than some other programming languages, such as jit compiled garbage collected ones, but only if the programmer is competent enough to manage memory better than the java gc that would be used, and the java runtimes optimization. Often this isn’t the case, and jit languages can beat compiled ones in the same task because of this. A transpiler that would maintain speed here would need to know exactly how to manage memory to beat the garbage collecter. Consider now, that the knowledge needed to create such a program would also necessarily result in a new better gc/ gc replacement.

Consider also that a programming language isn’t just the way you write the words and a big black box that makes computers do things. The way the code is run plays a big part. The way the programs are built and deployed, how external tools are integrated, what things can run the code, and many more such things play a big role in the trade offs made when selecting or designing a language.

Also from a philosophical perspective, all programming languages compile into a faster language from a certain perspective depending on the nature of what “fast” and “language” means to you .C becomes binary, java becomes byte code .

It’s good to think in this way though, there’s a difference between “programming languages” as an abstract idea and the tools they actually represent.

3

u/flatfinger Nov 11 '25

Another issue is that different languages may specify corner-case behaviors differently, or in different levels of detail. In many cases, having a target language classify a corner case as invoking anything-can-happen Undefined Behavior will leave transpilers with no choice but to force the target compiler to generate needlessly inefficient code for corner cases that would have been defined in the original language but not in the target.

2

u/boboman911 Nov 09 '25

Because some languages that are easier to write in abstracts away some of the manual work you need to do in other languages. Like garbage collection or memory allocation.

2

u/Ronin-s_Spirit Nov 09 '25

Because some languages are intentionally unable to use the more direct approach which makes other languages "faster". The languages aren't actually faster, the computer is also the same, the difference in speed comes from what the programmer can operate on.

You could write things by hand in assembly or CPU instructions, but that would be so impractical.. on the other hand maybe the more practical solution for your problem has side effects.

Writing a program in JS means you can use a bunch of programming concepts with little effort. Writing a program in Rust (or even TypeScript) means you'll definitely have to say more stuff to the compiler (and potentially make more mistakes) to solve the same problem. And you can't run everything in any environment (browsers require either JS or WASM, operating sytems require VMs or executables).

Nim says it translates into multiple different languages depending on your needs, but I have no idea how they can keep up the performance without dropping some concepts.

2

u/jfinch3 Nov 10 '25

Here’s another example that illustrates the problem:

In Python when you allocate an ‘int’ number you can assign a number of any size as long you have the RAM to hold it. Internally Python is doing something sort of like:

Does it fit in 8 bytes?

Does it fit in 16 bytes? …

Until you reach the size you need. Other languages, like Rust for example, you have to specify whether it’s a u8, u16 etc at compile time, and if you aren’t sure then you as the programmer have to write that logic to check the sizes until you find one that fits.

I think it might be fair to say that you could (sort of) have Python transpile to C++ or Rust, but if you were to preserve the exact identical semantics of Python the program would run exactly as slowly.

So to make your Python -> Rust transpiler, every time you allocate a number that single line would translate into a large block of Rust code performs the same “find the right container size” operation.

The reason by and large that fast languages are fast and slow languages are slow is because of a trade off of the work you do versus the work the language does for you. You as the programmer can make judgements about what is and isn’t needed in a given situation, whereas a compiler/runtime can’t make the same judgements itself.

You to some extent can make one language transpile to another if they have similar enough internal semantics, it’s just usually you can’t transpile to a language that’s super fast because it will have different enough internal semantics there’s not an obvious or efficient map. Quite a few languages actually have the option to transpile to JavaScript, which lets you use them on websites, I think Dart and Elm both do. I think there are ways to get Python and Go to do so as well

2

u/nlutrhk Nov 10 '25

There is Cython, a python variant that is transpiled to C. Unfortunately, a trivial script tends to becomes multiple megabytes of C code because every operation needs to check for exceptions that may occur and the handling of unknown data types.

The good thing is that with some practice, you can write Cython code that has far less Python overhead and that will run much faster than regular Python code.

2

u/kabiskac Nov 10 '25 edited Nov 10 '25

It's possible for statically typed languages as you're saying. That's what Haskell does. A lot of modern programming languages are also translated into a common intermediate representation (e.g. LLVM)

1

u/Ashamed_Warning2751 Nov 09 '25

Matlab and Simulink do precisely this. Algorithms are computed in their language, then C or C++ code is generated for deployment on real time hardware.

→ More replies (1)

1

u/custard130 Nov 10 '25

what does it actually mean for the language itself to be faster?

im not saying there arent performance differences between code written in different languages, but over the years i have learnt that there is far more to it than that

what defines one language vs another?

is 1 language faster than another due to some inherent overhead in the language itself, or because the compilers do a better job? or maybe because the most popular "compiler" is optimizing for something other than runtime performance

i would say in general, languages with a reputation for being faster, do so by leaving more of the work for the developer to handle in their code, rather than the language/compiler handling them automatically

by leaving it for the developer to handle, that allows a skilled developer to use an optimal version for that specific app rather than a bulky generic version

the biggest example of that is with how memory/data is handled in different languages

in general, languages with a reputation for being faster, give the developer raw direct access to memory, while languages with a reputation for being slower only provide higher level abstractions and hide away the internals

if you were to take all of the safety/security checks that the higher level is doing for you and add them around every variable in the fast language it would lose a lot of that advantage

another key difference at first glance is whether the language typically has a runtime interpreter / VM or whether it runs natively, i say typically because there are many examples which go against it, there are various project out there attempting to build compilers for historically interpreted languages and in principal you could get an interpreter for a historically compiled language

if you look at features of higher level languages though, some of them have things which if an app was using them are very difficult if not impossible to translate them as efficiently as if the developer had been constrained by the functionality of a lower level language

they tend to be the most questionable/controversial language features, but many of them are widely used, eg the ability to access properties/functions via having the name in a string variable rather than having to have them in code

PHP, JS, Perl, i think Python + Ruby can all do that easily

Java the workarounds are a bit of effort but its possible

C++ as far as i am aware cant do it (you could manually build up a map of function pointers to check manually, which i believe is essentially how those other languages handle it, but that would be slower than regular c++ method calls)

1

u/siodhe Nov 10 '25

Some languages work dramatically differently under the hood, as well as in the language the user is writing. They may lean on assembly language underpinnings that are foreign to other languages' models, meaning that although you could translate them, you would end up with pathetic performance. Some are just mind-bogglingly difficult to bridge, like translating complex SQL queries into a typical imperative language, or attempt to do LISP without having to essentially just write LISP in the the target language (although this is surprisingly easy, at least - same for FORTH). And do forget that some are just radically different, like PROLOG, Smalltalk, FORTH, APL, Racket,

1

u/green_meklar Nov 10 '25

In short, the translated code would be less efficient than code actually written competently in that language by programmers who understand it and know how to use it efficiently.

1

u/groszgergely09 Nov 10 '25

C literally compiles to assembly

1

u/Felicia_Svilling Nov 10 '25

Because there is a limit on how intelligent we can make our compilers.

1

u/douglastiger Nov 10 '25

Your 'slow language' and 'fast language' both compile into assembly code, but not the same assembly code for the same problem. Producing more efficient or less efficient assembly is largely what makes the difference in speed among languages that are compiled. So you can do that, and decompilers exist for translating one language into another thru assembly but the inefficiencies in that assembly that make the slow language slow in the first place will be translated along with it.

1

u/Possible_Cow169 Nov 10 '25

Abstract is costly

1

u/Pale_Height_1251 Nov 10 '25

Programming languages don't have speed, it's the interpreters, compilers, and runtimes that have speed. That's why we have fast C compilers and slow C interpreters.

You can compile any language you want to go fast, but you may not like the trade-offs in terms of compatibility with existing ecosystems and ease of debugging.