I used to work at an OCaml company and it wasn't nearly as much of an issue as one might predict. You can (it turns out) build a very successful business even if there aren't a lot of existing libraries, or if the language lacks certain basic features like native multithreading (same with Python of course). I don't have a great model for why this isn't devastatingly expensive, but it's probably some combination of
* Most existing libraries are kind of bad anyway so you're not missing out much by not using them
* If you write everything yourself you get system expertise "for free", and gaining expertise in something that already exists is hard
* You can tailor everything to your business requirements
* Writing libraries is "fun work" so it's easier to be productive while doing it
I think Jane Street is a big exception. It's like when PG espouses lisp. Back in the 90's[1] language ecosystems were very sparse. An ecosystem was a few big libraries and a syntax highlighter. Now stuff like IDEs, linting, packages, etc. have made people's standards quite high for ecosystems. On the flip side, back in the day languages like OCaml and Lisp had stuff other languages could only dream about. Functions as arguments! Macros! Type inference! But now, barring macros, these features are all in mainstream languages.
If you were to do a similar company now, you'd have to recruit people who still write code like in the 90's: emacs/vim hackers who can write their own libraries and don't need no stinking IDE. Except you now have a significantly smaller advantage because a lot of the languages have caught up and while your god tier programmers can write their own custom serialization library, that's still more developer time than using serde.
Which is why a lot of people are moving to Rust I suppose. You still get the hip factor but responsibly. It's the Foo Fighters of languages. Cool, but not irresponsible.
The big difference between Rust and OCaml is that a company the size of Jane Street can influence OCaml development, while it takes one the size of Amazon (according to the recent accusations) to do the same with Rust. I think OCaml has one of those "ancient" communities that seem to value independence more than consensus. Rust is very hard to build without cargo, OCaml works fine with make or dune. I'm not sure if focusing on independence is the right tradeoff for most companies, but I can see some cases where it might be.
> If you were to do a similar company now, you'd have to recruit people who still write code like in the 90's: emacs/vim hackers who can write their own libraries and don't need no stinking IDE.
IDE support is getting there with OCaml. In VSCode, it's not as good as TypeScript but it's usable.
> Except you now have a significantly smaller advantage because a lot of the languages have caught up and while your god tier programmers can write their own custom serialization library, that's still more developer time than using serde.
There are a few libraries that you can use. Serde also tends to make the already long compilation time blow up.
I was writing code in the 90's, and my first IDE was Turbo Basic in 1990 precisely, followed by Turbo Pascal alongside Turbo Vision and Object Windows Library.
Eventually I also got into Turbo C, Turbo C++, and then upgraded myself into Borland C++, used Visual Basic 3.0 in 1994, and a couple of years later Visual C++ 5.0 was my first MS C++ IDE.
Mac OS MPW was an IDE and stuff like AMOS and DevPac were IDEs as well.
Java IDEs started to show up around 1998, like Visual Cafe and the first Eclipse, after being ported from IBM's Visual Age.
Visual Age, which were the IDEs for Smalltalk and C++ from IBM for OS/2 and Aix.
The only group that wasn't using IDEs were the UNIX folks, thankfully XEmacs was around to bring some back sanity when I had to code in UNIX.
I'm curious about these early IDEs. My knowledge of 90's programming is solely from secondary sources. What features did they have? Did they do stuff like automatic renaming or goto definition? Were those features done syntactically or semantically? How fast were they? A common complaint I've read is that people could type faster than an IDE could keep up, which is something I rarely encounter these days.
Clojure has access to the Java library ecosystem and works beautifully in IntelliJ. That may be one of the best ratios of language properties to tooling quality.
These days, you don’t need to build an IDE from scratch - you can just build some language server support for your language and plug into existing IDEs. It’s much less work!
Also, as an aside that’s not really germane to the argument, it’s possible (and IMO preferable) to write code without using an IDE. It forces you to write code that’s broken up into contexts small enough to fit in human working memory. This pays off in the long run. However, once people in your company start writing code with an IDE, it requires more context and becomes almost impossible to edit without an IDE.
Haskell is another language besides OCaml that doesn’t have a ton of MEGACORP backing but nonetheless forms the basis for several very successful companies and groups within MEGACORPs, and where many developers prefer the experience of using it despite not having a $10M IDE like you would for Java. And speaking of that, all the ludicrously expensive and complicated IDEs mostly suck anyway!
> you'd have to recruit people who still write code like in the 90's: emacs/vim hackers who can write their own libraries and don't need no stinking IDE
I wasn’t writing code in the 90s, but I’ve worked at places like this and I would take it any day over “people who copy/paste from stack overflow and get lost without autocomplete” - unless the novel alternative you have in mind is something better than that?
> Which is why a lot of people are moving to Rust I suppose. You still get the hip factor but responsibly
Rust does seem to be in the schelling point of “better enough than C++ to get us off our asses, but no so much better as to scare the devs”. Not sure I’d say it’s especially “responsible” though.
Language servers are certainly a big improvement. However there's a different between "there exists" and "this is a community priority". In some language communities the developers use IDEs, they like IDEs and they make IDEs a priority. In other communities there's one or two people who like them, kinda, and maintain a plugin. Let's put it this way, I don't see OCaml moving to a query based compiler anytime soon.
I'm not sure I agree with the no-IDE part. It feels very "Plato complaining about the invention of writing". Human working memory is quite narrow and quite fickle. If you step away from a codebase for a while, or you're learning it for the first time, an IDE can really help with your bearings. I agree that code should be broken up into contexts and well organized, but I don't think the editor should be the forcing function here.
And IDEs are great! Goto definition that works even in complicated situations unlike ctags; inline type inference; generating imports. I don't begrudge someone using emacs or vim (2nd generation emacs user) but I gotta say, IDEs work wonders.
As for who I'd recruit, I think it's a false dichotomy to say that the alternative is "people who copy/paste from stack overflow and get lost without autocomplete". There's plenty of great, legit developers who can write you a custom serialization library in nano, but choose to use IntelliJ and packages because it gets the job done.
I don't mean to denigrate the OCaml, Haskell or Lisp communities. I wish more people wrote them! But I also recognize that these languages went from secret weapons to, well, a valid option in a trade off matrix. I'd still love to work at Jane Street, although between this comment and my application record, that may be a pipe dream.
> Also, as an aside that’s not really germane to the argument, it’s possible (and IMO preferable) to write code without using an IDE. It forces you to write code that’s broken up into contexts small enough to fit in human working memory
No, complex programs by definition don’t fit into human working memory. Even with best practices, FP, whatever, function composition alone can’t always elevate the complexity to the requirement’s level — so in the end you will end up with larger chunks of code for which you will have to use code navigation features - for which I personally prefer an IDE, but that is subjective.
> No, complex programs by definition don’t fit into human working memory.
If you write your code in the right way they don’t have to. That’s the point.
You shouldn’t need to comprehend your entire program at once to work with it.
> Even with best practices, FP, whatever, function composition alone can’t always elevate the complexity to the requirement’s level
Function composition isn’t the pinnacle of abstraction. We have many other abstraction techniques (like rich types, lawful typeclasses, parametric programming, etc.) which allow for any given subcomponent of a program to be conceptualized in its entirety.
> If you write your code in the right way they don’t have to. That’s the point.
I recommend you try working through some equality proofs in Coq, first with and then without coqtop / Proof General. I think you may change your mind about this rather rapidly. And many proofs get much more complex than that.
I’ve used (and developed) plenty of proof assistants. Proofs are one very narrow domain where automation is basically a no-brainer. You don’t really lose out from the proof having high semantic arity. With normal code, you do lose out.
I dunno. I think the line between "normal code" and proofs is a lot blurrier than many people make it out to be, and I don't think there's a huge advantage to asking people to run a type checker or inference algorithm in their heads even if you have managed to encode all your program's invariants in the type system (which is impossible or impractical in many languages). I say that as someone who doesn't use an IDE except when I'm forced to: I know I lose out on a lot of productivity because of it, and I don't find that removing the IDE forces me to develop better or more concise code.
I can work without autocomplete, but I find my productivity is about 20% when I have to go back and forth with the compiler on syntax errors and symbol names, like back in college. Working professionally with an IDE that just doesn't happen.
PG seems to be the only person who has built a successful business using Lisp. While thousands of successful companies are using C++/Java/.. etc. why do you think so few companies have succeeded with Lisp?
While it's true that there are lots of bad libraries and many libraries are easy, you really isolate yourself from the broader ecosystem by doing this. Vendors and 3rd party solutions are now much harder to use, and when you use them you'll probably only use them at a surface level instead of using all the features.
And some things are so mature and vast you don't have a chance of building them yourself. If what you are doing can be done well in very mature ecosystems like React or PyTorch, the effort to recreate them will dwarf the time spend on important work.
> If what you are doing can be done well in very mature ecosystems like React or PyTorch, the effort to recreate them will dwarf the time spend on important work.
Sometimes that's effort that's not really necessary. At work we had a team build a dashboard with React and a few graphs recently. It clocks at 2000 unique dependencies. That's not a typo, it's two thousands dependencies for a few graphs. Reimplementing all of that would take many man-years of work, but I think it wouldn't be necessary in the first place. Chart.js doesn't use any runtime dependencies, and could probably fill most of our needs. Chart.js is 50k of Javascript, which is a lot but probably more than we need. I don't know how much time it would take to make a reimplementation to have the API we need, but I think it's doable. Why would we want to do that? Because those 2000 dependencies are a liability. Last time I checked 165 were looking for funding. It would be easy to imagine a malicious actor paying a few people to contribute to low profile but widely used JS libraries, and take over the maintenance when the original maintainer becomes tired. I don't know if this is a worse liability than developing our own chart library. I don't know much about security and the tradeoff involved.
All of that to say, isolation from the broader ecosystem may be a good thing.
Yes, it's not free in the sense that this is paid developer time, and also a delay before actual production deployment.
As long as learning the basics of a 3rd-party library takes a relatively short time, those who use it have an advantage: they ship faster. Certainly mastering it may take as long as writing one's own. But you can do that while writing more production code and shipping features. Also, you get improvements made by other people for free (because likely you're using an OSS library anyway).
That's interesting, thanks for sharing your experience. Sometimes I wonder how much interesting experience I miss by mostly using things people already built. Sure, if you're just trying to get something done it's probably faster, but on the other hand spending more time gives you experience.
My experience as well. I worked in industries (Games development) where no open-source or proprietary solutions existed for what we needed. So we built it ourselves. It wasn’t that hard and we never had problems with it because it did 100% exactly what we needed and nothing else. If any new feature was needed we simply added it. I would routinely get an ask from a programmer, artist, musician or game designer and would have it implemented and a new version ready for them within a day or two. The productivity gains were immense.
Multi-threading can often be handed off to the OS in the form of just run more processes. So in most cases there is really no need for the language to handle it.
Its still nice to have shared memory especially in a functional language where due to lots more immutability it isn't as big of a price (i.e. more concurrency safe). Especially if your sharing in-memory caches and the like.
I've seen this save tons of dollars in cloud setups (100,000's) in my career in more than one place. Safe multi-threading was marketed as part of the advantage of functional programming to many people; which IMO why I find it strange that OcAML didn't have it for so long. Lightweight threads (e.g. Tasks, Channels, etc) use less system resources than processes as well.
You can do anything with anything but you usually pay some price of inefficiency to do so. That may be small, but sometimes it is large enough to matter.
Agreed; especially since it didn't have it originally. I'm sure some compromises were made to do it in a way that fits into the execution model/doesn't cause regressions to older code. They are both good languages for sure which makes sense because one is derived from the other.
F# through itself and .NET has had the equivalent functionality for many years however (Threads, Tasks, Async's, Channel libraries, etc) being the one of the first languages (before C#) to have an Async construct. I would imagine it would take some time I think for OcAML's ecosystem to catch up API wise with this where it matters for application development. Looking at OcAML's recent release notes I see work to slowly migrate multicore into OcAML but the feature itself hasn't landed yet? Think it comes in 5.0.
I have to say though F# performance is quite good too those days from working/dabbling with both languages + the ecosystem is bigger. I would like to see/understand where the OcAML perf advantage is there is any for evaluation. The CLR has really good performance these days; its has features to optimise some things (e.g. value types make a big difference to some data structures, hot loops vs the JVM) from my experience especially if you don't allow Unsafe code for many algo's/data structures. For example I just looked at the benchmarks game (I know has its problems including bad contributed implementations for niche ecosystems) but it shows .NET Core (and therefore F#) performance is within the same scale as OcAML at times beating it (https://benchmarksgame-team.pages.debian.net/benchmarksgame/...).
If you don't need to share any data between processes, sure. Otherwise, you will find yourself forced into a pattern that is:
* extremely costly
* hard to make portable cross-platform
* hard to make secure (since data external to the process can't be trusted like shared-memory data can).
* requires constantly validating, serializing, and deserializing data, wasting developer time on something irrelevant to their problem domain
* adds a bunch of new failure modes due to the aforementioned plus having to worry about independent processes crashing
* fails to integrate into the type system of your language (relevant for something like Rust that can track things like uniqueness / immutability for you)
* cannot handle proper sharing of non-memory resources, except on a finicky case-by-case basis that is even more limited and hard to make cross-platform than the original communication (so now you need to stream events to specific "main" processes etc., which is a giant headache).
* Can cause significant additional performance problems due to things like extra context switching, scheduler stupidity, etc.
* Can result in huge memory bloat due to needing redundant copies of data structures and resources, even if they're not actually supposed to be different per thread.
Make no mistake here, when you're not just running multiple copies of something that don't communicate with each other, "just use processes" is a massive pain in the ass and performance and productivity loss for the developers using it, as well as hurting user experience with things like memory bloat. The only reason to go multiprocess when you have threads is in order to create a security boundary for defense in depth, like the Chromium does--and even they are starting to reach the limits of how far you can push the multiprocess model before things become unusably slow / unworkable for the developers.
There isn't really a need for anything, which is kind of the point. You can use a random language that's missing a ton of functionality and you can probably make it work.
* Most existing libraries are kind of bad anyway so you're not missing out much by not using them
* If you write everything yourself you get system expertise "for free", and gaining expertise in something that already exists is hard
* You can tailor everything to your business requirements
* Writing libraries is "fun work" so it's easier to be productive while doing it