This is nothing new, it is also a reason why languages like C and C++ won the systems programming wars from the 1990's.
After a while one gets tired to write wrapper libraries, or having to pay extra for an additional compiler that isn't part of the platform SDKs.
Hence why successful languages always need some kind of killer feature, or a company with deep enough pockets willing to push it into the mainstream no matter what.
Same applies to new OS architecture ideas as well.
These days, Zig seems to be explicitly trying to do the same thing, but without paying the backwards compatibility tax:
https://ziglang.org/documentation/master/#Import-from-C-Head...
Edit: Oh, looks like it was released just a few days after I last checked; ha. Although, it's not clear to me whether it's intended for end-user use yet.
BUT back on the thread's topic, since i started programming in Rust, the only time i've felt it was hard to wrap my head around the compiler's output was with complex async programming. Otherwise, every single time i felt like a simple text editor was more than enough with rustc's output to understand what's going on, because in Rust everything is very explicit and statically typed with clear lifetimes, and the compiler has very helpful error messages often including suggestions on how to fix the error.
For me, everything (non-async) Rust is a clear win in terms of understandability/hackability, compared to all other languages i've tried before (admittedly not a lot of them). I think complex IDE tooling can ease the pain, but proper language design can help prevent the disease in the first place.
EDIT: i should add, since i started programming in Rust, i've only once or twice seen a runtime panic (due to array indexing error on my side). Otherwise, literally all of the bugs i had written were caught by the compiler before the program ran. For me it was a huge win to spend one more hour to please the compiler in exchange for spending days less debugging stuff afterwards.
I did not program in Rust so I can not really judge the language but I doubt that it is so nice and expressive comparatively to modern C++ that suddenly the types of bugs I am hunting will magically disappear.
Then you're a much better programmer than i am! :)
For algo debugging i just use pen and paper. For more surprising results, print statements are usually all i need.
> suddenly the types of bugs I am hunting will magically disappear
Maybe not, but i'd recommend to give it a try, if only to offer a different perspective. For me personally, strict and expressive enums, mandatory error handling and Option/Result types as language core features (among others) have definitely eliminated most bugs i write. Well i still write those bugs, but at least the compiler doesn't compile like everything is fine, and instead lets me know why my program is flawed.
https://devblogs.microsoft.com/cppblog/edit-your-c-code-whil...
https://uecasts.com/courses/unreal-engine-5-introduction/epi...
With VC++ and Unreal catching up with Lucid Energize[0], others will have to up their game.
Anyway, this is really a matter of implementation, not a language issue. There's nothing about Zig that makes it inherently impossible to support SH2 or any other platform - indeed, as others have noted, they already have a C backend in the works, so the endgame is to support everything that has a C compiler.
Also, as far as C interop goes, if I remember correctly, Nim can't just take a C header and expose everything declared in it - you still have to manually redeclare the functions and types that you want in Nim, no? You can use c2nim, of course, but that's not really any different than generators for other languages, and requires extra build steps etc. Zig handles it all transparently.
I think separating the two is a bit artificial. Python being slow is partially an implementation issue but the fast implementations can't run everything. When you compare languages, you have to compare implementations, otherwise it's meaningless.
And sure, you can always "fix" a language by designing a derivative higher-level language that transpiles into the old one. In fact, this is a time-honored tradition - C++ was originally just such a transpiler (to C). But the very fact that you have to do this points at the original design deficiencies.
That's kind of what people are getting at in this whole conversation though isn't it, ecosystems around languages matter. They can't be an afterthought.
I'm not even sure why arch support was brought up in this thread, to be honest, because it's not relevant at all? If your problem is unsupported architecture, it's a blocker long before you need to use any libraries...
https://www.welton.it/articles/programming_language_economic...
I like the Tcl example, that is how we worked at a .com startup I was part of.
There's a third strategy: hitching your wagon to an already-successful ecosystem, like languages such as Kotlin do.
Using Kotlin as example, its initial selling point was Java compatibility, now it wants to be everywhere, and its Java compatibility story is also constrained for what Android Java is capable of.
So the tooling attrition increases, with KMM, wrapping FFI stuff to be called from Java like coroutines, and everything that is coming with Loom, Panama and Valhala.
* 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
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.
[1]: I was in a very famous tv show: https://www.youtube.com/watch?v=FBw-Z8ULwcc
> 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.
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.
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.
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.
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.
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.
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.
Can you look at them in small chunks to understand what they are contributing to the result?
It looks like there is such a thing as complexity that is not functionally decomposable.
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.
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.
Code is code: both models (3rd party vs no 3rd party) can work and the time spent reinventing the wheel is not necessarily business breaking.
That said, you're right it is fun, and people like doing it so its good to keep your work mixed up and you team motivated.
It's a good lever to pull IMHO, but not always.
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).
Though I think the "fun work" point is really interesting and worth a broader discussion
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.
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/...).
* 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.
On the other hand this is like "Wallaroo moves from the Cadillac of languages nobody uses, to the Chevy Equinox of languages nobody uses." Like, totally fine, you grew older and had kids and needed an SUV to keep up with home life, no shame in that... but there is a wistful "ah when we were young" to the transition, no?
Pony is like the far-off "ah maybe someday I'll be able to use that at work, maybe for some little experiment" thing and it reminded me of going to a dealer and being like "let me drive the Caddy, you know I'm not gonna buy it, I know I'm not gonna buy it, but I just wanted to live a little today." I don't have any particular experience with Chevy SUVs so I just chose one at random, the point was that Rust is like a "look we're just trying to be C with explicit contracts between parts that allow for memory safety" type of language, very practical and chunky and like people love it don't get me wrong... just, it's an SUV. It's less opinionated and more just "let's get from point A to point B safely."
I will also add that Rust is not trying to be C (and neither trying to "replace C"). It's here to offer an alternative, that in some cases makes more sense than sticking with C. C code means a lot of thing. For example, some people code in C89 because they find some kind of purity in it. You're never going to get that from Rust. For some people, it means fast and secure code, like with Python's cryptography. That's a place where Rust can be used. For some other people, it's C because that's the only thing that's allowed by some authority. Again, Rust isn't going to fit here until/if it's allowed. I think in general, trying to reason in terms of use case leads to better comprehension than trying to think in languages.
But outside of that, the move was basically the same. They found another language that's very similar, but that has a way bigger ecosystem.
I thought F# was OCaml?
Having some experience with large scale F# codebases its rare you define a class compared to records, unions and functions. 100's of functions, 50-100 small types, 1-2 classes approx is usually the ratio I've seen for a typical microservice (YMMV).
When I think of OCaml, the concepts that come to mind are brilliant French computer scientists and hedge funds. A practical Haskell. When I think of F#, I think of... .NET, bright enterprise programmers who want to work with a tolerable language, and that's about it. If forced to name a user of it, I'd say "uhh, no idea... Maybe Stack Overflow?"
(That's entirely aside from the relative merits of both languages, which are leaps and bounds ahead of both most OOP and functional languages.)
I think the biggest use for objects is to have a kind of row polymorphism? I don’t know too much because I haven’t used them at all.
The biggest quirk coming from something like Java or C# is that you can't downcast. But classes can still opt into this ability (by using virtual methods + extensible variants) where it makes sense; and in most cases, the presence of downcasts means that a discriminated union is probably a better fit to model something than a class.
It also makes me think of CircleCI where they stayed in Clojure for quite some time - it really didn't have that much need for libraries (and the ones it did need, such as AWS, were provided by Java).
When evaluating whether to use a non-mainstream language, the rule I use now is:
- will I need to interact significantly with the outside world in a way that can only be done with libraries?
- if not, do I gain a lot with this non-mainstream language?
That contrasts against how I used to do it, where I viewed it as a trade-off between the ecosystem and the advantage of the non-mainstream language.
A language that does NOT have as many features and limits more what you can do is NOT a strictly worse language. You can never say a language is worse than another, anyway, in general: it's always relative to what usage you have in mind. Your apparent disdain for a language just on the basis of the language features shows that you have a lot to learn about language economics, mentioned in other threads here.
This is in contrast with Kotlin, that tries to gain popularity by including many features, but always feeling “just sugar syntax over Java” to me.
Could you please elaborate on that? It was my understanding that Kotlin did everything that Java did (or any JVM-based language) but actually added first-class support for basic features missing from Java that required magic sauce like Lombok to fill in the gaps.
It's never had working error highlighting for Scala. I filed a bug where using a parameterized member type was incorrectly highlighted as an error, the next version using a parameterized member types was never highlighted as an error. I filed a bug with a case that should have been an error wasn't, the next version my original bug was back. I gave up at that point.
and having a big ecosystem doesn't mean it's a good or a healthy one either.
Like, the only reason are computers are remotely working fine is that great deal of abstractions.