I can't speak to Scala's compile time issues, but for C++ there are few factors contributing to long compile times.
- "module" system based around textual inclusion of header file: essentially the compiler duplicates a lot of effort, reading the same files over and over for each translation unit, and you can't avoid the cost because of the interaction with text macros. That said, C++20 offers a solution through its new module system; it will be interesting to see how much of an improvement this will bring.
- complicated parser requiring contextual information (i.e. information from typing and analysis phases) in order to distinguish between, say, a class object instantiation and function forward declaration (the notorious most vexing parse). Most other languages learned from the syntax mistakes of C++, but C++ had a clear mandate to not break existing C code, so it had no choice but to build what existed.
- C++ template system revolves around a kind of syntactic substitution, where you have a template expression with some type variable, and at the template instantiation site (i.e. every call, not at the definition) you you essentially do template argument deduction yielding concrete type bindings for the type variables, and then your next step is the transform the AST with the template expressions into concrete types, functions, etc. This involves a lot of tree transformations which can be expensive. I think with other languages this is less of a problem in part because the type checking is done at the definition site, rather than at call site. Here again C++ concepts were introduced to address this issue, but as always in C++, it's not all milk and honey.
- "module" system based around textual inclusion of header file: essentially the compiler duplicates a lot of effort, reading the same files over and over for each translation unit, and you can't avoid the cost because of the interaction with text macros. That said, C++20 offers a solution through its new module system; it will be interesting to see how much of an improvement this will bring.
- complicated parser requiring contextual information (i.e. information from typing and analysis phases) in order to distinguish between, say, a class object instantiation and function forward declaration (the notorious most vexing parse). Most other languages learned from the syntax mistakes of C++, but C++ had a clear mandate to not break existing C code, so it had no choice but to build what existed.
- C++ template system revolves around a kind of syntactic substitution, where you have a template expression with some type variable, and at the template instantiation site (i.e. every call, not at the definition) you you essentially do template argument deduction yielding concrete type bindings for the type variables, and then your next step is the transform the AST with the template expressions into concrete types, functions, etc. This involves a lot of tree transformations which can be expensive. I think with other languages this is less of a problem in part because the type checking is done at the definition site, rather than at call site. Here again C++ concepts were introduced to address this issue, but as always in C++, it's not all milk and honey.