Tomas Karban

@tomaskarban.techhub.social.ap.brid.gy

software developer 🌉 bridged from ⁂ https://techhub.social/@tomaskarban, follow @ap.brid.gy to interact

A human in control. In #curl development. https://daniel.haxx.se/blog/2026/06/10/a-human-in-control/

A human in control

There seems to be a fair amount of people in either extremes in the current AI landscape. At one side we see the “vibe coders” who use agents and allow them to merge code without any person even looking at the source, while on the other side of the field there are people who are against everything and anything even remotely associated with AI. My personal stance is somewhere in between, as I suppose shouldn’t be too surprising to readers of this blog. ## A work of love and pride The core team behind curl, and that is more people than just me, consists of individuals to whom code quality and source code excellence is important. We do software development because it is a craft we love and we are proud of what we have accomplished this far. We do not hand over our responsibilities to any machines. _We stand for ever bit of code we merge – as humans._ ## AIs do mistakes Blindly accepting code written by AI means that you merge a certain amount of errors, but this is certainly true for human written code as well, so this is not in itself special. Some data suggests that AI generated code might even contain more mistakes than the human versions. We invented test cases and code review a long time ago as a means to help us combat and reduce mistakes to get merged. The particular way code was written does not take away the benefits from code review and getting additional checks and eyes on pending changes. A good code review helps spotting mistakes, omissions or slip-ups. It also helps reinforce the architecture and established design choices. This is true however the code was created. This far, code reviews done by automatic AI bots and the likes have not yet managed to replace the humans. They are simply not good enough. Human reviews are much better. They catch other things and they help make sure proposed changes stay on track. Not to mention how I want to know how curl works, even if I don’t keep 100% intimate knowledge of every single angle and corner, I know most of it. I think it helps me make better decisions, debug better, help users better and keep the architecture sound. Getting the initial code written is not the big deal. For curl, maintaining and polishing the landed code _through decades_ is the real task. _Everything we merge in curl is determined fine and fitting by humans._ ## Humans do mistakes In all living software projects we get bugs reported and we fix them. We do new releases and continue to iterate. We have done this since software was invented and we still do, as humans are quite fallible and easily make mistakes. We try to reduce the error density and frequency by adding tests and by adding more human eyes on the code before we green-light it. It helps, but is not perfect. To help us do better code we invent, introduce and enforce a wide variety of different tools. With tools that look at code and identify problems in the early stages, they help avoid landing bad code in the first place. They make us do better code. They reduce the bug frequency. Some of the best tools for detecting coding mistakes today use AI. These tools might work on existing source code in a git repository or they might look at proposed changes in pull-requests. Above I mentioned that human code reviews are better; but the opposite is also true. In a somewhat complicated change request, it is now common that after the humans can’t spot any more problems, the AI PR review bots can still find an issue or two to remark on. Sure, sometimes they are wrong and then the comment is easily dismissed, but more often than not the findings they point out are actually something worth addressing before merge. _curl is developed and driven by humans, assisted by tools._ ## Communication is for humans Open Source is about sharing code and is a development model where we do things in the open. The _communication_ part of this model is key. Share your ideas, your visions, your problems or maybe just your ideas for what to do this afternoon. Express what you want or what the problem is, and the team can respond and we can work together on fixing and improving whatever needs to be done. Effective communication, a condition for good Open Source, implies _human-to-human_ interaction. Inserting a large AI generated tone-deaf large wall-of-text into such a flow _can_ still work, but only in the same way humans can learn to work with difficult individuals as well. It is not ideal and it is not a smooth way of working. It introduces sand in the machine. Don’t do that. It is rude. _Effective Open Source work means we communicate as humans, even if parts of the work and the code is made with the help of AI._ ## The combination Humans and machines excel at different things. We can complement each other in software development. Everyone is free to act to their own will, but in the curl project we don’t hand over responsibility to machines. We stand for our product. We make it as good as we possibly can; using all the tools that are available to us. I claim that in order to do this, humans need to remain in control.

daniel.haxx.se

Some people are willing to go very far to avoid the C++ `virtual` keyword. https://www.sandordargo.com/blog/2024/12/04/crtp-vs-concepts

Replace CRTP with concepts?

In my Meeting C++ 2024 trip report, among my favourite ideas I mentioned Klaus Iglberger’s talk where he mentioned the possibility of replacing the curiously returning template pattern with the help of class tagging and concepts. Class tagging might mean different things in different contexts, or at least might be implemented in different ways. The end goal is to mark, in other words, tag classes or functions to be used in certain contexts, with certain algorithms. As you’ll see, in our case it’ll also be a tool to prevent duck typing. We are going to see an example implementation of a static interface with CRTP with a couple of different derived classes, then we’ll see the implementation without CRTP. The CRTP solution With the static interface, we are creating a static family of types. There is no need for dynamic polymorphism to share the same interface. It’s still granted through a base class, which is a template taking the deriving class as a parameter. Let’s use animals making sounds for a sample implementation. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 // CRTP version #include template class Animal { public: void make_sound() const { const Derived& underlying = static_cast(*this); underlying.make_sound(); } }; class Cow: public Animal { public: void make_sound() const { std::cout << "moo\n"; } }; class Sheep: public Animal { public: void make_sound() const { std::cout << "baa\n"; } }; class Dog: public Animal { public: void make_sound() const { std::cout << "wouf\n"; } }; template void print(Animal const& animal) { animal.make_sound(); } int main() { Cow cow; print(cow); Sheep sheep; print(sheep); Dog dog; print(dog); } The non-CRTP solution In this case, we don’t use the CRTP pattern (the base class template) to add functionality but to ensure having a common interface without the costs of dynamic polymorphism. We can achieve that with a concept. 1 2 3 template concept Animal = requires(T animal) { animal.make_sound();}; The problem with the above concept is that now every class that has a make_sound() method will be accepted as an animal. Even if the author of the Animal concept or the author of those fake animal classes didn’t want that. That’s why we are also going to require the AnimalTag. 1 2 3 4 5 6 class AnimalTag {}; template concept Animal = requires(T animal) { animal.make_sound();} && std::derived_from; We can be pretty sure that nobody will accidentally inherit from the AnimalTag Now let’s see the non-CRTP version. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 // non CRTP version #include #include class AnimalTag {}; template concept Animal = requires(T animal) { animal.make_sound();} && std::derived_from; void print(Animal auto const& animal) { animal.make_sound(); } class Sheep: public AnimalTag { public: void make_sound() const { std::cout << "baa\n"; } }; class Cow: public AnimalTag { public: void make_sound() const { std::cout << "moo\n"; } }; class Dog: public AnimalTag { public: void make_sound() const { std::cout << "wouf\n"; } }; int main() { Cow cow; print(cow); Sheep sheep; print(sheep); Dog dog; print(dog); } In comparison In my opinion, the non-CRTP solution is more readable and less error-prone. With the CRTP you might accidentally pass in a wrong template argument. It’s true that there is a solution to that. You can make the base class constructor private and make Derived a friend of Base. But you need to think about this. Also, for those who are not familiar with the pattern, seeing the CRTP inheritance plus the static_cast to the derived class is not necessarily easy to understand. The non-CRTP solution is more readable if you are familiar with concepts. While CRTP is a not-so-well-known design pattern, concepts are part of the main language, so you’ll have to get familiar with them sooner rather than later. If you want to learn more about concepts, you can find a series on this blog and I also have a book on concepts At the same time, you need to compile using C++20, which might not be available to you at the moment. I expected the non-CRTP solution to result in a significantly smaller binary, but I was proven wrong. With these small examples, I didn’t find a consistent difference. Depending on the optimization level even one was a bit smaller or the other. I still want to try it in a bigger example and I’ll report back the results, but it might take some time. Conclusion In this article, we covered how we can replace CRTP when we use it to have static interfaces for a family of classes. We saw that with C++20’s concepts, we could replace CRTP and have less error-prone and more readable code. The only question is whether you can already use C++20. Connect deeper If you liked this article, please hit on the like button, subscribe to my newsletter

sandordargo.com