Skip to main content

TypR vs R — What Really Changes

A side-by-side comparison of R and TypR.

AspectR (classic)TypR
End of instructionnewline is sufficient; expected (parser warning if missing)
Typingdynamic, no annotationsstatic; fn(...) always requires a return type
Name casingfree conventionenforced by parser: snake_case for let, PascalCase for type/aliases
Listslist(a = 1, b = 2), no validationlist{a=1, b=2} generates a real constructor + validator (as.T, validate_T)
Sum typesno native type — ad-hoc class conventionstags .A(T) | .B + exhaustive match
Method dispatchUseMethod/S3, or $ on R6/environment objectsgeneral UFCS: x.f(y)f(x, y) for any type
Interfacesno formal notioninterface { ... } + structural validator I(x) at compile time
Pattern matchingswitch(), barely typedmatch with tag/type/record/tuple/wildcard patterns
Modulespackages / local() / ad-hoc environmentsmodule M { ... } → R environment, explicit @pub visibility
Genericsnone (dynamic S3 dispatch)type parameters T, kind sigils (%R @I ^S ?B #N)
Mutationx <- f(x) explicitexpr!; sugar + State for real shared mutation
OutputR directly executedtranspiles to idiomatic R (R/*.R) — 100% of generated R is readable and executable as-is

Key takeaway

TypR is not a new runtime — it is a layer of static verification and syntactic sugar (UFCS, tags, match, interfaces, modules, generics) that fully desugars into conventional R before execution. None of this exists at R runtime; everything is resolved by the TypR compiler.


Migration effort

TypR is designed for gradual adoption:

  • Start with a single .ty file in your existing R package
  • Call R functions from TypR using @ signatures
  • Write new functions in TypR incrementally
  • Generated R code is standard — CRAN, devtools, testthat all work unchanged

See Compatibility with R for a detailed walkthrough.