User suggestion: Use Mojo's reflection capabilities to automatically serialise/deserialise structs to/from TOML, eliminating the need for explicit .as_string(), .as_int(), etc. calls.
struct Config:
var name: String
var port: Int
var debug: Bool
var limits: Limits
struct Limits:
var max_connections: Int
var timeout: Float64
# Automatic serialisation
var config = from_toml[Config]("config.toml") # Deserialise
var toml_str = to_toml(config) # SerialiseMojo's reflection module provides:
✅ Available:
get_type_name[T]()- Get type names as stringsstruct_field_count[T]()- Count fields in a structstruct_field_names[T]()- Get field names (compile-time)struct_field_types[T]()- Get field typesstruct_field_index_by_name[T]()- Lookup field indexstruct_field_type_by_name[T]()- Lookup field type
❌ Critical Limitations:
- No runtime field value access (can get names, but not read/write values)
- No trait/interface querying
- No enum reflection
- Compile-time only operations
- Early-stage stability concerns
- Runtime field access - Read/write field values dynamically
- Dynamic construction - Build structs from parsed data
- Recursive handling - Process nested structs automatically
- Type conversion - Map TOML types to Mojo types safely
- Error handling - Validate missing/invalid fields with good errors
Blockers:
- Cannot access field values at runtime (critical)
- Reflection API stability concerns
- Unknown performance characteristics
- API will evolve and break code
Consensus: Wait for reflection to mature before implementing.
Add a Deserializable trait that users implement manually:
trait Deserializable:
fn from_toml(data: Dict[String, TomlValue]) raises -> Self
trait Serializable:
fn to_toml(self) -> Dict[String, TomlValue]
struct Config(Deserializable, Serializable):
var name: String
var port: Int
var debug: Bool
fn from_toml(data: Dict[String, TomlValue]) raises -> Config:
return Config(
name=data["name"].as_string(),
port=data["port"].as_int(),
debug=data["debug"].as_bool()
)
fn to_toml(self) -> Dict[String, TomlValue]:
var result = Dict[String, TomlValue]()
result["name"] = TomlValue(self.name)
result["port"] = TomlValue(self.port)
result["debug"] = TomlValue(self.debug)
return result^
# Usage - cleaner than raw Dict access:
var data = parse(toml_content)
var config = Config.from_toml(data)
var toml_str = to_toml(config.to_toml())Benefits:
- Reduces boilerplate
- Type-safe at struct definition
- Stable (no experimental features)
- Can be implemented now
Drawbacks:
- Still requires manual implementation per struct
- Not as ergonomic as automatic reflection
- Define
DeserializableandSerializabletraits - Provide example implementations
- Document patterns in user guide
- Consider helper macros if Mojo gains macro support
- Automatic serialisation:
from_toml[T](str) - Automatic deserialisation:
to_toml(struct) - Type-safe config loading
- Blocked on: Runtime field access in Mojo reflection
Status: Tracking Mojo stdlib development
- Mojo Reflection Docs: https://docs.modular.com/mojo/std/reflection/
- User discussion: v0.5.0 release feedback
- Related: serde in Rust, dataclasses in Python
Add to roadmap as future feature - Excellent idea, but wait for Mojo reflection to mature. Consider trait-based interim solution for v0.6.0.