I like OCaml and have written the "why we chose XYZ language" posts. Most of the time the real answer is "we like it and it makes us feel good to use it". Like the answers aren't wrong per se but they're more post-facto justifications. And that's perfectly fine! I think we should normalize saying that tech stack choices are subjective and preference-based. We're not robots. The social and aesthetic parts of a stack matter to people
Definitely agree. Most teams don't choose a language for purely rational reasons, and we're not pretending we did.
We like OCaml, it makes us excited to build. We know the language deeply, which means we can reason about performance and behavior before we run the code. We can onboard new engineers quickly because the type system forces clarity.
The runtime is simple enough that we can predict what it's doing. So yes, part of it is that OCaml feels good to use. But that feeling comes from years of watching it make complex systems simpler to reason about, not harder.
Exactly! OCaml is the language I like to solve problems in, and I'm excited to solve problems in, so that's why Terrateam uses OCaml (I'm the CTO). You can do a lot (but not all) of this in Go, or TypeScript, but I don't get excited about those languages. Certainly I'll use them if I have to (our UI is written in Svelte) but building your own company is a grind, and using OCaml makes the grind just a bit more exciting, and that's an edge.
Industry is just starting to come around to it, but I've never been more happy programming than when using a strongly-typed language with sum types. What most people fail to understand is that fighting the type checker is almost always a feature, not a bug. It is training you to write code in a way that it understands, which forces your thinking to be less sloppy, even on non-happy paths.
Sum types enable much higher levels of expressivity of what valid states are while still being statically analyzable. Any new PL lacking them, IMO, is making a huge unforced error. They don't apply for every situation, but they do handle a large amount of day-to-day programming concerns.
Side note: OO is oft-maligned in OCaml, but I really appreciate that they included it anyway. I much prefer languages that give you a set of tools to use in whatever situation you find yourself in.
I've used a lot of Rust and Haskell over the past few years (I consider OCaml to be similar), and I think the benefits go beyond just user preference. But I think it's something that requires experience with "must not fail" systems failing in production, and then seeing how these languages make that failure impossible. The level of freedom and confidence that brings is amazing. And yes, that also makes them more fun to use.
I think that in some cases where OCaml was chosen, like Docker or some parsers, the choice was obviously not evangelical. But I agree that in most cases it is a post-facto justification.
One of the great understated reasons for using 'cool' programming languages is that it allows a business to hire selectively for people for whom programming is a passion.
Joy is probably an improvement on slog, but one person's joy is another's hell. I've inherited a lot of joyful projects that were an awful fit for continued maintenance because joyful meant using new, unproven, and unstable technologies.
I have experienced many identical situations. Some people just love to tinker and over-engineer for the sake of stretching a muscle. It's unfortunate when that sneaks into a prod system that has to be maintained by others.
> I think we should normalize saying that tech stack choices are subjective and preference-based. We're not robots. The social and aesthetic parts of a stack matter to people
I would just like to distinguish "subjective and preference-based" from "social and aesthetic" and also clarify some notions.
1. The social is objective. We are social animals. It is essential to what it means to be human. We need social relations to grow and develop and to become more human.
2. The aesthetic is objective. We confuse taste with beauty, and this is perhaps the legacy of influence of certain philosophical traditions on our thinking. Beauty has to do with the fullness with which some thing instantiates a form and realizes some end/good. So, when it comes to artifacts like programming languages, a beautiful language will satisfy some human purpose more perfectly than a less beautiful language. Taste is a matter of subjective disposition to beauty. Someone with bad or poor taste might prefer the inferior over the superior, for example, or fail to discern between the two.
We sort of create mystery about preference here, as if they were just arbitrary, immutable, inexplicable brute facts. But preferences can be more good or less good or even bad. Note the relation between preference and taste.
> We're not robots.
3. Typically - and I do not accuse you of this - this is meant to mean that what makes us human compared to robots is that we have emotions. But it isn't that. Many animals have emotions. What makes us distinct as human beings is the intellectual and the rational, which robots (as computational instruments) are not.
4. Post hoc rationalizations may not stand behind the actual motivations, but the content of the rationalization may remain true and valid nonetheless.
I’m sorry but there is no way you can demonstrate a universal aesthetic. Your opinion of other people’s tastes does not reflect on their taste — it reflects on yours.
This is pretty much obvious for people migrated from JavaScript to TypeScript and suddenly realised that most of their unit tests can now go to a trash bin.
I have worked with Haskell, Scala, and OCaml; they all bring the joy of programming into daily tasks, and OCaml has a fast compiler and a great module system. This makes it a really fun and effective language to use.
Scala just seems to have an ever changing identity. Scala 3 drastically changed syntax and now they're trying to move the language from monads to effects.
We're still figuring out what balance makes sense between openness and sustainability, and we'd rather take the time to get it right than rush into a license we'll regret later. The goal is for Stategraph to last a long time.
> Most systems handle this defensively with locks and runtime validation.
So i work at an org with 1000s of terraform repos, we use the enterprise version which locks workspaces during runs etc.
everywhere else i’ve worked, we either just use some lock mechanism or only do applies from a specific branch and CI enforces they run one at a time.
My question is: who is this aimed at and what problem is it actually solving? Running terraform isn’t difficult - thousands of orgs handle it no problem - the issues I have with it with it have never been around lock contention and race conditions..
Hello, CTO of Terrateam here, the creators of Stategraph.
As you said, the common practice is to use locks on state to guarantee that operations don't step on each other. This works, however the cost is that if it takes 5 minutes to perform an operation, only one person can be doing an operation at a time, so if 5 devs are modifying infrastructure, the last one has to wait 25 minutes just to get back the plan, even if those 5 people are not changing overlapping resources in the state.
The way that most people deal with this is they take their infrastructure and break it up across multiple root modules, and then when those root modules, break it up again, etc.
Stategraph is solving the problem of getting all of the performance benefits of breaking up your root modules without breaking up your root modules. It dynamically determines which resources each of those 5 devs are operation on and, if the resources do not overlap, can run them in parallel.
That means Stategraph is manipulating state in a bit more sophisticated way than standard Terraform/Tofu, and we need to be careful we don't get it wrong.
Back in the day, before git, we had RCS. Developers would just lock files when they worked on them, and then unlock when they were done. Or you'd copy a folder manually ("branch") to work on things concurrently and then punch them in the shoulder when they forgot to unlock master so that you could lock it and check in. It worked absolutely fine, there were loads of workarounds!
> The concurrent applies isn’t that big of a deal?
That depends. There are many organizations (we talk to them) which have plans and applies that take 5 - 10s of minutes, some even close to an hour. That's a problem. We talked to one customer that a dev can make a change in the morning and depending on the week might have to wait until the next day to get their plan, and then another day to apply it, assuming there are no issues.
If you're in that position you have two options:
1. Just accept it and wait.
2. Refactor your root module to independent root modules.
(2) is what a lot of people do, but it's not cheap, that's a whole project. It's also a workflow change.
Stategraph is trying to offer a third option: if your changes don't overlap, each dev can run independently with no contention.
Even if one doesn't think contention over state is a big deal, I hope that one can agree that a solution that just removes that contention at very little cost is worth considering.
> There are many organizations (we talk to them) which have plans and applies that take 5 - 10s of minutes, some even close to an hour. That's a problem. We talked to one customer that a dev can make a change in the morning and depending on the week might have to wait until the next day to get their plan, and then another day to apply it
That's us. Especially because our teams are distributed across NA/Eastern Europe/Japan. So getting a lock is a problem because you have to wait for someone else to finish, then getting the required reviews is a problem because you have to wait for people from other timezones to come on, then by the time you're ready to re-plan after the reviews someone else has taken the lock, then you have to wait for them,...
Sorry for the large aside, but anyone knows the whereabouts of the Flambda2 project? Can't find the GH repo anymore, only this fork I didn't know about: https://github.com/oxcaml/oxcaml/
That's the repo, Jane Street has rebranded their OCaml fork to OxCaml (as in oxidised, Rust-like). From the readme:
> This is also the home of the Flambda 2 optimiser
Their plan is to use OxCaml as their experimental fork and work with upstream to port features from it. Labelled tuples and immutable arrays for example landed in OCaml 5.4 but were originally from OxCaml.
>One operation can't corrupt another operation's view of state because state is immutable by default.
How true is this in practice? I mean on the one hand sure Operation 2 doesn't seem some half modified state from Operation 1. On the other hand Operation 2 now has some stale state and makes the wrong decisions does the wrong thing because it didn't see Operation 1's changes.
That happens whether immutable or not. In the mutable world, you have to guard that using a mutex or something. In that case, operation 1 may be blocked by operation 2, and now you get a "stale" state from operation 2. But that's okay. You'll get a new state next time. The real problem occurs when two states are mixed and corrupted.
My concern for a team language choice is "How hard is going to be be hire people to write in this language effectively and how much will /they/ enjoy it?"
It's one thing to pick a language that I like and am productive in, it's another to choose a language for a larger team.
If you've found an full team of motivated and capable OCaml coders, great.
It has not been a challenging finding candidates for OCaml. For the most part, people who like OCaml are chomping at the bit to find a job writing it. And for those that don't know OCaml, a lot of really good devs are excited to try something different.
I don't really get what's special about OCaml with these points they raise? Wouldn't almost any strongly typed language do? Wouldn't TypeScript also tick all these boxes?
EDIT: I wouldn't choose TypeScript either for this type of use case, but not for the reasons they state, that's my point
Typescript (javascript) is kind of a joke compared to what ocaml brings to the table.
Ocaml has a top in class typesystem, a "faster than Go" compiler and (in 2025) good tooling. It allows you to say fuck it and write a while loop if you need to. Hell you can even do OOP. Also it has an incredible module system and full type inference. It also has an effect system, and good concurrency features (ocaml 5).
I cant say many other languages that has all the same features.
It's the combination with concurrency that makes this a hard problem.
And OCaml excels at solving that sort of problem. OCaml and Erlang are the only two languages that I'm aware of that have a really clean way of doing this, in most other languages there is always some kind of kludge or hack to make it work and at best you're going to do something probabilistic: it seems to work, even under load, so it probably is good now. Until six weeks later on an idle Tuesday the system deadlocks and you have no idea how it happened.
What advantage does OCaml have over Haskell here? I find software transactional memory in Haskell so simple to work with that I have lost all fear of concurrency, but what am I missing out on?
I personally find OCaml more pragmatic than Haskell.
Haskell has a steeper learning curve IMHO: monads are pervasive and are hard to understand, laziness isn't a common programming pattern and it adds complexity. I find type classes confusing as well, it's not always clear where things are defined.
I like that OCaml is close to the hardware, there are no complex abstractions. The module system makes it easy to program in the large (I love mli). If you avoid the more advanced features, it's a super simple language.
Its mostly about practicality. Haskell is kind of pain when you need IO, as in when you go there there is no way out.
Ocaml is more practical, and less punishing (you can do IO without monads), but the most important diffrence is performance. Haskell is VERY hard to make predictable because its lazy. Ocaml is strict so general system performance is much easier to predict.
But they are sibling languages in my book, while i still prefer ocaml over haskell.
Also IMO the dev tooling is better for OCaml. Far better compile times.
A big part of interacting with APIs (which I imagine Stategraph does) is just dealing with records, and working with records in Haskell is really annoying unless you bring in lenses which bring a lot of complexity.
Besides the better type system, OCaml is a compiled language, you don't need workarounds like rewriting code in Rust and Go, as it happens on TypeScript/JavaScript world.
Certainly there are specifics between the type systems that differentiate. TypeScript generally chooses to enforce types in an ergonomic way whereas OCaml chooses to enforce types in a sound way. Whether or not that is a meaningful differentiator for someone is up to them.
This blog post shows the elements of OCaml that motivate us to use it. Is it complete? No. Maybe it should be more explicit that we like using OCaml, and these technical aspects aren't unique but certainly benefits we see.
TypeScript does not have an equivalent to PPX infrastructure AFAIK. If there is, it's definitely not as widely used within the ecosystem compared to PPX for OCaml.
Functional programming is immutable by default. TypeScript and many other typed languages don't really stop you from clobbering things, particularly with concurrency. Rust does. But immutability with GC is a lot easier to use than Rust if you don't need the performance of Rust.
That is only true since people started equating FP with Haskell.
OCaml as the discussion subject on this thread, allows for mutable data structures, and I am old enough to have been taught Lisp as one possible avenue for FP.
But what is functional besides haskell? Purescript? Elm I guess. Ocaml is not. It has for loops even. You can write pure functional ocaml but people don't. It mattered a lot less when it didn't have true concurrency, but now clobbering things in ocaml is quite possible.
My point was that without any escape hatches or magic you can code a segfault starting in ocaml5. That may be true of haskell? It is true of rust too, though the only known way to do it isn't something that is likely to happen by accident and is tracked as a bug. In ocaml5 if you use domain, it is down to experience skill, and some luck to be sure you used atomic when necessary. I'm a bad programmer despite going on four decades of experience. I'm not even remotely methodical. If I adopt ocaml for a project I'm using 4 or adding something that fails the pipeline if it finds domain anywhere.
It shouldn't, the OCaml 5 memory model bounds the reach of data races in both space and time. [1] Thread-unsafe code won't be correct when misused, but it will stay memory safe unless you reach for an additional escape hatch (or you find an implementation bug of course).
You are right! As of 5.1.1 at least it catches the cross domain access I was using to smash things. From what I am reading it sounds like it didn't work in 5.1 I could go try it in godbolt to find out when it was fixed, but I kind of don't care. Very exciting, I like ocaml and was lamenting the changes.
That makes a lot more sense: The earliest 5.x releases weren't stable at all despite the non-prerelease version numbers. I waited for longer than I wanted to before upgrading from the LTS to 5, but right now it should be ok to switch as long as the few regressions, like the GC pacing issue, don't affect you workload.
Pure functional programming languages do not allow mutable state. They can simulate it with monads, and they typically have impurities to allow io sode effects, but a for loop is an inherently imperative construct. Mostly functional languages like ocaml have things like ref. Functional languages aren't just about functions being composable and having no side effects, they also require that once a value is bound to a name, that it does not change. That isn't just pedantry either, it is what allows safe concurrency by default.
Ocaml is immutable. It has ref if you need mutation, this is not the default thing you grab tho. Haskell has unsafe and IORef, that does basically the same thing. Scala, rust etc has all escape hatches.
A loop by itself is not non-fp, as i can do the exact same thing via recursion. Its just syntax.
Hell, i can write a never halting program in lambda calculus with a fixed point combinator causing "undefined behaviour".
OCaml has a much stronger type system than Typescript.
The real question is "why not Rust?". I've used both a fair bit and OCaml's only major advantage IMO is compile time. That doesn't seem compelling enough to put up with the downsides to me.
I'm the CTO of Terrateam. For "why not rust", I have found the downsides of Rust not compelling enough to use it. We don't need close-to-metal performance. We don't really need the borrow checker, a GC is fine. We are immutable by default so the borrow checker doesn't help much there.
Great choice by way, I feel too many reach out for Rust, because they lack the perspective ML type systems are not something introduced by Rust, rather a long linage of languages since ML/Standard ML.
Plus, OCaml kept the SML tradition in its robust module system, with modules as first-class citizens and ML-style functors, this is something hard to see nowadays, even among ML-inspired languages.
The sense I get from some comments is that if you need a type system and to compile to an executable, Rust is the only option, otherwise you can use pretty much anything. But, as you say, MLs have been compiling to binaries for decades. One of the first online books on OCaml is for systems programming.
I know that isn't everyone's view, but I do hope posts like this, even if not technicaly deep, at least let people know that there are lots of options out there.
I don’t like OCaml myself, but I’d pick it over rust here as bare metal perf is not necessary, and time wasting fighting the borrow checker is just not worth it.
It is worth it in my opinion because it's mostly a one-time cost (learning how it works and what is allowed), and in return you get less buggy program structures (it basically forces you not to write spaghetti code). Also you have to worry about it much less if you don't need 100% performance and are happy to clone everything.
Occasionally I do still fight it, e.g. if you want a self-borrowing structure there still isn't a great solution (I think Rust should support position independent borrows) but overall it's fine.
Answer is easy, not everyone needs the performance boost provided by borrow checker, 99% of the time some kind of automatic resource management is good enough.
I wrote the OCamlByExample and I can only say, good luck, I don't think OCaml is ready for production, and it's generally not a very user-friendly language, but IMO it's all about having fun first and if this is what makes it fun for you guys then you should do it!
Also with LLMs it's probably easier to just feed the compiler errors to an LLM and get something readable at the end.
Those two type systems are not the same. Typescript has some soundness issues in the type system. They are there because they have to work seamless with javascript so it's understandable. And they improve many codebases that would have been otherwise written in javascript. But they do not in any way give you the same level of guarantees that OCaml, Haskell, or Rust would give you.
There are many languages that fit these requirements. I don't get the purpose of writing these posts besides a reason to go viral and get clicks talking about your product.
I write OCaml myself, but not for $paid job, it's okay, it's a fine language although with cruft, but it's not the panacea described here.
I like OCaml and have written the "why we chose XYZ language" posts. Most of the time the real answer is "we like it and it makes us feel good to use it". Like the answers aren't wrong per se but they're more post-facto justifications. And that's perfectly fine! I think we should normalize saying that tech stack choices are subjective and preference-based. We're not robots. The social and aesthetic parts of a stack matter to people
Definitely agree. Most teams don't choose a language for purely rational reasons, and we're not pretending we did.
We like OCaml, it makes us excited to build. We know the language deeply, which means we can reason about performance and behavior before we run the code. We can onboard new engineers quickly because the type system forces clarity.
The runtime is simple enough that we can predict what it's doing. So yes, part of it is that OCaml feels good to use. But that feeling comes from years of watching it make complex systems simpler to reason about, not harder.
The first comments here are people reading this as if the authors are saying only OCaml can do this. They aren't.
Exactly! OCaml is the language I like to solve problems in, and I'm excited to solve problems in, so that's why Terrateam uses OCaml (I'm the CTO). You can do a lot (but not all) of this in Go, or TypeScript, but I don't get excited about those languages. Certainly I'll use them if I have to (our UI is written in Svelte) but building your own company is a grind, and using OCaml makes the grind just a bit more exciting, and that's an edge.
Industry is just starting to come around to it, but I've never been more happy programming than when using a strongly-typed language with sum types. What most people fail to understand is that fighting the type checker is almost always a feature, not a bug. It is training you to write code in a way that it understands, which forces your thinking to be less sloppy, even on non-happy paths.
Sum types enable much higher levels of expressivity of what valid states are while still being statically analyzable. Any new PL lacking them, IMO, is making a huge unforced error. They don't apply for every situation, but they do handle a large amount of day-to-day programming concerns.
Side note: OO is oft-maligned in OCaml, but I really appreciate that they included it anyway. I much prefer languages that give you a set of tools to use in whatever situation you find yourself in.
I've used a lot of Rust and Haskell over the past few years (I consider OCaml to be similar), and I think the benefits go beyond just user preference. But I think it's something that requires experience with "must not fail" systems failing in production, and then seeing how these languages make that failure impossible. The level of freedom and confidence that brings is amazing. And yes, that also makes them more fun to use.
I think that in some cases where OCaml was chosen, like Docker or some parsers, the choice was obviously not evangelical. But I agree that in most cases it is a post-facto justification.
One of the great understated reasons for using 'cool' programming languages is that it allows a business to hire selectively for people for whom programming is a passion.
Using something you enjoy is fine, as long as you don’t forget the person who is going to maintain your code after you move on.
Imagine inheriting a project that was a joy for someone to work on instead of a slog.
Joy is probably an improvement on slog, but one person's joy is another's hell. I've inherited a lot of joyful projects that were an awful fit for continued maintenance because joyful meant using new, unproven, and unstable technologies.
I have experienced many identical situations. Some people just love to tinker and over-engineer for the sake of stretching a muscle. It's unfortunate when that sneaks into a prod system that has to be maintained by others.
> I think we should normalize saying that tech stack choices are subjective and preference-based. We're not robots. The social and aesthetic parts of a stack matter to people
I would just like to distinguish "subjective and preference-based" from "social and aesthetic" and also clarify some notions.
1. The social is objective. We are social animals. It is essential to what it means to be human. We need social relations to grow and develop and to become more human.
2. The aesthetic is objective. We confuse taste with beauty, and this is perhaps the legacy of influence of certain philosophical traditions on our thinking. Beauty has to do with the fullness with which some thing instantiates a form and realizes some end/good. So, when it comes to artifacts like programming languages, a beautiful language will satisfy some human purpose more perfectly than a less beautiful language. Taste is a matter of subjective disposition to beauty. Someone with bad or poor taste might prefer the inferior over the superior, for example, or fail to discern between the two.
We sort of create mystery about preference here, as if they were just arbitrary, immutable, inexplicable brute facts. But preferences can be more good or less good or even bad. Note the relation between preference and taste.
> We're not robots.
3. Typically - and I do not accuse you of this - this is meant to mean that what makes us human compared to robots is that we have emotions. But it isn't that. Many animals have emotions. What makes us distinct as human beings is the intellectual and the rational, which robots (as computational instruments) are not.
4. Post hoc rationalizations may not stand behind the actual motivations, but the content of the rationalization may remain true and valid nonetheless.
I’m sorry but there is no way you can demonstrate a universal aesthetic. Your opinion of other people’s tastes does not reflect on their taste — it reflects on yours.
TIL (via a rabbit hole after reading this) that a good type system removes an absurd amount of boilerplate validation code.
This is pretty much obvious for people migrated from JavaScript to TypeScript and suddenly realised that most of their unit tests can now go to a trash bin.
Do you have any good resources on this subject? I agree and would like to see what a persuasive argument for it looks like.
The very classic parse don't valide if you haven't already read it : https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va...
I have worked with Haskell, Scala, and OCaml; they all bring the joy of programming into daily tasks, and OCaml has a fast compiler and a great module system. This makes it a really fun and effective language to use.
Scala has some quirks but I enjoyed it relative to more popular languages and its apparent stagnation makes me sad.
Scala just seems to have an ever changing identity. Scala 3 drastically changed syntax and now they're trying to move the language from monads to effects.
I hope for the team to settle with a FLOSS license, so it becomes feasible to evaluate for everyone.
We're still figuring out what balance makes sense between openness and sustainability, and we'd rather take the time to get it right than rush into a license we'll regret later. The goal is for Stategraph to last a long time.
Best of luck. Hoping for AGPL :-)
> Most systems handle this defensively with locks and runtime validation.
So i work at an org with 1000s of terraform repos, we use the enterprise version which locks workspaces during runs etc.
everywhere else i’ve worked, we either just use some lock mechanism or only do applies from a specific branch and CI enforces they run one at a time.
My question is: who is this aimed at and what problem is it actually solving? Running terraform isn’t difficult - thousands of orgs handle it no problem - the issues I have with it with it have never been around lock contention and race conditions..
Hello, CTO of Terrateam here, the creators of Stategraph.
As you said, the common practice is to use locks on state to guarantee that operations don't step on each other. This works, however the cost is that if it takes 5 minutes to perform an operation, only one person can be doing an operation at a time, so if 5 devs are modifying infrastructure, the last one has to wait 25 minutes just to get back the plan, even if those 5 people are not changing overlapping resources in the state.
The way that most people deal with this is they take their infrastructure and break it up across multiple root modules, and then when those root modules, break it up again, etc.
Stategraph is solving the problem of getting all of the performance benefits of breaking up your root modules without breaking up your root modules. It dynamically determines which resources each of those 5 devs are operation on and, if the resources do not overlap, can run them in parallel.
That means Stategraph is manipulating state in a bit more sophisticated way than standard Terraform/Tofu, and we need to be careful we don't get it wrong.
Back in the day, before git, we had RCS. Developers would just lock files when they worked on them, and then unlock when they were done. Or you'd copy a folder manually ("branch") to work on things concurrently and then punch them in the shoulder when they forgot to unlock master so that you could lock it and check in. It worked absolutely fine, there were loads of workarounds!
Yeah I get the sense that terraform change application is solved by just serializing all changes? The concurrent applies isn’t that big of a deal?
> The concurrent applies isn’t that big of a deal?
That depends. There are many organizations (we talk to them) which have plans and applies that take 5 - 10s of minutes, some even close to an hour. That's a problem. We talked to one customer that a dev can make a change in the morning and depending on the week might have to wait until the next day to get their plan, and then another day to apply it, assuming there are no issues.
If you're in that position you have two options:
1. Just accept it and wait. 2. Refactor your root module to independent root modules.
(2) is what a lot of people do, but it's not cheap, that's a whole project. It's also a workflow change.
Stategraph is trying to offer a third option: if your changes don't overlap, each dev can run independently with no contention.
Even if one doesn't think contention over state is a big deal, I hope that one can agree that a solution that just removes that contention at very little cost is worth considering.
> There are many organizations (we talk to them) which have plans and applies that take 5 - 10s of minutes, some even close to an hour. That's a problem. We talked to one customer that a dev can make a change in the morning and depending on the week might have to wait until the next day to get their plan, and then another day to apply it
That's us. Especially because our teams are distributed across NA/Eastern Europe/Japan. So getting a lock is a problem because you have to wait for someone else to finish, then getting the required reviews is a problem because you have to wait for people from other timezones to come on, then by the time you're ready to re-plan after the reviews someone else has taken the lock, then you have to wait for them,...
If there was a time to insert a Jobs "you're holding it wrong" I think it would be here...
Agreed and well said!
Sorry for the large aside, but anyone knows the whereabouts of the Flambda2 project? Can't find the GH repo anymore, only this fork I didn't know about: https://github.com/oxcaml/oxcaml/
That's the repo, Jane Street has rebranded their OCaml fork to OxCaml (as in oxidised, Rust-like). From the readme:
> This is also the home of the Flambda 2 optimiser
Their plan is to use OxCaml as their experimental fork and work with upstream to port features from it. Labelled tuples and immutable arrays for example landed in OCaml 5.4 but were originally from OxCaml.
>One operation can't corrupt another operation's view of state because state is immutable by default.
How true is this in practice? I mean on the one hand sure Operation 2 doesn't seem some half modified state from Operation 1. On the other hand Operation 2 now has some stale state and makes the wrong decisions does the wrong thing because it didn't see Operation 1's changes.
That happens whether immutable or not. In the mutable world, you have to guard that using a mutex or something. In that case, operation 1 may be blocked by operation 2, and now you get a "stale" state from operation 2. But that's okay. You'll get a new state next time. The real problem occurs when two states are mixed and corrupted.
My concern for a team language choice is "How hard is going to be be hire people to write in this language effectively and how much will /they/ enjoy it?"
It's one thing to pick a language that I like and am productive in, it's another to choose a language for a larger team.
If you've found an full team of motivated and capable OCaml coders, great.
It has not been a challenging finding candidates for OCaml. For the most part, people who like OCaml are chomping at the bit to find a job writing it. And for those that don't know OCaml, a lot of really good devs are excited to try something different.
nicely designed site - welcome change from dark background, gradient colors etc.
just white, grey & blue.
I don't really get what's special about OCaml with these points they raise? Wouldn't almost any strongly typed language do? Wouldn't TypeScript also tick all these boxes?
EDIT: I wouldn't choose TypeScript either for this type of use case, but not for the reasons they state, that's my point
Typescript (javascript) is kind of a joke compared to what ocaml brings to the table.
Ocaml has a top in class typesystem, a "faster than Go" compiler and (in 2025) good tooling. It allows you to say fuck it and write a while loop if you need to. Hell you can even do OOP. Also it has an incredible module system and full type inference. It also has an effect system, and good concurrency features (ocaml 5).
I cant say many other languages that has all the same features.
It's the combination with concurrency that makes this a hard problem.
And OCaml excels at solving that sort of problem. OCaml and Erlang are the only two languages that I'm aware of that have a really clean way of doing this, in most other languages there is always some kind of kludge or hack to make it work and at best you're going to do something probabilistic: it seems to work, even under load, so it probably is good now. Until six weeks later on an idle Tuesday the system deadlocks and you have no idea how it happened.
What advantage does OCaml have over Haskell here? I find software transactional memory in Haskell so simple to work with that I have lost all fear of concurrency, but what am I missing out on?
I personally find OCaml more pragmatic than Haskell.
Haskell has a steeper learning curve IMHO: monads are pervasive and are hard to understand, laziness isn't a common programming pattern and it adds complexity. I find type classes confusing as well, it's not always clear where things are defined.
I like that OCaml is close to the hardware, there are no complex abstractions. The module system makes it easy to program in the large (I love mli). If you avoid the more advanced features, it's a super simple language.
Its mostly about practicality. Haskell is kind of pain when you need IO, as in when you go there there is no way out.
Ocaml is more practical, and less punishing (you can do IO without monads), but the most important diffrence is performance. Haskell is VERY hard to make predictable because its lazy. Ocaml is strict so general system performance is much easier to predict.
But they are sibling languages in my book, while i still prefer ocaml over haskell.
Also IMO the dev tooling is better for OCaml. Far better compile times.
A big part of interacting with APIs (which I imagine Stategraph does) is just dealing with records, and working with records in Haskell is really annoying unless you bring in lenses which bring a lot of complexity.
Tooling was kind of bad previously. But dune has got really good. I like the new dune developer preview thing that is still in beta.
https://preview.dune.build/
Besides the better type system, OCaml is a compiled language, you don't need workarounds like rewriting code in Rust and Go, as it happens on TypeScript/JavaScript world.
Certainly there are specifics between the type systems that differentiate. TypeScript generally chooses to enforce types in an ergonomic way whereas OCaml chooses to enforce types in a sound way. Whether or not that is a meaningful differentiator for someone is up to them.
This blog post shows the elements of OCaml that motivate us to use it. Is it complete? No. Maybe it should be more explicit that we like using OCaml, and these technical aspects aren't unique but certainly benefits we see.
• Stategraph manages Terraform state, so correctness isn't optional
TypeScript has soundness issues that OCaml does not have
• Strongly-typed data structures catch field errors at compile time
TypeScript does have this, although the guarantees are in practice weaker since libraries may have incorrect type definitions
• Type-safe SQL queries prevent schema drift before deployment
There are TypeScript libraries that offer this, so fair point!
• Immutability by default eliminates race conditions
TypeScript is not immutable by default
• PPX generates correct JSON serialization automatically
TypeScript does not have an equivalent to PPX infrastructure AFAIK. If there is, it's definitely not as widely used within the ecosystem compared to PPX for OCaml.
Edit: Downvoters care to respond?
Functional programming is immutable by default. TypeScript and many other typed languages don't really stop you from clobbering things, particularly with concurrency. Rust does. But immutability with GC is a lot easier to use than Rust if you don't need the performance of Rust.
That is only true since people started equating FP with Haskell.
OCaml as the discussion subject on this thread, allows for mutable data structures, and I am old enough to have been taught Lisp as one possible avenue for FP.
But what is functional besides haskell? Purescript? Elm I guess. Ocaml is not. It has for loops even. You can write pure functional ocaml but people don't. It mattered a lot less when it didn't have true concurrency, but now clobbering things in ocaml is quite possible.
Define functional?
Even Haskell is not functional in the strictest sense. It has unsafe IO. It can throw exceptions. Functions may not halt.
Fair. Agda, gallina, f* maybe?
My point was that without any escape hatches or magic you can code a segfault starting in ocaml5. That may be true of haskell? It is true of rust too, though the only known way to do it isn't something that is likely to happen by accident and is tracked as a bug. In ocaml5 if you use domain, it is down to experience skill, and some luck to be sure you used atomic when necessary. I'm a bad programmer despite going on four decades of experience. I'm not even remotely methodical. If I adopt ocaml for a project I'm using 4 or adding something that fails the pipeline if it finds domain anywhere.
> you can code a segfault starting in ocaml5
It shouldn't, the OCaml 5 memory model bounds the reach of data races in both space and time. [1] Thread-unsafe code won't be correct when misused, but it will stay memory safe unless you reach for an additional escape hatch (or you find an implementation bug of course).
[1]: https://ocaml.org/manual/5.4/memorymodel.html
I'm much more concerned about the amount of poorly vetted escape hatches in wide use in OCaml, mainly for bindings.
You are right! As of 5.1.1 at least it catches the cross domain access I was using to smash things. From what I am reading it sounds like it didn't work in 5.1 I could go try it in godbolt to find out when it was fixed, but I kind of don't care. Very exciting, I like ocaml and was lamenting the changes.
That makes a lot more sense: The earliest 5.x releases weren't stable at all despite the non-prerelease version numbers. I waited for longer than I wanted to before upgrading from the LTS to 5, but right now it should be ok to switch as long as the few regressions, like the GC pacing issue, don't affect you workload.
Shouldn't most application programmers in OCaml be reaching for EIO or some other well-tested abstraction?
When there was no true concurrency, only preemption, eio was safe. Not now, you can still clobber things.
Edit: i was wrong! Since at least 5.1 it catches the cross domain access and errors gracefully.
Eio didn't exist before multicore OCaml actually, it was designed for it.
FP has nothing to do with mutability. You seem to lack a basic understanding what the common FP languages are, and what FP actully is.
Pure functional programming languages do not allow mutable state. They can simulate it with monads, and they typically have impurities to allow io sode effects, but a for loop is an inherently imperative construct. Mostly functional languages like ocaml have things like ref. Functional languages aren't just about functions being composable and having no side effects, they also require that once a value is bound to a name, that it does not change. That isn't just pedantry either, it is what allows safe concurrency by default.
Ocaml is immutable. It has ref if you need mutation, this is not the default thing you grab tho. Haskell has unsafe and IORef, that does basically the same thing. Scala, rust etc has all escape hatches.
A loop by itself is not non-fp, as i can do the exact same thing via recursion. Its just syntax.
Hell, i can write a never halting program in lambda calculus with a fixed point combinator causing "undefined behaviour".
StandardML (standard metalanguage), scheme?
Doesn't scheme have a set macro? I think for purity you'd have to go to something used for proofs that doesn't actually interact with the world.
OCaml has a much stronger type system than Typescript.
The real question is "why not Rust?". I've used both a fair bit and OCaml's only major advantage IMO is compile time. That doesn't seem compelling enough to put up with the downsides to me.
I'm the CTO of Terrateam. For "why not rust", I have found the downsides of Rust not compelling enough to use it. We don't need close-to-metal performance. We don't really need the borrow checker, a GC is fine. We are immutable by default so the borrow checker doesn't help much there.
Great choice by way, I feel too many reach out for Rust, because they lack the perspective ML type systems are not something introduced by Rust, rather a long linage of languages since ML/Standard ML.
Plus, OCaml kept the SML tradition in its robust module system, with modules as first-class citizens and ML-style functors, this is something hard to see nowadays, even among ML-inspired languages.
The sense I get from some comments is that if you need a type system and to compile to an executable, Rust is the only option, otherwise you can use pretty much anything. But, as you say, MLs have been compiling to binaries for decades. One of the first online books on OCaml is for systems programming.
I know that isn't everyone's view, but I do hope posts like this, even if not technicaly deep, at least let people know that there are lots of options out there.
I don’t like OCaml myself, but I’d pick it over rust here as bare metal perf is not necessary, and time wasting fighting the borrow checker is just not worth it.
It is worth it in my opinion because it's mostly a one-time cost (learning how it works and what is allowed), and in return you get less buggy program structures (it basically forces you not to write spaghetti code). Also you have to worry about it much less if you don't need 100% performance and are happy to clone everything.
Occasionally I do still fight it, e.g. if you want a self-borrowing structure there still isn't a great solution (I think Rust should support position independent borrows) but overall it's fine.
Ocaml has a garbage collector. It's less of a struggle than Rust.
Answer is easy, not everyone needs the performance boost provided by borrow checker, 99% of the time some kind of automatic resource management is good enough.
Rust has too many footguns. Ocaml is usually more safe.
Rust is a pain
I wrote the OCamlByExample and I can only say, good luck, I don't think OCaml is ready for production, and it's generally not a very user-friendly language, but IMO it's all about having fun first and if this is what makes it fun for you guys then you should do it!
Also with LLMs it's probably easier to just feed the compiler errors to an LLM and get something readable at the end.
Everyone makes mistakes, it's good to admit them.
Is any of this OCaml specific? You can check all boxes with TypeScript.
Those two type systems are not the same. Typescript has some soundness issues in the type system. They are there because they have to work seamless with javascript so it's understandable. And they improve many codebases that would have been otherwise written in javascript. But they do not in any way give you the same level of guarantees that OCaml, Haskell, or Rust would give you.
For all practical purposes I believe it does the same thing.
If you are choosing ocaml they most definitely do not do the same thing for all practical purposes.
Does TypeScript emit machine code? OCaml gives you this option, if you need it.
Well, TS transpiles to JS which then runs on Node, aka V8, a native JIT compiler. So yes, I guess?
Kind of, given that V8 performance is never going to be as good as AOT compiled language, and JIT needs warmup time.
It is no accident that famous JavaScript tools keep being rewritten into C++, Dart, Go and Rust.
But they say "we use ocaml [because it has types]" not "[because it can emit machine code]"
I would go for Rust if I wanted machine code
It's explained in the OP.
No...no you cant.
There are many languages that fit these requirements. I don't get the purpose of writing these posts besides a reason to go viral and get clicks talking about your product.
I write OCaml myself, but not for $paid job, it's okay, it's a fine language although with cruft, but it's not the panacea described here.