A solution to fragmentation caused by camel casing and snake casing in OCaml/Reason

Drup sent a pull request to OCaml on April fools: Make OCaml case-insensitive. I don’t know if the solution was meant as a joke, but the problem itself is real. I will quote Drup for the problem description:

With ReasonML and Bucklescript, the OCaml community has received an influx of programmers coming from web programming languages, notably Javascript. While OCaml programmers traditionally follow the snake_case convention, these new programmers usually follow the camlCase convention. The camlCase convention also has the advantage of mapping very well to Javascript APIs, and has thus been adopted by new libraries, notably Bucklescript’s alternative standard library, Belt.

This has led to some remarks and quite a bit of churn, which led to the creation of libraries such as Tablecloth which offers wrappers over both Core and Belt to provide both camlCase and snake_case.

Clearly, OCaml users will continue to use snake case and Reason users will continue to use camel case. But, it would be a shame to see the communities split over something as inconsequential as casing. Making the compiler case insensitive is perhaps a little bit heavy handed, but there must be another way of bridging the gap.

After all, there is an obvious mapping between snake case and camel case, and my guess is that in very few cases will a library export symbols that cannot be mapped bijectively between the two. This is my proposed solution: what if the casing of a library you are using could be toggled freely in your dune file? Something along the lines of:

(executable
  (name Foo)
  (libraries mylibrary)
  (transform-case snake-case mylibrary))

I am not well versed in the internals of OCaml or Dune, so I don’t know how hard this is to do or if there are any serious issues with it. A simple PPX wouldn’t be enough since you would also need a way to transform the casing of exported symbols in object files, and I don’t know how you would go about this.

Any library would be able to be used freely in either OCaml or Reason, without compromising on casing preference. There would be no breaking changes, since you could simply pretend that the transform-case option doesn’t exist. Libraries like Tablecloth could provide one casing, and not have to pollute their code and documentation with duplicate functions. Cross-pollination between the OCaml and Reason ecosystems would ensue!

Happy to hear a discussion about this. Alternative solutions are also welcome, especially if this does not work.

Solutions based on identifier equivalence classes are going to be an end-user experience nightmare.

They impose a needless cognitive burden on code readers and more important, they break something fundamental: the ability to use basic search functionality to lookup identifiers in source code and its derived artefacts (e.g. API docs). This being grep, your editor built-in search functionality, your browser’s in-page search functionality, web search, GitHub source code search or any non-custom full-text search engine. However crude and primitive you may find these tools I suggest we do not break them in the name of identifier aesthetics.

Instead I rather suggest treating @drup’s proposal the way it should be on such a date.

13 Likes

This is a fair objection.

1 Like

Half of the joke of this proposal is that it’s a (silly, as @dbuenzli pointed out) technical solution to a social problem. You could say it’s a cop-out, as it doesn’t solve the underlying social problem.

(And while the underlying problem is real, and IMHO important, watching people freak out about that patch has been extremely entertaining :smiley: )

2 Likes

Unfortunately, we already have this burden, as the same type might have multiple names, e.g.,

'a option
'a Option.t
'a sexp_option
'a Base__option.t
etc

The same is true for value identifiers, thanks to module aliasing, e.g., Option.iter, Base__option.iter etc.

That’s not to say, of course, that we have to increase this burden, but to highlight that the problem was already there, even before the clash with the world of web developers with their CamelCase notation. And putting jokes aside, this problem should be addressed. Especially on the tooling level (doc generators, merlin, etc), which should follow the Internet Robustness principle and treat literals using their equivalence classes. This is how argot API search was implemented, and I believe, that @Drup was implementing at some point of time and space a better than Argot solution. Not sure if it was published somewhere.

5 Likes

I can comment on the multiple option names, given that I work on these projects and I know why we have all these names.

sexp_option is being deprecated. It was an historical detail of ppx_sexp_conv which is now being replaced by an attribute.

Regarding Base__option.t, its presence is an unfortunate artifact of the way the world works at the moment. There are people working on solving this problem at the root so that these weird modules can eventually go away. However, that requires changes to the language. It is important to keep in mind that such changes to the language can take a lot of time. They require a lot of design work, discussions amongst core OCaml developer and finally implementation. Moreover, because of the nature of this particular work (i.e. namespaces), it will also require proper integration in user facing tools such as dune, odoc, merlin, … This is just to say that we are aware of these problems, we are working on it, but this stuff takes time so please be patient :slight_smile:

In the meantime, I suppose the tooling could have special handling of such special names. However, given that these __ names are meant to go away in the future, it would be totally understable if authors of such tools prefered to wait for the long term solution.

In the end, that leaves us with two names: option and Option.t. This is the case for all pre-defined types and I’m not sure much can be done about this. Indeed, it is nice to have the short names for such standard types, but it also makes sense to have the longer Option.t for consistency.

In any case, the -short-paths option of the compiler is here to help and display the most user friendly name to users.

6 Likes

Which changes do you mean? I thought Namespaces were dropped in favor of module aliasing done automatically by dune.

Ah, not really. This is my understanding of the namespace story: in the past, we only had module packs. However, they suffered severe technical limitations and were effectively unpractical. For instance, at Jane Street we effectively reached the limit of what we could do with module packs, which made progress harder. At the same time, there were a lot of proposals to add namespaces in OCaml. This is a complex subject and no agreement was reached on a particular proposal. Then someone came up with the idea of module aliases and this unblocked the situation.

In a way, module aliases bought us more time to find the right namespace design but I don’t believe they were ever intended as a complete replacement for namespaces.

6 Likes

Sure and you can also write

let zorglub = List.fold

and then use zorglub throughout in your project.

Regarding types, as @jeremiedimino said, you have mostly this problem with built-in types which is not the kind of things you grep for when you try to orient yourself in a code base and personally never found that to be a burden.

I’m not sure that would qualify as an instance of the robustness principle (especially since it’s a controversial one), that’s just basic search interface design; namely token normalization.

But surely if you implement a language aware search engine there’s a lot of clever and interesting things you can do to better satisfy the user’s information need and please do, I never said that this should not be done.

I simply said that more basic, best-effort, search tools should not be broken or rendered less useful for a stupid reason.

I don’t think people freak out about the patch, I think people freak out when they see how many people find that to be a good idea…

This use of zorglub should be universal across all libraries.

5 Likes

Another solution would be to just forbid camelCasing; which is just bad taste and anti-ergonomic (because spaces and underscores are way better word separators, so easier to read, than a change in case). :japanese_goblin: :japanese_ogre:

5 Likes

FYI, snake_case is when you use underscores _ to separate words, contrary to camelCase which relies on the change in case.

Camel case being ironically disfavored in OCaml.

3 Likes

typo corrected, thanks!

Yep. And I sometimes use both camelCase and snake_case in the same code. One of the nice things about ocaml is that aside from capitalizing constructors and not-capitalizing other names, you’re free to choose your names as you wish. I sure would dislike if I were unable to name something “fooBar” because I’d already named something else “foo_bar”.

1 Like