Skip to content

Instantly share code, notes, and snippets.

@jabrena
Created November 29, 2025 12:09
Show Gist options
  • Select an option

  • Save jabrena/2c37bb1b2db4f2295465ce19cf432b81 to your computer and use it in GitHub Desktop.

Select an option

Save jabrena/2c37bb1b2db4f2295465ce19cf432b81 to your computer and use it in GitHub Desktop.
Comprehensive Generics Comparison Table
Feature Java Scala Kotlin Rust Go Zig Python JavaScript TypeScript
Implementation Strategy Type erasure Type erasure (JVM) but with TypeTag/ClassTag Type erasure (JVM) but with reified for inline Monomorphization GCShape stenciling (hybrid) Monomorphization via comptime Runtime duck typing, optional static analysis No type system Structural type system, compiles to JS
Syntax <T> angle brackets [T] square brackets <T> angle brackets <T> angle brackets [T] square brackets comptime T: type parameter [T] square brackets (3.9+) N/A <T> angle brackets
Type Checking Compile-time, mandatory Compile-time, mandatory Compile-time, mandatory Compile-time, mandatory Compile-time, mandatory Compile-time, mandatory Optional via external tools (mypy) ❌ None Compile-time, optional enforcement
Runtime Type Enforcement ⚠️ Erased but checked at boundaries ⚠️ Erased unless TypeTag ⚠️ Erased unless reified ❌ None (monomorphized) ❌ None ❌ None ❌ None (hints ignored) ❌ None ❌ None (erased to JS)
Primitive Type Support ❌ Must box (Integer, Double) ⚠️ Yes with @specialized ✅ Automatic optimization ✅ Full support ✅ Full support ✅ Full support ✅ No distinction (all objects) ✅ No distinction ✅ No distinction (JS runtime)
Runtime Type Info ❌ Erased (except raw types) ⚠️ Available with TypeTag ⚠️ Available with reified ❌ Not available ❌ Not available ❌ Not available by default ✅ Full via annotations ❌ None ❌ Erased to JS
Performance Cost ⚠️ Boxing overhead, vtable calls ⚠️ Similar to Java unless specialized ⚠️ Better than Java, some optimization ✅ Zero-cost abstraction ✅ Near zero-cost ✅ Zero-cost abstraction N/A (dynamic, hints are free) N/A (dynamic) N/A (JS performance)
Variance Use-site only (? extends, ? super) Declaration-site (+T, -T) and use-site Declaration-site (out, in) and use-site Automatic inference ❌ Invariant only ❌ Invariant only Declaration-site (TypeVar covariant/contravariant) N/A Bivariant by default, can specify
Type Bounds extends for upper bounds Upper (<:), lower (>:), context, view Upper (:) with multiple where Trait bounds with where Interface constraints ❌ Duck typing at comptime bound= and constraints in TypeVar N/A extends for upper bounds
Higher-Kinded Types ❌ Not supported ✅ Full support F[_] ❌ Not supported ⚠️ Via GATs (Generic Associated Types) ❌ Not supported ⚠️ Via comptime metaprogramming ❌ Not supported N/A ❌ Not supported
Const/Value Generics ❌ Not supported ❌ Not supported ❌ Not supported const N: usize ❌ Not supported ✅ Any comptime value ⚠️ Limited via TypeVarTuple N/A ❌ Not supported
Type Inference ⚠️ Limited, improved with var ✅ Excellent ✅ Excellent ✅ Excellent ✅ Excellent ✅ Excellent ✅ Excellent (mypy) N/A ✅ Excellent
Null Safety Integration ❌ No integration ⚠️ Via Option[T] ✅ Built-in T vs T? ✅ Via Option ⚠️ Via pointers vs values ⚠️ Via ?T optionals ⚠️ Via Optional[T] or T | None ❌ None ⚠️ Via T | null | undefined
Duck Typing ❌ Nominal typing only ❌ Nominal typing only ❌ Nominal typing only ❌ Nominal typing only ⚠️ Interface satisfaction ⚠️ Structural at comptime ✅ Native, fundamental ✅ Native, fundamental ⚠️ Structural typing
Structural Typing ❌ Not supported ❌ Not supported ❌ Not supported ❌ Not supported ✅ Yes (interfaces) ⚠️ Via comptime ✅ Protocols (PEP 544) ✅ Native ✅ Core feature
Array Handling ⚠️ Covariant arrays, invariant generics ✅ Invariant, consistent ✅ Invariant, consistent ✅ Invariant, consistent ✅ Invariant slices ✅ Consistent ✅ Lists are objects ✅ Arrays are objects ✅ Arrays typed as T[]
Generic Arrays/Collections ❌ Cannot create new T[] ⚠️ Workarounds with ClassTag ⚠️ Some limitations ✅ Full support ✅ Full support ✅ Full support ✅ Full support (runtime) ✅ Full support ✅ Type checking only
Specialization ❌ Not available ✅ @specialized annotation ⚠️ Automatic for primitives ✅ Automatic monomorphization ⚠️ GCShape groups ✅ Full monomorphization N/A N/A N/A
Associated Types ❌ Not supported ⚠️ Via type members ❌ Not supported ✅ Native support ❌ Not supported ⚠️ Via comptime structs ❌ Not supported N/A ⚠️ Via mapped types
Union Types ❌ Not supported ⚠️ Via sealed traits ❌ Not supported ⚠️ Via enums ❌ Not supported ⚠️ Via tagged unions ✅ Full support (int | str) ✅ Dynamic (anything) ✅ Full support (T | U)
Intersection Types ⚠️ Via bounds T extends A & B ✅ Via with keyword ⚠️ Via where clause ⚠️ Via multiple trait bounds ❌ Not supported ❌ Not supported ❌ Not supported N/A ✅ Full support (T & U)
Literal Types ❌ Not supported ❌ Not supported ❌ Not supported ❌ Not supported ❌ Not supported ⚠️ Via comptime ✅ Literal[value] N/A ✅ Native support
Type Aliases ❌ Not supported type keyword typealias type keyword type keyword ✅ Implicit via const type keyword (3.12+) N/A type keyword
Conditional Types ❌ Not supported ⚠️ Limited via implicits ❌ Not supported ❌ Not supported ❌ Not supported ✅ Via comptime if ❌ Not supported N/A T extends U ? X : Y
Mapped Types ❌ Not supported ❌ Not supported ❌ Not supported ❌ Not supported ❌ Not supported ⚠️ Via comptime ❌ Not supported N/A { [K in T]: U }
Template Literal Types ❌ Not supported ❌ Not supported ❌ Not supported ❌ Not supported ❌ Not supported ❌ Not supported ❌ Not supported N/A `prefix${T}`
Operator Constraints ❌ Only via interfaces ❌ Only via type classes ❌ Only via interfaces ⚠️ Via traits (Add, Mul, etc.) ✅ comparable, Ordered ❌ Duck typing ❌ Duck typing N/A ❌ Not supported
Reflection/Introspection ⚠️ Limited, especially with generics ✅ TypeTag/Manifest ⚠️ reified for inline ⚠️ Limited (type_name, TypeId) ⚠️ Limited (reflect package) ✅ Full @typeInfo at comptime ✅ Full annotations ✅ Full (typeof, instanceof) ❌ Erased at runtime
Method-Level Type Params ✅ Yes ✅ Yes ✅ Yes ✅ Yes ⚠️ Not on generic type methods ✅ Yes (via comptime) ✅ Yes N/A ✅ Yes
Wildcard/Existential Types ⚠️ Wildcards ? ✅ Existential types ⚠️ Star projection * ⚠️ impl Trait ❌ Not supported ⚠️ anytype ⚠️ Any type N/A ⚠️ unknown type
Self-Referential Types ⚠️ Recursive bounds hack ✅ this.type ✅ Via generics ⚠️ Via traits ❌ Not supported ⚠️ Via comptime ✅ Self (3.11+) N/A ✅ this type
Error Messages ⚠️ Confusing wildcard captures ⚠️ Can be very complex ✅ Generally good ⚠️ Can be verbose ✅ Simple and clear ⚠️ Comptime errors can be cryptic ✅ Tool-dependent (mypy is good) N/A ✅ Generally excellent
Binary Size Impact ✅ Single version (small) ✅ Single version (small) ✅ Single version (small) ❌ Large (each instantiation) ⚠️ Moderate (grouped) ❌ Large (each instantiation) N/A N/A N/A
Compilation Speed ✅ Fast ⚠️ Slower ✅ Moderate ❌ Slow (monomorphization) ✅ Fast ⚠️ Moderate-slow (comptime) ✅ Instant (no compilation) ✅ Instant ⚠️ Moderate (type checking)
Learning Curve ⚠️ Moderate (wildcards confusing) ❌ Steep (many features) ✅ Gentle ❌ Steep (lifetimes, ownership) ✅ Very gentle ⚠️ Moderate (comptime concept) ✅ Optional, gradual ✅ None needed ⚠️ Moderate (advanced types)
Maturity ✅ 20+ years (since 2004) ✅ 15+ years ✅ Mature (since 2016) ✅ Mature (since 2015) ⚠️ New (since 2022) ⚠️ Language still evolving ⚠️ Types since 2015, evolving N/A ✅ Mature (since 2012)
Standard Library Usage ✅ Pervasive (Collections, etc.) ✅ Pervasive ✅ Pervasive ✅ Pervasive ⚠️ Minimal (slices, maps packages) ✅ Pervasive ⚠️ Growing adoption N/A ✅ In @types definitions
Gradual Typing ❌ All-or-nothing ❌ All-or-nothing ❌ All-or-nothing ❌ All-or-nothing ❌ All-or-nothing ❌ All-or-nothing ✅ Core philosophy N/A ⚠️ Via any type
Types as First-Class Values ❌ Not supported ⚠️ Via reflection ❌ Not supported ❌ Not supported ❌ Not supported ✅ Full support ⚠️ Via annotations ✅ Yes (constructors) ❌ Only at type level
Inline/Unrolling Control ⚠️ JIT decides ⚠️ @inline hints ⚠️ inline keyword hint ✅ #[inline] attribute ⚠️ Compiler decides ✅ inline keyword guaranteed N/A N/A N/A
Generic Exceptions ❌ Cannot extend Throwable ⚠️ Via type bounds ❌ Limited ✅ Result<T, E> pattern ❌ No exceptions ✅ Error unions !T ✅ Any type can be exception ✅ Any type can be thrown ⚠️ Typed but not enforced
Type Narrowing ⚠️ Via instanceof ⚠️ Pattern matching ⚠️ Smart casts ⚠️ Pattern matching ⚠️ Type switches ⚠️ Via comptime ✅ isinstance guards ✅ typeof guards ✅ Control flow analysis
Tuple Types ❌ Not supported ✅ Native tuples ❌ Use data classes ✅ Native tuples ❌ Not supported ✅ Native tuples ✅ Tuple[T, U] ⚠️ Arrays only ✅ [T, U] tuples
Readonly/Immutability ⚠️ Via final keyword ⚠️ Via val keyword ⚠️ Via val keyword ✅ Core feature (ownership) ❌ Not enforced ⚠️ Via const ❌ Not enforced ❌ Not enforced ✅ readonly modifier
Excess Property Checking ✅ Yes ✅ Yes ✅ Yes ✅ Yes ✅ Yes ✅ Yes ⚠️ Limited (mypy strict mode) ❌ None ✅ For object literals

Legend

  • ✅ Full support / Excellent
  • ⚠️ Partial support / With limitations
  • ❌ Not supported / Poor
  • N/A - Not applicable to language paradigm
@jabrena
Copy link
Author

jabrena commented Nov 30, 2025

Generics Comparison: Java, C, Assembly, and Crystal

Feature Java C Assembly Crystal
Native Generics Support ✅ Built-in language feature ❌ Not supported ❌ Not supported ✅ Built-in language feature
Implementation Strategy Type erasure Manual (void*/macros/codegen) Manual code duplication Monomorphization
Syntax <T> angle brackets Macros or void* casts N/A - labels/registers only (T) parentheses
Type Safety ✅ Full compile-time checking ❌ None (void*) or ⚠️ Limited (macros) ❌ None whatsoever ✅ Full compile-time checking
Type Checking Compile-time, mandatory ❌ None (void*) or limited (macros) ❌ None Compile-time, mandatory
Type Inference ✅ Good (especially modern Java) ❌ None ❌ None ✅ Excellent
Runtime Type Enforcement ⚠️ Erased but checked at boundaries ❌ None ❌ None ❌ None (monomorphized)
Primitive Type Support ❌ Must box (Integer, Double) ✅ No distinction (if implemented) ✅ All data is just bytes ✅ Full support, no boxing
Runtime Type Info ❌ Erased (except raw types) ❌ Lost with void* or ✅ Separate (macros) ❌ None ⚠️ Available via reflection
Performance Cost ⚠️ Boxing overhead, vtable calls ✅ Zero (macros) or ⚠️ Pointer overhead (void*) ✅ Zero - you control everything ✅ Zero-cost abstraction
Binary Size ✅ Small (single version) ⚠️ Small (void*) or ❌ Large (macros) ⚠️ Depends on implementation ❌ Large (each instantiation)
Compile Time ✅ Fast ✅ Fast (void*) or ⚠️ Slow (macro heavy) ✅ Very fast ⚠️ Can be slow (monomorphization)
Error Messages ✅ Clear, type-specific ❌ Cryptic macro errors or runtime crashes ❌ None - crashes or wrong results ✅ Excellent, clear
Code Reuse ✅ Write once, use anywhere ❌ Explicit instantiation per type ❌ Copy-paste or manual duplication ✅ Write once, use anywhere
Standard Library ✅ Comprehensive generic collections ❌ No generic library ❌ No standard library ✅ Generic collections built-in
Learning Curve ⚠️ Moderate ❌ Complex (must learn workarounds) ❌ Extremely steep ✅ Gentle, intuitive
Memory Safety ✅ GC handles it ⚠️ Manual, error-prone ❌ Completely manual, very dangerous ✅ GC handles it
Memory Management ✅ Automatic (GC) ⚠️ Manual (malloc/free) ⚠️ Manual (allocate/deallocate) ✅ Automatic (GC)
Null Safety ⚠️ NullPointerException risk ⚠️ Segfault risk with pointers ⚠️ Access violations ✅ Compile-time nil checking
Bounds/Constraints ✅ Full support (extends) ❌ Not possible ❌ Not possible ✅ Full support (type restrictions)
Union Types ❌ Not supported ⚠️ Via unions (type-unsafe) ⚠️ Manual bit manipulation ✅ Full support (T | U)
Type Aliases ❌ Not supported ✅ typedef N/A ✅ alias keyword
Variance Use-site only (? extends, ? super) N/A N/A ⚠️ Limited support
Higher-Kinded Types ❌ Not supported N/A N/A ❌ Not supported
Const/Value Generics ❌ Not supported ⚠️ Via macros (#define) ⚠️ Via assembly-time constants ❌ Not supported
Specialization ❌ Not available ✅ Each macro instantiation is specialized ✅ You write specialized code ✅ Automatic monomorphization
Method-Level Type Params ✅ Yes ⚠️ Via macros N/A ✅ Yes
Operator Overloading ❌ Not supported ❌ Not supported N/A - direct operations ✅ Full support
Compile-Time Execution ❌ Very limited ⚠️ Preprocessor only ⚠️ Assembler macros only ✅ Rich macro system
Reflection/Introspection ⚠️ Limited, especially with generics ❌ None ❌ None ✅ Full reflection at runtime
Inline Control ⚠️ JIT decides ⚠️ Compiler hints (inline keyword) ✅ Complete control ✅ Always inlined
Platform Abstraction ✅ Write once, run anywhere (JVM) ⚠️ Portable source, recompile ❌ CPU-specific ✅ Cross-platform LLVM backend
Metaprogramming ❌ Limited ⚠️ Preprocessor macros only ⚠️ Assembly-time macros ✅ Powerful macro system
Duck Typing ❌ Nominal typing only N/A N/A ⚠️ Structural via duck typing
Nil/Null Handling ⚠️ Can be null, runtime errors ⚠️ NULL pointers, segfaults ⚠️ Zero/invalid addresses crash ✅ Nil-safe types (T
Pattern Matching ⚠️ Limited (switch, instanceof) ❌ Not supported ❌ Not supported ✅ Full pattern matching
Tuple Types ❌ Not supported ❌ Not supported ❌ Not supported ✅ Native tuples
Concurrency Model ⚠️ Threads, synchronized ⚠️ POSIX threads, manual ⚠️ Completely manual ✅ Fibers (lightweight)
Maturity ✅ 20+ years (since 2004) ✅ 50+ years (no generics ever) ✅ 70+ years ⚠️ Relatively young (2014)
Ecosystem Size ✅ Massive ✅ Massive ⚠️ Architecture-specific ⚠️ Growing
Production Readiness ✅ Battle-tested enterprise ✅ Industry standard for systems ✅ Ultimate control ⚠️ Production-ready but smaller adoption
Debugging Generics ⚠️ Can be tricky (erasure) ❌ Very difficult ❌ Register-level debugging ✅ Good debug info

@jabrena
Copy link
Author

jabrena commented Nov 30, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment