From anecdotal experience I view OCaml's bytecode compile speeds to be on par with Go's (as a rule of thumb I expect about 1 second per 10k lines). Far slower than something like TCC, but quite fast among other languages.
From anecdotal experience I view OCaml's bytecode compile speeds to be on par with Go's (as a rule of thumb I expect about 1 second per 10k lines). Far slower than something like TCC, but quite fast among other languages.
As for your view of OCaml byte code compilation speed being on par with Go seems rather unlikely or I'm misunderstanding what you mean. Go is not dealing with anywhere as near a complex type system as OCaml and generates a lot more potato machine code (usually not using -mnative so you can know you can copy a binary to arbitrary machines).
In general HM-based type systems are both conceptually quite simple and can have quite fast implementations. What makes them seem "complex" is that languages with HM-based type systems also tend to make it hard to "go around" the type system and enforce much more rigid discipline around how your code can be written.
I think this is due to the influence of Pascal and/or Modula on the language.
If you're asking about OCaml's pattern matching, it's compiled quite efficiently: https://www.cs.tufts.edu/comp/150FP/archive/luc-maranget/jun...
In practice it is actually very rare that they significantly affect compile times because it is very rare for the `n`-size to increase as the size of your codebase increases (these exponential blowups are generally limited to a single expression) for non-pathological code. Basically while you can have exponential blowups inside a single expression, I can't think of a time where you'll have exponential blowups across multiple expressions, which is what counts in a large codebase.
One of the times where big-O analysis doesn't accurately predict real-world runtimes.
To be clear, I think pattern matching is a good thing.
Go and HM-style type systems both have set operations they need to do that are of comparable practical computational complexity.
Exhaustivity checking without pattern matching (e.g. inserting wildcard expressions in every argument to a pattern other than the outermost tag) is computationally very straightforward and is at worst linear in the number of constructors a given type has. This is similar in computational complexity to Go's type checking of interfaces, which is also linear in the number of methods (since Go doesn't have any explicit interfaces it cannot simply do a name lookup).
// This still checks for exhaustivity and is at worst
// linear in the number of `Case0`, `Case1`, etc.
case thing of {
Case0 x -> ...
Case1 y -> ...
Case2 z -> ...
}
// This is how you get equivalent to SAT, but is also
// comparatively rare
case thing of {
Case0 True False True -> ...
Case1 True True True -> ...
Case0 True True False -> ...
// etc.
}
Exhaustivity checking in the presence of pattern matching is only non-linear in the number of parameters to the constructor, which in most code is only one (because beyond one usually you would use a record instead). So in practice there aren't any obvious computational edges that Go typechecking has.To add some data to the discussion, I have been recently measuring the compilation profile of some OCaml libraries, and the average time spent in the typechecker is around 40% (https://www.polychoron.fr/ocaml/2021/08/19/measuring_compila...).
Thus the complexity of the OCaml type system can only have a limited effect on OCaml compilation time.
And this measure does include interface files, where the compilation pipeline is reduced to just parsing, typechecking, and dumping the computed file to the disk.
The compiling pipeline of bytecode is basically typing -> lambda -> bytegen
Bytegen is really close to what Zinc does.
But doesn't the compiled code run slower in bytecode mode? I think that counts.
The healthy mix of interpreter/JIT/AOT backends is what many languages miss on their toolchains.