Design for handling error codes
IIUC, the rationale behind the current design for handling error code is to separate the rendering from the code generating the diagnostic.
Trying to use the library in a project, I realize that if there are multiple diagnostics but I want to use the rendering only at once place in my code, this is not convenient to use since I need to export multiple definitions and it may not compose that well if I have multiple definitions of error codes. In that case, they need to be wrapped.
Moreover, the library does not ensure the uniqueness of the representation of the error code.
Have you considered a design where the library exports a type code with some constructors. And it is the library that handles the rendering?
Probably the user must provide optionally a code and a number. Then it is the responsibility of each library to provide such a mapping from any error type the user's library is using instead of doing this mapping by the renderer. This way, we recover some locality property.
If the library maintains some global state, it can also check where a code is not registered twice.
By the way, at the moment, there is no way to opt-out from the error code (like for an Help message). Maybe code_to_string should return an option? Or the engine should handle the empty string in a particular way.
Trying to use the library in a project, I realize that if there are multiple diagnostics but I want to use the rendering only at once place in my code, this is not convenient to use since I need to export multiple definitions and it may not compose that well if I have multiple definitions of error codes. In that case, they need to be wrapped.
The design of error codes was to be as agnostic as possible (hence why we parameterise the types and require a code_to_string function for rendering).
For your use-case, to avoid wrapping multiple definitions I suggest the following:
- Polymorphic variants
- Extensible variants
- A single large closed variant for error codes (this is what rustc does)
Moreover, the library does not ensure the uniqueness of the representation of the error code.
It is up to the user to ensure injectivity of code_to_string for the existing design. I'll make this clearer in the documentation.
However, if you wish to keep the wrapped representation with a local code_to_string function for each code type, I suggest either:
- Prefixing the individual codes when you wrap them. This would trivially give you injectivity for
code_to_string. - Have some global hashtbl of codes, and check injectivity on registration of the mapping.
By the way, at the moment, there is no way to opt-out from the error code (like for an Help message). Maybe code_to_string should return an option? Or the engine should handle the empty string in a particular way.
You should be able to opt-out of error codes by simply providing None for a code. For example:
open Grace
let diagnostic = Diagnostic.createf Help "help me"
Closing as won't fix