Skip to content

generator: more idiomatic language APIs for errors and optional values

In this year's Prologin finals, I had discussions with fellow rustaceans on how the generated Rust API felt clumsy and unidiomatic at times. We concluded that it would be great if the API could better match the language's idioms and common patterns more.

The problem

Here are two common patterns that would benefit greatly from a better API:

Optional values

Sometimes, fetching some information through an API call can fail, e.g. if the provided input is invalid. In this case, games usually return a sentinel value that represents "no meaningful value", like -1. This might be idiomatic in C, but since optional values are literally everywhere in programming, modern (i.e. non-C) languages have better ways of representing optional values:

  • Rust, OCaml and Haskell have Option, option and Maybe respectively
  • Python, Java, C# and PHP all have some flavor of null

Errors

Similarly, a champion might attempt to perform an invalid action, in which case the came usually responds with an error enumeration giving more details on why the attempted action was invalid. Once again, every language has its own error handling mechanisms (also see #89):

  • Rust has Result, OCaml has result, Haskell has Exception*
  • Python, Java, C# and PHP have exceptions*
  • C++ programmers can't agree on how to handle errors, leave them alone

* There is a caveat here: unhandled exceptions are propagated and can crash the program, and developers might be forced to write code to handle them (e.g. Java). Competitive programming is not the place for proper error handling and beautiful error messages. There is a trade-off here: having errors crash the program is good for debugging (no error goes unnoticed), but bad for tournaments where you want to continue the match no matter what, and bad for writing quick and dirty code.

Proposed solution

The API is built on top of a C FFI layer, which can hardly be changed as it needs to be common to all languages. However, nothing prevents us from building language-specific abstractions on top of the FFI. I think the two cases presented in this issue are fundamental and deserve special treatment. If we consider this to be true, then we can integrate them in the YAML config files used for specifying a game's API.

Optional values

Functions can mark a function's return value as optional by specifying the sentinel value in a fct_ret_none_val field. This tells the generator to generate code to transform the sentinel into the langage's idiomatic way of representing missing values, like None in Rust or null in Java.

Errors

Errors are specified in a new top-level list error (same level as enum or function), which has fields err_name, err_summary, err_kind. err_kind follows the same format as enum_field.

At the C FFI level, the error is represented as an enum, where the first variant (value 0) is an OK variant representing success.

Language APIs now translate this C enum into the language's idiomatic exception mechanism.


I can work on implementing this myself, but I would like some feedback on whether this is useful (though I have no doubt it is), and whether this is the right way to go. cc @remi-dupre