What are the differences between templates in C++ and generics in Go and TypeScript?
Generics in Go and TypeScript do not work in exactly the same way as templates in C++. While they all provide a way to write reusable and type-safe code, the underlying mechanisms and philosophies differ significantly.
1. C++ Templates
Compile-time code generation: C++ templates are a form of compile-time metaprogramming. When you use a template with a specific type, the compiler generates a separate version of the code for that type.
Turing complete: Templates in C++ can be used for complex compile-time computations, such as SFINAE (Substitution Failure Is Not An Error), specialization, and overloading.
Performance trade-off: Since each instantiation creates a new version of the code, it can lead to code bloat.
Example:
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
int result = add(5, 10); // Instantiates add<int>
double dresult = add(5.5, 2.2); // Instantiates add<double>
}
2. Go Generics (Since Go 1.18)
Type parameters with constraints: Go generics introduce type parameters with constraints defined via interfaces.
Type erasure approach: Unlike C++ templates, Go generics are implemented using a form of type erasure at runtime. The compiler generates a single version of the code, using reflection or interface boxing when necessary.
Simpler and more restricted: Go generics are deliberately kept simple to avoid complexity and compilation overhead.
Example:
func Add[T int | float64](a, b T) T {
return a + b
}
func main() {
fmt.Println(Add(3, 4))
fmt.Println(Add(3.5, 2.2))
}
3. TypeScript Generics
Runtime type erasure: TypeScript generics exist only at compile time and do not affect the emitted JavaScript code.
Flexible and dynamic: Since TypeScript is a superset of JavaScript, its generics are more flexible, focusing on ensuring type safety during development but without runtime enforcement.
No performance cost: Since generics vanish in the compiled JavaScript, there's no runtime overhead.
Example:
function identity<T>(arg: T): T {
return arg;
}
console.log(identity<number>(42));
console.log(identity<string>("Hello"));
Key Differences Summary
Final Considerations
If you're coming from a C++ background, Go and TypeScript generics may feel less powerful because they do not create specialized code for each type but instead rely on abstraction.
Go aims for simplicity and maintainability with minimal runtime overhead.
TypeScript generics provide static type safety without affecting runtime behavior.
Each approach is tailored to the goals of the respective language, prioritizing either performance (C++), simplicity (Go), or developer experience (TypeScript).