Cryptosense is happy to announce the initial release of ppx_enum !
ppx_enum is a ppx to derive enum-like modules from variant definitions. It’s inspired by the enum declaration syntax in Python, and various other languages.
Enums are bare variants that are intended to represent a flag that can have more values than just true and false. The idea is that ppx_enum makes it easier to work with enums, in particular handling the conversion to and from strings. This is useful when (de)serializing values (for example, when serializing to store in a database), and cuts down on repetitive boilerplate code.
Consider the following simple example:
type my_enum =
| Foo
| Bar
| Baz
[@@deriving enum]
The use of [@@deriving enum] will generate the following functions:
let my_enum_to_string = function
| Foo -> "Foo"
| Bar -> "Bar"
| Baz -> "Baz"
let my_enum_from_string = function
| "Foo" -> Ok Foo
| "Bar" -> Ok Bar
| "Foo" -> Ok Foo
| _ -> Error ...
let my_enum_from_string_exn = function
| "Foo" -> Foo
| "Bar" -> Bar
| "Foo" -> Foo
| _ -> invalid_arg ...
Since we found this was something we were doing a lot in our code, the use of ppx_enum has improved readability, reduced the need for boilerplate tests and made the conversions less error prone (as it eliminates bugs caused by typos in the string conversion methods).
It’s in a beta release at this point so any feedback is appreciated!
Thanks for the contribution! PPXs like this that eliminate type-related boilerplate are really valuable in my experience.
A couple of thoughts.
It’s perhaps worth mentioning that ppx_enumerate has a very similar name, but quite different semantics. Someone using both will write [@@deriving enumerate, enum] to mean rather different things. (enumerate lists all examples in an all value, and works for more than simple variants.)
One can achieve the same goal of ppx_enum using [@@deriving sexp] and Sexpable.Of_stringable or similar. It’s as syntactically lightweight as what you describe here, since you need to explicitly construct, e.g., the to_string from the sexp_of_t, but it avoids most of the boilerplate you’re trying to take care of here, and is more general.
@Drup: That is definitely a problem - I’d completely missed the clashing name, and it doesn’t seem like you can have namespace calls like [@@deriving ppx_enum.enum] in the same way that you can with ppx attributes - do you know of any way that you could use the two at the same time?
It would be possible to work around by just adding the plugins of ppx_deriving as libraries rather than ppx_deriving.std, but that is obviously a pain (and you could never use at the same time as ppx_deriving.enum even though it seems unlikely you would want to).
I’d guess that maybe a rename is the solution here, but I can’t think of a good one immediately.
Strong agree. This behavior belongs in ppx_deriving core! (It’s exactly what I, also, expected the builtin enum deriver to do; and I was similarly disappointed to @echowuhao when I discovered it only handled integers.)
@leamingrad any chance you’d be willing to upstream this work? What if it requires a small change in semantics, to fit in with the other std plugins; how widely have you used it internally, how difficult would it be to refactor?
To work around the name clash, the name of the deriver has been changed to str_enum, so the example above would now be:
type my_enum =
| Foo
| Bar
| Baz
[@@deriving str_enum]
@ELLIOTTCABLE and @echowuhao: I am glad to hear that this is helpful to the bucklescript community, but I don’t have any plans to upstream it into ppx _deriving, since I think that migrating away from using ppxlib would be a step backwards.