[HN Gopher] We chose OCaml to write Stategraph
       ___________________________________________________________________
        
       We chose OCaml to write Stategraph
        
       Author : lawnchair
       Score  : 140 points
       Date   : 2025-11-07 13:10 UTC (9 hours ago)
        
 (HTM) web link (stategraph.dev)
 (TXT) w3m dump (stategraph.dev)
        
       | cyberpunk wrote:
       | > 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..
        
         | ab5tract wrote:
         | Agreed and well said!
        
         | sausagefeet wrote:
         | 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.
        
           | pjd7 wrote:
           | I'm not sure I would want this even if I could have it TBH.
           | Engingeering org size is about ~200 with infra/sre/ops around
           | ~25.
           | 
           | Different teams want to move at difference cadences. At a
           | certain scale splitting up things feels a little more natural
           | (maybe I am stockholmed by prior limitations with TF though
           | or just used to this way of operating now).
           | 
           | But even then, we're moving to k8s operators to orchestrate a
           | bunch of things and moving off terraform apart from the stuff
           | that doesn't change much (which will eventually get retired
           | as well). Something like https://www.youtube.com/watch?v=q_-
           | wnp9wRX0
           | 
           | Terraform variable management is our larger problem
           | (now/nearterm) when we have to deploy numerous cells of infra
           | that use the same project/TF files with different variables.
           | Given the number of projects/layers of TF getting cell
           | specific variables injected is meh.
           | 
           | Those variables are instance size, volume size, addresses,
           | IAM policy, keys etc.
           | 
           | This is in the b2b saas world with over a million MAU. We've
           | got islands of infra for data soverignty, some global cells
           | where each cell can communicate back / host some shared
           | services (internal data analytics, orchestration tooling,
           | internal management tooling and the like).
        
         | leoqa wrote:
         | 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?
        
           | sausagefeet wrote:
           | > 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.
        
             | yawaramin wrote:
             | > 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,...
        
               | cyberpunk wrote:
               | If there was a time to insert a Jobs "you're holding it
               | wrong" I think it would be here...
        
               | yawaramin wrote:
               | They were, in fact, not holding it wrong
        
         | internet_points wrote:
         | 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!
        
       | koakuma-chan wrote:
       | Is any of this OCaml specific? You can check all boxes with
       | TypeScript.
        
         | stefanos82 wrote:
         | Does TypeScript emit machine code? OCaml gives you this option,
         | if you need it.
        
           | procaryote wrote:
           | But they say "we use ocaml [because it has types]" not
           | "[because it can emit machine code]"
        
             | koakuma-chan wrote:
             | I would go for Rust if I wanted machine code
        
           | a-french-anon wrote:
           | Well, TS transpiles to JS which then runs on Node, aka V8, a
           | native JIT compiler. So yes, I guess?
        
             | pjmlp wrote:
             | 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.
        
         | zaphar wrote:
         | 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.
        
           | koakuma-chan wrote:
           | For all practical purposes I believe it does the same thing.
        
             | zaphar wrote:
             | If you are choosing ocaml they most definitely do not do
             | the same thing for all practical purposes.
        
         | phplovesong wrote:
         | No...no you cant.
        
         | yawaramin wrote:
         | It's explained in the OP.
        
       | laszlojamf wrote:
       | 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
        
         | jacquesm wrote:
         | 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.
        
           | internet_points wrote:
           | 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?
        
             | phplovesong wrote:
             | 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.
        
               | myaccountonhn wrote:
               | 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.
        
               | phplovesong wrote:
               | 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/
        
             | yodsanklai wrote:
             | 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.
        
         | gregwebs wrote:
         | 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.
        
           | galangalalgol wrote:
           | 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.
        
             | greener_grass wrote:
             | Define functional?
             | 
             | Even Haskell is not functional in the strictest sense. It
             | has unsafe IO. It can throw exceptions. Functions may not
             | halt.
        
               | galangalalgol wrote:
               | 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.
        
               | greener_grass wrote:
               | Shouldn't most application programmers in OCaml be
               | reaching for EIO or some other well-tested abstraction?
        
               | galangalalgol wrote:
               | 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.
        
               | debugnik wrote:
               | Eio didn't exist before multicore OCaml actually, it was
               | designed for it.
        
               | debugnik wrote:
               | > 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.
        
               | galangalalgol wrote:
               | 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.
        
               | debugnik wrote:
               | 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.
        
             | e12e wrote:
             | StandardML (standard metalanguage), scheme?
        
               | galangalalgol wrote:
               | 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.
        
             | phplovesong wrote:
             | 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.
        
               | galangalalgol wrote:
               | 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.
        
               | phplovesong wrote:
               | 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".
        
           | pjmlp wrote:
           | 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.
        
         | greener_grass wrote:
         | * 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?
        
         | IshKebab wrote:
         | 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.
        
           | toolslive wrote:
           | Ocaml has a garbage collector. It's less of a struggle than
           | Rust.
        
           | jitl wrote:
           | Rust is a pain
        
           | sausagefeet wrote:
           | 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.
        
             | pjmlp wrote:
             | 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.
        
               | sausagefeet wrote:
               | 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.
        
               | schonfinkel wrote:
               | 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.
        
           | pjmlp wrote:
           | 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.
        
           | linhns wrote:
           | 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.
        
             | IshKebab wrote:
             | 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.
        
           | phplovesong wrote:
           | Rust has too many footguns. Ocaml is usually more safe.
        
         | sausagefeet wrote:
         | 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.
        
         | pjmlp wrote:
         | 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.
        
         | phplovesong wrote:
         | 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.
        
       | hardwaregeek wrote:
       | 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
        
         | criddell wrote:
         | The first comments here are people reading this as if the
         | authors are saying _only_ OCaml can do this. They aren 't.
        
           | sausagefeet wrote:
           | 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.
        
             | xedrac wrote:
             | 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.
        
             | mattgreenrocks wrote:
             | 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.
        
         | lawnchair wrote:
         | 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.
        
         | whobre wrote:
         | 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.
        
           | strongly-typed wrote:
           | Imagine inheriting a project that was a joy for someone to
           | work on instead of a slog.
        
             | blandflakes wrote:
             | 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.
        
               | whalesalad wrote:
               | 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.
        
             | lenkite wrote:
             | Parent developer's Joy is the inheriting developer's
             | Despair. A project is successful when the parent developer
             | is Bored.
        
         | BenGosub wrote:
         | 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.
        
           | yahoozoo wrote:
           | Docker?
        
         | lo_zamoyski wrote:
         | > 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.
        
           | ab5tract wrote:
           | 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.
        
             | lo_zamoyski wrote:
             | > I'm sorry but there is no way you can demonstrate a
             | universal aesthetic.
             | 
             | What do you mean by "aesthetic", because I've already made
             | the distinction between objective beauty and subjective
             | taste. If my explanation is true, then it follows that
             | there is an objective ordering of beauty (of at least two
             | kinds: with respect to the same form/end, and between forms
             | and ends). Then, there's the question of how competent
             | someone is at recognizing this order. And finally, there
             | are contingent factors that will affect expressed
             | volitional preference as a function of factors like
             | attainability or character flaws or whatever.
             | 
             | Making beauty a matter of purely subjective response makes
             | it more mysterious and nonsensical, not less.
             | 
             | > Your opinion of other people's tastes does not reflect on
             | their taste -- it reflects on yours.
             | 
             | How do you know this? _You_ haven 't demonstrated this
             | claim. I've at least explained the basis for mine.
             | 
             | I claim that on the contrary, yes I can. I can claim that
             | someone who thinks rape or murder are beautiful has
             | objectively deranged tastes, because these acts are
             | intrinsically ugly.
        
         | svara wrote:
         | 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.
        
         | epolanski wrote:
         | > I think we should normalize saying that tech stack choices
         | are subjective and preference-based.
         | 
         | True but I don't think this is the correct way to frame it,
         | because it sounds unprofessional.
         | 
         | The correct, and understandable way is:
         | 
         | - the language has properties that fit the software
         | 
         | - the language has properties that fit the development process
         | 
         | - it boosts morale of development team
         | 
         | - the team has the required skillset
         | 
         | Then it's not only a preference, but a conscious engineering
         | choice made of evaluating the different pros and cons of
         | various alternatives.
        
       | keyle wrote:
       | 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.
        
       | celpgoescheeew wrote:
       | I hope for the team to settle with a FLOSS license, so it becomes
       | feasible to evaluate for everyone.
        
         | lawnchair wrote:
         | 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.
        
           | yawaramin wrote:
           | Best of luck. Hoping for AGPL :-)
        
       | iLoveOncall wrote:
       | Everyone makes mistakes, it's good to admit them.
        
       | sgarland wrote:
       | TIL (via a rabbit hole after reading this) that a good type
       | system removes an absurd amount of boilerplate validation code.
        
         | yanis_t wrote:
         | 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.
        
           | sgarland wrote:
           | I'm speaking from a Python background. I love types and use
           | them religiously, but I had no idea how much better (modulo
           | runtime checks; that one's obvious) others were at it.
        
         | Hasnep wrote:
         | Do you have any good resources on this subject? I agree and
         | would like to see what a persuasive argument for it looks like.
        
           | ebonnafoux wrote:
           | 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...
        
           | strongly-typed wrote:
           | Here's my take. It helps you enforce properties about your
           | data. Didn't mean to make this response so long, but alas.
           | (*          Quick note on notation: I will use "double
           | quotes" when referring to _values_ and `backticks` when
           | referring to _types_.       *)            (*          Think
           | of this as an interface. It defines the shape of a module.
           | Notice that the interface describes a module that defines a
           | type called `t`, and two values: "of_string", and
           | "to_string", and they are functions with types: `string ->
           | t`, and `t -> string`.        *)       module type ID = sig
           | type t         val of_string : string -> t         val
           | to_string : t -> string       end              (*
           | Below this comment is a module named "Id" that _is of type_
           | (in other words: it _implements the interface called_) `ID`.
           | Due to the explicit type annotation (Id : ID), now from the
           | perspective of anywhere else in the code, the exported
           | interface of the module "Id" is `ID`.                Modules
           | only contain two things: `type declarations`, and "values".
           | Values are your primitives such as 1, '<', "hello", but also
           | composite such as (fun x -> x + 1), (Some x), f x, { foo =
           | "bar"; baz = 42 }, and even (module Id) (yes! modules can be
           | values too!). Type declarations tell the compiler . Anything
           | which is a value _always_ has a type that can _usually_ be
           | inferred.                No type annotation is necessary when
           | the compiler correctly deduces the type of your value through
           | static analysis. For instance, in the module below,
           | "of_string" is deduced to be of type ('a -> 'a). The ' on the
           | symbol 'a signifies a "type variable", and it means that it
           | can be filled in with any type. For instance (t -> t) and
           | (string -> string), but not (t -> string) or (string -> t).
           | For those it would have to be of type ('a -> 'b). We cannot
           | deduce this type, however, because our implementations do
           | nothing with their inputs besides return them. Since nothing
           | is changed, it's always the same type.               Now, can
           | you spot the pink elephant? Notice how the "ID" interface
           | from above defines "of_string" to be of type (string -> t).
           | How can this be possible? It's because we gave the compiler a
           | hint when we said `type t = string`. This says that a "value"
           | of type `t` is backed by a value of type `string`. If
           | something type checks as `t`, it also type checks as
           | `string`.               So, we could reason through and say
           | ('a -> 'a) can be instantiated to (t -> t), but `t` is also
           | equal to `string`, so we can mentally imagine a hypothetical
           | intermediate type... something like ({t,string} ->
           | {t,string}). This type and type equality is visible _inside_
           | the module. But when the `ID` interface was applied over the
           | `Id` module as in (Id : ID), this has the effect of hiding
           | the type equality (the fact that `type t = string`) because
           | in the `ID` interface we define `t` without an equals sign:
           | `type t`. This forces us to _choose_ a concrete type to
           | expose externally, even though the type is less general than
           | what the implementation sees.                NOTE: OCaml
           | doesn't use parens for function definition or application.
           | Compare this OCaml code against its Python equivalent.
           | > let hello_world h w = (h, w)         > let h, w =
           | hello_world 1 2                vs.                > def
           | hello_world(h, w):         >   return (h, w)         > h, w =
           | hello_world(1, 2)       *)       module Id : ID = struct
           | type t = string         let of_string s = s         let
           | to_string s = s       end              let main () =
           | let s = "abc123" in         let id = Id.of_string s in
           | (* NOTE(type error): because the built-in "print_endline"
           | function is of type (string -> unit) and not (Id.t -> unit)
           | *)         (* NOTE: if an expression returns unit, you don't
           | need to create a let binding for it. You can simply tack a
           | semicolon to the end of it if you need sequence another
           | expression to follow it. *)         print_endline id;
           | (* okay *)         (* STDOUT: abc123 *)         print_endline
           | (Id.to_string id)       ;;              main ()
           | 
           | You could imagine implementing this pattern of defining
           | parsers such as "of_string", "of_bytes", "of_json", "of_int",
           | "of_db_row", "of_request", for any piece of input data. You
           | can think of all of these functions as static constructors in
           | OOP... you take in some data, and produce some output value:
           | e.g. "of_string" takes in a `string` and produces a `t`.
           | 
           | Now, if you have a bunch of "values" of type `t`, you know
           | that they _only_ could have been produced by the `of_string`
           | function, because `of_string` might be the _only_ function
           | that ends with `-> t`. Therefore, all the values maintain the
           | same properties enforced by the `of_string` function (similar
           | to class constructors in OOP). With this, you can create
           | types such as `Nonnegative.t`, `Percent.t`, `Currency.t`,
           | `Image.t`, `ProfilePicture.t`, and parsers from another type
           | to the newly minted type.
           | 
           | The compiler can help you enforce these properties by
           | providing guardrails in the form of static compiler checks
           | (these checks are run _before_ your code can even be
           | compiled). If I have a value of type `Nonnegative.t`, then
           | not only do I not need to validate that it's not negative, I
           | also don't have to validate that it's not negative everywhere
           | else that values of that type are used -- the validation
           | logic is baked into the constructor. Parse, don't validate.*
        
       | churlin wrote:
       | 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.
        
         | therealdrag0 wrote:
         | Scala has some quirks but I enjoyed it relative to more popular
         | languages and its apparent stagnation makes me sad.
        
           | vips7L wrote:
           | 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.
        
             | abathologist wrote:
             | One of OCaml's outstanding, but too little mentioned,
             | virtues is the community's commitment to extremely strong
             | backwards compatibility guarantees.
        
               | Quekid5 wrote:
               | Which led to a _really_ bad standard library with next to
               | no features... but yes, it 's very stable.
               | 
               | And, hey, if it works for you, that's great... but
               | Batteries Included can also be great for a language.
        
             | Quekid5 wrote:
             | Scala 3 didn't "drastically" change syntax -- most of the
             | changes also have automatic rewrites with appropriate
             | compiler switches. The effects story is still pretty
             | experimental, but there's also improvements to 'effects'
             | syntax (for-comprehensions) in "preview" for 3.7.
             | 
             | As long as the 'effects' work will let me distinguish
             | pure/non-pure, I'd be happy to use just that bit and stick
             | with ZIO/TypeLevel's ecosystem... which will probably be
             | supported forever, regardless of whatever happens with the
             | "effects" stuff.
        
         | Quekid5 wrote:
         | The Ocaml module system is great, but the module system in
         | Scala isn't the usual Java package thing... it's traits. It's
         | about as powerful as the OCaml module system on any axis I've
         | ever used, but it's easy to miss how powerful it is. (Scala 3
         | added some ergonomics to make it easier to use, but it was all
         | technically accessible in Scala 2 with 'workarounds'.)
        
       | markstos wrote:
       | 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.
        
         | sausagefeet wrote:
         | 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.
        
       | a-french-anon wrote:
       | 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/
        
         | debugnik wrote:
         | 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.
        
       | stonemetal12 wrote:
       | >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.
        
         | jinwoo68 wrote:
         | 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.
        
       | baby wrote:
       | 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.
        
         | abathologist wrote:
         | All fine and good if you don't like it for whatever reasons,
         | but AFAIK, people have been using OCaml software as parts of
         | tech stacks in critical industries for around 20 years. So
         | unless you have some qualifications to offer,
         | 
         | > I don't think OCaml is ready for production
         | 
         | seems to indicate your thinking is just not based on fact. This
         | position is further belied by the stack of successful
         | production applications you can see at
         | https://ocaml.org/industrial-users/businesses.
        
       | dzonga wrote:
       | nicely designed site - welcome change from dark background,
       | gradient colors etc.
       | 
       | just white, grey & blue.
        
       ___________________________________________________________________
       (page generated 2025-11-07 23:01 UTC)