Skip to content

Latest commit

 

History

History
134 lines (100 loc) · 3.9 KB

File metadata and controls

134 lines (100 loc) · 3.9 KB

Reflection-Based Struct Serialization

Overview

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.

Ideal API

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)  # Serialise

Current Reflection Capabilities (Mojo 2026-01)

Mojo's reflection module provides:

Available:

  • get_type_name[T]() - Get type names as strings
  • struct_field_count[T]() - Count fields in a struct
  • struct_field_names[T]() - Get field names (compile-time)
  • struct_field_types[T]() - Get field types
  • struct_field_index_by_name[T]() - Lookup field index
  • struct_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

Requirements for Auto-Serialisation

  1. Runtime field access - Read/write field values dynamically
  2. Dynamic construction - Build structs from parsed data
  3. Recursive handling - Process nested structs automatically
  4. Type conversion - Map TOML types to Mojo types safely
  5. Error handling - Validate missing/invalid fields with good errors

Assessment

Not Ready for v0.6.0-0.7.0 ❌

Blockers:

  1. Cannot access field values at runtime (critical)
  2. Reflection API stability concerns
  3. Unknown performance characteristics
  4. API will evolve and break code

Consensus: Wait for reflection to mature before implementing.

Interim Solution: Trait-Based Approach

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

Roadmap

v0.6.0-0.7.0: Manual Trait Approach (Possible)

  • Define Deserializable and Serializable traits
  • Provide example implementations
  • Document patterns in user guide
  • Consider helper macros if Mojo gains macro support

v0.8.0+: Automatic Reflection (When Ready)

  • 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

References

Decision

Add to roadmap as future feature - Excellent idea, but wait for Mojo reflection to mature. Consider trait-based interim solution for v0.6.0.