Question

If data is simple and objects are complex, I'm curious if there are any existing statically typed languages that would be able to augment(?) a map type into a type with guaranteed fields. I realize that at runtime, in any language this type of check is pretty doable. But in theory I also believe this should be possible to check with a compiler. To do everything below in Java, would be an explosion of interfaces (HasComplete, HasTitle, HasTitleAndComplete)

So has anyone done it? If not, how come? If so, how was it implemented?

This would allow you to read in data but then manipulate it with at least some type safety:

// User input is often simply converted to a Map
function parse(json) -> Map {...} 

// result still has all user input fields, 
// but this would be a runtime exception 
// if specified fields are missing
function cast(Map, Map<fields...>) -> Map<fields...> { ... }

input = "{title:'do it', complete: false, rank: 5, subtitle: 'now'}"

// Would throw class cast exception if complete or title were missing
todo = cast(parse(input), Map<title:str, complete:bool>)     

// Runtime introspection
todo instanceOf Map -> true
todo instanceOf Map<title:str, complete:bool> -> true
todo instanceOf Map<title:str> -> true
todo instanceOf Map<complete:bool> -> true
todo instanceOf Map<complete:date> -> false
todo instanceOf Map<rank:int> -> false because cast() did not specify rank
todo instanceOf Map<title:str, complete:bool, author:str> -> false 

// Typed methods based on map with certain fields
function capitalize_title(Map<title:str>) {...}
function finish_task(Map<complete:bool>) {...}
function finish_and_rename(Map<title:str, complete:bool>, newTitle) {...}
function increase_rank(Map<rank:int>) {...}

// Static Check compile pass
todo = capitalize_title(todo)
todo = finish_task(todo)
todo = finish_and_rename(todo, "[complete]")

// Static Check Compile Fail because cast() did not specify rank
increase_rank(todo)

// Methods could return a type with added (or removed) fields
function add_uuid(Map) -> Map<+id:int> {...}
todo_with_id = add_uuid(todo)
todo_with_id instanceOf Map<title:str, complete:bool, id:int> // true

No correct solution

Licensed under: CC-BY-SA with attribution
scroll top