Type System Roadmap
Type System Roadmap
Section titled “Type System Roadmap”Starlark’s type system is evolving. This page tracks the current state and future direction across implementations.
Current State
Section titled “Current State”starlark-rust (Most Advanced)
Section titled “starlark-rust (Most Advanced)”Meta’s Rust implementation has the most complete type system:
# Full type annotationsdef process(items: list[str], count: int) -> dict[str, int]: result = {} for item in items[:count]: result[item] = len(item) return result
# Record typesConfig = record( name = str, value = int, tags = field(list[str], []),)
# Enum typesStatus = enum("pending", "active", "done")
# Union typesdef handle(input: str | int) -> str: return str(input)Available now:
- ✅ Function parameter and return types
- ✅ Generic types (
list[T],dict[K, V]) - ✅ Union types (
A | B) - ✅
recordfor structured data - ✅
enumfor constrained values - ✅
typingmodule (Any,Callable,Iterable)
Experimental:
- ⚠️ Static type checking (compile-time)
- ⚠️ Type inference
starlark-go (Basic Support)
Section titled “starlark-go (Basic Support)”Google’s Go implementation supports basic annotations:
# Basic type hints (documentation only in most cases)def add(x: int, y: int) -> int: return x + y
# No record/enum support# Use dicts insteadconfig = {"name": "test", "value": 42}Available now:
- ✅ Basic type annotations (syntax support)
- ✅ Some runtime type checking
Not available:
- ❌
recordtype - ❌
enumtype - ❌ Union types
- ❌ Generic type checking
starlark-java (Work in Progress)
Section titled “starlark-java (Work in Progress)”Bazel’s Java implementation is actively developing static types:
# Proposed (not yet implemented)def my_rule_impl(ctx: ctx) -> list[Provider]: ...Tracking: bazelbuild/bazel#27370
Specification Process
Section titled “Specification Process”-
Proposal
New type features are proposed on bazelbuild/starlark
-
Discussion
Maintainers from all implementations discuss feasibility and design
-
Specification Update
Accepted features are added to the spec
-
Implementation
Each implementation adds support at their own pace
Future Directions
Section titled “Future Directions”Static Type Checking
Section titled “Static Type Checking”The biggest upcoming change is compile-time type verification:
# With static types, this error is caught before executiondef greet(name: str) -> str: return "Hello, " + name
greet(42) # Error: expected str, got intBenefits:
- Catch errors earlier in development
- Better IDE support (completion, refactoring)
- Documentation through types
- Performance optimizations
Challenges:
- Maintaining Starlark’s simplicity
- Backwards compatibility with untyped code
- Cross-implementation consistency
Gradual Typing
Section titled “Gradual Typing”The likely path forward is gradual typing:
# Fully typed functiondef typed_function(x: int) -> int: return x * 2
# Untyped function (still valid)def untyped_function(x): return x * 2
# Mixed: typed functions can call untyped onesresult = typed_function(untyped_function(5))This allows:
- Incremental adoption
- Legacy code compatibility
- Opt-in strictness
Protocol Types
Section titled “Protocol Types”Similar to Python’s protocols for structural typing:
# Hypothetical future syntaxPrintable = protocol( to_string = typing.Callable[[], str],)
def print_all(items: list[Printable]) -> None: for item in items: print(item.to_string())Type Aliases
Section titled “Type Aliases”For complex type definitions:
# Hypothetical future syntaxStringMap = dict[str, str]Callback = typing.Callable[[int], str]
def process(data: StringMap, handler: Callback) -> None: ...Writing Future-Proof Code
Section titled “Writing Future-Proof Code”Do: Use Available Types
Section titled “Do: Use Available Types”# Good: Types work across implementationsdef calculate(values: list[int]) -> int: total = 0 for v in values: total += v return totalDo: Encapsulate Implementation-Specific Features
Section titled “Do: Encapsulate Implementation-Specific Features”# If using starlark-rust records, isolate them# config_types.star (starlark-rust only)Config = record(name=str, value=int)
def make_config(name: str, value: int) -> Config: return Config(name=name, value=value)Don’t: Mix Untyped and Typed Inconsistently
Section titled “Don’t: Mix Untyped and Typed Inconsistently”# Avoid: Partial typing is confusingdef process(data, count: int): # data untyped, count typed ...
# Better: All typed or all untypeddef process(data: dict[str, str], count: int) -> list[str]: ...Don’t: Depend on Runtime Type Checking
Section titled “Don’t: Depend on Runtime Type Checking”# Avoid: Relying on type errors at runtimedef risky(x: int) -> int: return x * 2
try: risky("not an int") # May not error in all implementationsexcept: ...
# Better: Explicit validationdef safe(x) -> int: if type(x) != "int": fail("expected int, got " + type(x)) return x * 2Implementation Timeline
Section titled “Implementation Timeline”| Feature | starlark-rust | starlark-go | starlark-java |
|---|---|---|---|
| Basic annotations | ✅ Now | ✅ Now | ✅ Now |
| Runtime checking | ✅ Now | ⚠️ Partial | ⚠️ Partial |
| Records/Enums | ✅ Now | ❌ N/A | ❌ N/A |
| Static checking | ⚠️ Experimental | ❓ Unknown | 🔜 In Progress |