Making public types concrete

Continuing the discussion from Upcoming Cmdliner 2.0 changes that need your attention:

The loss of deep pattern matching can be a pain. For example, experienced it with PrintBox – it exposes the main type as a view which only works with shallow matching.
printbox type view

This is a problem specifically because of the the design of PrintBox where backends and extensions are whole separate packages. Would be fine to keep PrintBox.t abstract by default, but opt-in concrete for backends and extensions.

1 Like

Right, I’m sure exceptions exists. But the thing I did in cmdliner was particularly stupid, namely in 2011 I defined:

type 'a conv = 'a parser * 'a formatter

There is no interest in pattern matching here… unless there is. While sifting through package failures I saw many cmdliner users that were reusing bits of the predefined converters so they would write:

let parse, _ = Arg.int32 in
…

Which is totally natural – I’m to blame for having exposed a pair – but provides no gain if you compare it to the silently recommended way since 2017:

let parse = Arg.conv_parser Arg.int32 

The next error was likely to wait 8 more years to make it abstract, though I didn’t try to track down if people using pairs wrote the code before 2017.

But I still think that in most of my libraries I’d be pressed to find an example where exposing concrete type to “regular” users of the library makes sense. And I know a few other were I did and I will regret it, e.g. (Vg.Font.t or Vg.Path.outline).

There are also a few other cases where exposing the representation is useful, but the all the ones I can think of are for some sort of advanced usage like writing a new backend for processing a representation. In this case I think it’s better to convert with a representation type exposed in a T.Private or T.Repr module. For example Vgr.Private or Jsont.Repr or Htmlit.El.Low – which shows that I have been highly inconsistent in naming these modules :–)

3 Likes