Essential insights from Hacker News discussions

OCaml as my primary language

Here's a summary of the themes discussed in the Hacker News conversation:

OCaml vs. F# Comparison and Language Features

A significant portion of the discussion revolves around comparing OCaml and F#, with users weighing in on their respective strengths, weaknesses, and perceived similarities. The comparison often touches upon specific language features.

  • One of the initial comments states: "If I wanted to program in OCaml, id program in F# instead."
  • The author of the original article acknowledges the comparison: "Yes, F# is a very nice language, however, it seems to me that I am making a somewhat forced comparison between OCaml and F#..."
  • The discussion delves into advanced features like GADTs: "You can hack up GADTs in F# - for example, ... (The other missing features I agree are missing.)" Another user clarifies the limitations: "I've used equality witnesses in F# before, they kinda work but can't match proper GADTs. First you'll need identity conversion methods on the witness, because patterns can't introduce type equalities, then you'll realise you can't refute unreachable branches..."
  • The author explains OCaml's capabilities: "In the specific case of OCaml, this is also possible using indexing and GADTs or polymorphic variants."

Tooling and Ecosystem Maturity

A recurring theme is the state of tooling for OCaml, particularly concerning development environments, debugging, and package management.

  • A user expresses frustration: "OCaml is a great language without great tooling. Desperately needs a good LSP implementation to run breakpoints and other debugging tools on VSCode or other LSP-aware IDEs. I know there ARE tools available but there isn't great support for them and they don't work well."
  • The author of the article acknowledges this: "Indeed, efforts should be made in terms of DAP..., extending the following experimentation:... However, I find the assertion about tooling a bit exaggerated, don't you?"
  • A counterpoint is offered: "?? OCaml has had a completion engine for as long as I can remember (definitely over a decade) and it powers their LSP these days. I do know however that the community focuses mostly on Vim and Emacs."
  • Another user highlights the importance of tooling: "I think LLMs benefit from training examples, static typing, and an LSP implementation more than terseness."
  • There's a strong sentiment that OCaml's tooling is a significant barrier for many: "I abandoned ocaml just because I couldn't get a stepping debugger to work. Can't remember the exact issues but I tried to install in vscode to no avail & I've no interest in emacs."
  • The package manager OPAM receives criticism: "'use opam' is always the answer but in reality its the worst package manager ever. I've never seen so many packages fail to install, so many broken dependencies and miscompilations that resulted in segfaults due to wrong dependencies. I just gave up with Ocaml due to the crappy ecosystem..."
  • However, there's also a defense of the ecosystem: "I have never had issues and been writing OCaml and using opam for years."
  • Future improvements via Dune are mentioned: "There is a lot of work on Dune Package Management that will fix some legacy issues related to OPAM, ... !! Stay tuned!" and the potential for Dune to act as an alternative package manager is discussed.
  • Reproducibility issues with package management are raised: "And even if you do get opam working for a project, it's not at all reproducible and will just randomly break at some point in the future." This is countered with the mention of opam lock and Dune's lockdir feature for reproducible builds.

Sum Types and Type System Expressiveness (OCaml vs. Java/Kotlin/C#)

A substantial part of the conversation is dedicated to a debate about the implementation and utility of sum types, particularly comparing OCaml's approach with sealed classes in languages like Java and C#.

  • The article's point about referring to cases as their own types is scrutinized: "Sum types: For example, Kotlin and Java (and de facto C#) use a construct associated with inheritance relations called sealing. This has the benefit of giving you the ability to refer to a case as its own type."
  • A user argues for the verbosity trade-off: "You declare the sum type once, and use it many times. Slightly more verbose sum type declaration is worth it when it makes using the cases cleaner."
  • This claim is contested: "Correct. This is not the case when you talk about Java/Kotlin. Just ugliness and typical boilerplate heavy approach of JVM languages."
  • The subtlety of the comparison is highlighted: "Kotlin's/Java's implementation is just a poor man's implementation of very restricted set of real sum types."
  • The discussion explores how OCaml can achieve similar results using advanced features: "You can use GADTs... and indexes..." and "You can use the structural nature of polymorphic variants..."
  • A user suggests that Java/C# sealed classes are a form of sum types: "With your shape example, you cannot express in the type system 'this function won't return a point'. But with sum type as sealed inheritance hierarchy I can."
  • This leads to a deeper dive into the nature of sum types and inheritance: "That’s for embedded records. You can have the same thing as Kotlin but with better syntax." and "If you don't do inline records you either ... create a separate record type, which is no less verbose than Java's approach..."
  • The idea that OCaml's approach can be "confusing" is raised, but the counterargument is that confusing parts are additions to the core type system.
  • Sunnydiskincali presents a more philosophical take on sum types and their relation to subtyping and program states, suggesting that OCaml's approach is fundamentally different and allows for better guarantees.
  • The analogy to class hierarchies and the intention behind sealed classes is debated, with the complexity of translating concepts between type systems being noted.

The Role of Functional Programming and Generality

The conversation touches on the benefits and perceived limitations of functional programming paradigms, including the power of OCaml's module system and higher-kinded types (HKTs).

  • The author of the article touches on function types being "exponential types," leading to a discussion on how function types relate to algebraic properties.
  • The expressiveness of OCaml's modules is discussed: "In short, OCaml modules are used for coarse-grained generics." and "In f# there is no HKTs that is types that can be parameterised with type classes. So in F# you have to have List.map, option.map etc, whereas in a language like OCaml or Haskell they would have one parametrised module."
  • The limitations of OCaml's HKTs are noted, but the author points out that modules provide a form of higher-kinded types.
  • The lack of explicit typeclasses in OCaml is mentioned, but ongoing work on proposals for them is highlighted.

OCaml's Syntax and Ergonomics

The syntax of OCaml is a point of contention for some, while others find it elegant.

  • "I feel if OCaml had got its act together around about 2010 with multicore and a few other annoyances[1] it could have been Rust."
  • "Practically speaking, the 31-bit Ints are annoying if you're trying to do any bit bashing, but aesthetically the double semicolons are an abomination and irk me far more."
  • A user finds the syntax alien: "the syntax seems absolutely alien to me. Some attempt to look like verbose imperative code, a bunch of semicolons, and for some strange reason, hate of parenthesis."
  • Others defend it: "That code is probably some of the hardest you'll encounter in Ocaml, but for me its quite obvious what it does and easy to read because I've worked with GADTs before." and "I actually really like the syntax of OCaml, its very easy to write and when you're used to it, easy to read (easier than reasonml IMO)."
  • The role of ReasonML as a syntax alternative and its limited adoption is also discussed.

OCaml vs. Rust

Several users draw comparisons between OCaml and Rust, often highlighting Rust's advantages in terms of ecosystem, tooling, and performance.

  • "I migrated from OCaml to Rust around 2020, haven't looked back. Although Rust is quite a lot less elegant and has some unpleasant deficiencies ..., But regardless, its huge ecosystem and great tooling allows me to build things comparatively so easily, that OCaml has no chance."
  • The benefit of Rust's "no gc but memory safe" has been a significant draw, but it's also noted that many programs don't strictly require this, and Rust's lifetimes can be a source of pain.
  • The core language features of OCaml (like ADTs) are seen as a strong retention factor for some developers, even when they choose Rust for other reasons.
  • The idea that Rust offers "the performance of C, but with memory safety and data race safety" is mentioned as a key initial appeal.

The Impact of LLMs on Programming Languages

A tangential but significant theme is the potential impact of Large Language Models (LLMs) on programming language usage and design.

  • There's speculation that functional languages, with their conciseness, may benefit LLMs due to smaller context windows: "My thought is that if FP languages like OCaml / Haskell / etc. let us compress a lot of information into a small amount of text, then that's better for the context window."
  • Conversely, others believe that verbosity might actually aid LLMs in self-correction.
  • The importance of strong typing and LSP implementations for LLM code generation is also emphasized.
  • The idea of using powerful type and effect systems to constrain LLMs and ensure correctness is proposed.

Community and Corporate Influence

The influence of large corporations on language ecosystems and community dynamics is touched upon.

  • The user who migrated from OCaml to F# notes: "The biggest problem for me was the management of the fsharp community, the second class citizen position of fsharp in the DotNet ecosystem, and Microsoft's action screwing the goodwill of the dev community..."
  • There's a comment suggesting that "a significant minority seem to resent the fact that one company (Jane Street) has written more OCaml than the the rest of the world combined and then some and so de facto controls the ecosystem." This is rebutted with data suggesting Jane Street's direct influence on packages is limited, though they might control the initial learning pipeline.

Other Mentions

  • GADTs: Discussed in the context of F# and OCaml, highlighting their expressiveness and the potential for compiler support.
  • Modules: Praised for coarse-grained generics and parameterization through functors in OCaml, with comparisons to Scala traits.
  • Sum Types vs. Sealed Classes: A debate on whether Java/C#'s sealed classes are equivalent to ML-style sum types, with arguments about expressiveness and type system guarantees.
  • LLMs and Code Generation: Speculation on how LLMs might interact with concise functional code, and the benefits of static typing and LSP for LLM-assisted development.
  • Rust: Frequently mentioned as a benchmark for tooling, ecosystem, and a certain kind of development experience that OCaml is seen by some to be lacking.
  • F#: Positioned as a more accessible alternative to OCaml by some, but with its own ecosystem and tooling criticisms.
  • Syntax: OCaml's syntax (including double semicolons and let...in) is a point of both admiration and criticism.
  • Package Management: OPAM's issues and Dune's development are central to discussions about OCaml's ecosystem maturity.
  • Performance: The underlying performance of OCaml (especially with ocamlopt) and comparisons to Rust are made.
  • Haskell: Mentioned as another functional language with a rich type system, often in parallel with OCaml discussions.
  • Interop: OCaml's C FFI is seen as a limitation compared to Rust's ability to expose a C-like interface.
  • Debugging: A consistent pain point for users attempting to use OCaml in IDEs other than Emacs.
  • Functional Programming Benefits: The inherent benefits of ADTs, pattern matching, and the type system for writing robust code are frequently acknowledged.