What does HackerNews think of immer?
Postmodern immutable and persistent data structures for C++ — value semantics at scale
Also, it's my understanding that, in practice, persistent data structures require a garbage collector in order to handle deallocation when used in a general-purpose way. How does your implementation handle that?
Also, have you seen https://github.com/cnuernber/ham-fisted ? I think there are a few other Java-based persistent collections as well in the overall Clojure ecosystem that also improve on Hickey's original implementation, but I can't recall them now…
Very much inspired by Clojure, with a lot of time put into benchmarking and profiling.
It's too early for me to share numbers on jank vs Clojure itself, especially due to the rewrite, but my earlier jank versions were definitely competitive with AOT compiled Clojure jars.
I've been, on and off, working on a little toy game engine, for a few years. Its a mix of keeping up with C++ advancements, learning various concepts like physically based rendering, and just the fun of crafting a big project, with no constraints other than my time and ability, no deadlines, no expectation of releasing anything. Its cathartic and enjoyable. I really do enjoy it.
Last September, I got frustrated with something I was working on in a more serious capacity. It was some server software, it responded to HTTP requests, it accessed third party services over HTTP and Websockets, it talked to a Postgres database. Overall it was an event driven system that transformed data and generated actions that would be applied by talking to third party services. The "real" version was written in Clojure and it worked pretty well. I really like Clojure, so all good.
But because I was frustrated with some things about how it ran and the resources it took up, I wondered what it would be like if I developed a little lean-and-mean version in C++. So I gave it a try as a side project for a few weeks. I used doctest[1] for testing, immer[2] for Clojure-like immutable data structures, [3] lager for Elm-like application state and logic management, Crow[4] for my HTTP server, ASIO[5] and websocketpp[6] for Websockets, cpp-httplib[7] as a HTTP client and PGFE[8] for Postgres, amongst some other little utility libraries. I also wrote it in a Literate Programming style using Entangled[9], which helped me keep everything well documented and explained.
For the most part, it worked pretty well. Using immer and lager helped keep the logic safe and to the point. The application started and ran very quickly and used very little cpu or memory. However, as the complexity grew, especially when using template heavy libraries like lager, or dealing with complex things like ASIO, it became very frustrating to deal with errors. Template errors even on clang became incomprehensible and segmentation faults when something wasn't quite right became pretty hard to diagnose. I had neither of these problems working on my game engine, but both became issues on this experiment. After a few weeks, I gave up on it. I do think I could have made it work and definitely could go back and simplify some of the decisions I made to make it more manageable, but ultimately, it was more work than I had free time to dedicate to it.
So my experience was that, yes, you can write high level application logic for HTTP web backends in C++. You can even use tools like immer or lager to make it feel very functional-programming in style and make the application logic really clean. Its not hard to make it run efficiently both in terms of running time and memory usage, certainly when comparing to Clojure or Python. However, I found that over all, it just wasn't as easy or productive as either of those languages and I spent more time fighting the language deficiencies, even with modern C++, than I do when using Clojure or Python.
I think I would think very long and hard before seriously considering writing a web backend in C++. If I had the time, I'd love to retry the experiment but using Rust, to see how it compares.
[1] https://github.com/doctest/doctest
[2] https://github.com/arximboldi/immer
[3] https://github.com/arximboldi/lager
[4] https://github.com/CrowCpp/crow
[5] https://think-async.com/Asio/
[6] https://www.zaphoyd.com/projects/websocketpp/
[7] https://github.com/yhirose/cpp-httplib
I saw a comment here about undo/redo and I think it's a must have feature for something like this. I implemented something based on the command pattern first, but ended up disliking the amount of code needed just for undo. I eventually tore all that out and built my state model on the excellent immer[2] library.
Not only can you do OOP in C, you can also do FP, implement your own iterators and the like. (Function) pointers are your friend: https://news.ycombinator.com/item?id=28378627#28406874
And remember: FP = pure functions (no side effects) + immutable values
Currying in C is essentially taking the address of a function pointer and not calling it. You can do lazy evaluation as well. The Cky is the limit!
Yes, C++ is comfy, but you cannot really do FP with its STL. As STL containers require mutability by default.
std::transform(v.begin(), v.end(), w.begin(), [](auto const& x){ /* ... */});
Transforming the contents of v requires a buffer(!) w. (The rescue: https://github.com/arximboldi/immer)
In Python, this would be something akin to:
map(lambda x: x, t); # t being a tuple type here
This will return another tuple.
Yeah, so these are just some pointers. I just wanted to stress that C can enable your creativity once you get the essence of it.
My dream programming language is basically a statically typed Clojure.
I've on and off poked at trying to make something like that (parsed using instaparse, type checked in Clojure, compiled to C++ using https://github.com/arximboldi/immer for the data structures), but haven't had the time to really get anywhere with it. Plus, even if I succeeded, I wouldn't have the rich Clojure (and by extension, Java and Javascript) ecosystem.
https://github.com/arximboldi/immer
https://github.com/arximboldi/lager
https://github.com/arximboldi/zug
Also, I very agree with what @jasode has said. C++ will be interesting for you if you can do interesting things in C++. That is the main reason I use it: there are certain domains where I work: professional music software, graphics, film, robotics, etc. where there are no solid alternatives (maybe Rust/Nim/Zig if you are very adventurous). This kind of software is actually really cool, it's creative and enhances artists's lives and does not live in magical "clouds" but runs on your machine. The language is imperfect and complicated but working in these domains is really cool and it makes the experience of taming the beast of C++ enjoyable :)
C++
> Garbage collection was never added into C++. Manual memory management is extremely error prone.
C++ has memory management simplification: reference couting via shared_ptr/unique_ptr. The trade-offs are different, but in C++ manually managing memory is not necessary unless you have a good reason.
> C++ is notorious for its slow compilation time. Significantly slower than Java, not as bad as Scala.
That depends on what you use and how you use it. However, this is tricky to figure out what slows down the compilation.
> In C++, all references are nullable.
Looks like this guy really needs to read up on C++. References can point to null, but not so easily. I think he means pointers.
> Catching/throwing errors is the preferred error handling mechanism.
I think he should really watch Herb Sutters Video[see 1] on the improvements of exception handling that are in the pipeline. Herb also discusses the alternatives to exception handling.
C#
> Multi-paradigm?
C# has Pattern matching since 8.0 [see 2]
Python
> Python is dynamically typed, there’s not much more to say about the type system.
Dynamically but strongly typed one could say.
> In comparison, NPM in JavaScript is the only tool you’ll ever need.
JS has Yarn as well...
> I don’t recommend using Python for large projects, the language was not built with serious software engineering in mind.
no arguments provided... and in fact there are very large python projects out there in the wild.
Also, pytest is one of the best test frameworks that i have seen.
Rust
> Rust was designed from the ground up to be fast. Compilation of Rust programs takes longer than compilation of Go programs.
i don't understand why he bashes C++ for slow compilation times and not rust. According to [see 3] rust is twice as slow on some benchmarks...
> Rust is the only modern language on our list with no garbage collection. > This forces the developers to think about low-level memory management, and makes developer productivity suffer.
No mention of the borrow checker etc, I find extremely disappointing.
> Rust has no built-in support for immutable data structures. Discussions like [4] should be referenced - i think when discussing this topic.
JS
> JavaScript has good libraries for working with immutable data (like Rambda/Immutable.js).
Weird that he doesn't mention the library efforts in C++ [5] and Rust [6] and Python for immutable data-structures [7][8]
----
[1] CppCon 2019: Herb Sutter “De-fragmenting C++: Making Exceptions and RTTI More Affordable and Usable” https://www.youtube.com/watch?v=ARYP83yNAWk
[2] https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/...
[3] https://users.rust-lang.org/t/are-there-any-compilation-time...
[4] https://users.rust-lang.org/t/persistent-data-structure-supp...
[5] https://github.com/arximboldi/immer
[6] https://github.com/orium/rpds