Julia has a bunch of semantic differences that are also responsible. For a quick list:
1. you can't add fields to structs (ie all types have __slots__) This is really important since it means you can store structs inline which avoids a ton of pointer chasing
2. eval always happens in the global scope (and world age means that eval doesn't have effect until you hit the global scope). This means that you can inline code which is one of the most important optimizations.
There are a few of other careful compromises like this where Julia gives up the small amount of dynamism that makes optimization impossible, while keeping enough dynamic behavior to be highly usable without doing anything that makes optimization impossible.
1. you can't add fields to structs (ie all types have __slots__) This is really important since it means you can store structs inline which avoids a ton of pointer chasing 2. eval always happens in the global scope (and world age means that eval doesn't have effect until you hit the global scope). This means that you can inline code which is one of the most important optimizations.
There are a few of other careful compromises like this where Julia gives up the small amount of dynamism that makes optimization impossible, while keeping enough dynamic behavior to be highly usable without doing anything that makes optimization impossible.