Using an editor that shows type inlays (e.g. VSCode) helps a lot but not fully because a lot of types are inferred as generics.
You're also correct that you don't have to use lists, but again most OCaml code does.
Using an editor that shows type inlays (e.g. VSCode) helps a lot but not fully because a lot of types are inferred as generics.
You're also correct that you don't have to use lists, but again most OCaml code does.
Most OCaml code use .mli which does have types. This is the recommended practice but I noticed a lot of beginners coming from other languages are reluctant to use them (because of duplication). It's a simple idea but I think it's a strong point of OCaml and it makes easier to program "in the large" than Haskell for instance.
And I did not experience any advantage of separate signature files so far, but I also haven't written anything large in OCaml (>100 kLOC).
It partially helps since it forces you to have types where they matters most: exported functions
> And I did not experience any advantage of separate signature files so far,
100kLoc is already quite big! I'm starting to think I'm an outlier since a lot of people don't see the benefits :)
For me, it helps because I really don't want to see the implementation when I use an API. If I need to look at the implementation, it means the interface isn't well specified. All I need should be in the interface: types, docs, (abstract) types. And no more.
Typically, an .ml file will have more than what is exported, types won't be abstract but will have a concrete implementation, and type signatures may be missing. How would it feels like to use list if only https://github.com/ocaml/ocaml/blob/trunk/stdlib/list.ml was available, instead of https://github.com/ocaml/ocaml/blob/trunk/stdlib/list.mli? and that's not the most compelling example since it's a simple module where the main type isn't abstract. Generally speaking, giving up mli means giving up on encapsulation which is one of the primary tools to deal with large programs.
Haskell forces you to say what is exported from a module, but the module user can only see the names. To see the signatures, you need to rely on generated doc or look it up on the code.
Arguably, since OCaml has includes, it suffers from the same problem, your ".mli" may have tons of include and it becomes harder to see what's exported without an external tool
But the problém the OP has is not knowing the types when reading the source (in the .ml file).
> How would it feels like to use list if only https://github.com/ocaml/ocaml/blob/trunk/stdlib/list.ml was available,
If the signature where in the source file (which you can do in OCaml too), there would be no problem - which is what all the other (for some definition of "other") languages except C and C++ (even Fortran) do.
No, really, I can't see a single advantage of separate .mli files at all. The real problém is that the documentation is often worse too, as the .mli is autogenerated and documented afterwards - and now changes made later in the sources need to be documented in the mli too, so anything that doesn't change the type often gets lost. The same happens in C and C++ with header files.
> the real problém is that the documentation is often worse too, as the .mli is autogenerated and documented afterwards
Of course, that would defeat the purpose of having interfaces and is incredibly bad practice. People do that when they try to fix an already broken codebase. It's actually pretty ironic that people who care about type safety (which I is why they use OCaml in the first place) don't value (or understand) things like encapsulation.
In OCaml you can't. If I could I wouldn't care about interface files, because I wouldn't need them.
I agree that the encapsulation capabilities of mli files are great, but I don't see why they need to be written in a separate file (apart from the obvious reason: that's how OCaml does it, and you can't just change a language's design just because you don't like one bit of it!)
If the list is not being used in a critical section, what's the problem? The implication here is that OCaml is slow or inefficient. OCaml is often orders of magnitude faster than other high-level languages (e.g. Python). Arrays in OCaml can result in some very fast code.
That is because they are generic most of the time.
This is also fun when using `#trace`in the REPL and all you see is `<poly>` instead of the "real" value
* intent of the author not clear
* auto-complete etc. doesn't work as well
* type errors not caught as early (for generics this means you get super confusing type errors)
Obviously some functions are intended to be generic (e.g. operations on containers) but typical OCaml code seems to contain functions that are actually only called with one type - and the author only intended for them to be called with one type - yet they get inferred as generic.
Oh yes, I'm not arguing against that or your other points. I just wanted to express that the types being inferred as generic is not an error, but by design.