In my old age, I find the more permissive a language is, the more painful it is to code in long term. Perl is great for simple things, but C++ was a vast improvement because it catches a lot of nonsense that Perl will compile just fine.
And debugging is so expensive that eventually writing code fast is near worthless. Whatever you gain you more than pay for in debugging afterwards.
C++ unfortunately doesn't go far enough.
There's a balance.
Rust is not a simple language.
Lisp is also a simple language.
Lua is simple as well (well… maybe not…)
JavaScript is not.
C++ is not.
It's not that C is simpler, it's less expressive.
I don't think this answers parents question though, which is what does it mean for a language to be simpler? I think that's a good question. This is just a list of examples.
It almost seems like simple is a bad concept applied to languages because what's simple and complex is the idea you're trying to express, accurately, in its totality - not necessarily the language.
The fewer ways there are to express an idea, the simpler the language is.
Simple languages do not imply simple software (look at lisp)
One could technically also get memory and reference safety this way. Which is the opposite of what Rust does for example, where it defaults to do a particular model of referencing memory and makes using any other painful.
It also does not have any constraints on timing or redundancy if necessary.
Automate some of this handling but still keep it explicit and you have a potential winner.
I hesitate to even guess what the findings would look like, but I bet it’d be interesting.
Meanwhile with ocaml you need to understand type theory, type inference, algebraic data types, the module system, maybe row poly, (insert a bunch of other things), and now also algebraic effects. And there's no guarantee that the well formed logic of your domain problem is compatible with the type theory your language is using (although, adt + generics almost always does the job if you take a minute).
That being said, the way that's being expressed here does leave something to be desired. Like, if someone doesn't jive well with static techniques that's one thing. But I've never really understood decrying people who get it as suffering from some sort of Stockholm syndrome.
Even though I don't agree with the dynamic camp, I like advocating for it because I think there are scenarios where there is something there.
However, the position that the static camp is somehow against freedom and morally wrong is pretty weird to me.
Okayish was fine or even necessary in the past but the industry has matured to the point where we need more purpose built tools for more specific projects.
Rust is going to be necessary but also zig, hylo, vale, p, Odin, and jai (assuming we ever get a release date). A language able to do everything that c++ can is almost definitely only able to do it all okayish.
You can add other constraints (e.g. temporal constraints) and get similar benefits, on top of the above.
And a large fraction of the problems that lead to security situations. Worse, they are often so subtle that they stay in a codebase for decades.
> and replacing them by an immediate shutdown is hardly a very useful improvement on program quality.
That's a pretty absolutist statement about something that's very context dependent.
Yes, there are security issues beyond memory safety bugs. But these are the issues that are most regularly turned into the most serious exploits and they are hellishly common.
All systems security is about layered defenses. "Oh, log4j exists" is not a compelling reason to avoid changes that can mitigate very large portions of security risk.
There are places where you'll truly never encounter untrusted input and a crash is just as bad as blasting off and performing whatever unexpected computation, but that's nowhere near the entire existing C++ landscape.
And it explicitly introduces undefined behaviour aka "memory safety bugs".
[0] I meant what I said.
I find it interesting because until about three years ago, C++ was always on the other side of this argument. We fight about static type systems. You could shout at the compiler that you know that your code is correct even though the type system doesn't pass. Why does the committee think it knows better than me! Everything is just bits after all!
Now we are on the other side. C++ people saying "bro I totally promise I'll initialize this data member before it is used, stop making me initialize it in my constructor"
C++ has never said this - if a type has a constructor, that constructor will always be used in a data member (or elsewhere).
You can absolutely write a type like this.
class Foo {
public:
Foo() {} // never initialized x
int x;
}
And then using it like this Foo f;
bar(foo.x); // oops
"But my types are well designed" is the usual response to "why the heck does the language allow you to quietly expose yourself to UB in this way?"Any instance of Foo will run Foo's constructor because Foo has one. The problem is that that instance of Foo won't definitely have x initialized, because int doesn't.
Plus, there are stl types that don't guarantee initialization of members. So it isn't like only ever resting on top of stl types is sufficient. std::optional has a non-default constructor but it can happily blow up because of a read of uninitialized data.
And the fact that this is the silent default behavior in C++ is wild to me. Even in languages where it is possible to leave data in an uninitialized state, you should need to loudly signal it.
I agree, totally. Backwards compatibility is a cruel mistress.
You can do this in Rust if you want! You just have to use unsafe { mem::uninitialized() } or even better, the newer unsafe { mem::MaybeUninit::uninit() }
The whole point is that you probably don't ever want to have an uninitialized variable you can access willy-nilly, and if you do, you should be very explicit.
Even your statement about C (and C++) isn't quite accurate, right, because anything static is guaranteed to be initialized to zero on creation. So while `int x` is a free for all, `static int x` is gonna be zero. Another thing people shouldn't have to think about!
Principle of least surprise.
Congrats if you never write bugs. For the rest of us, we will use the widely available data that demonstrates that these bugs recur over and over and over and over even in organizations with strong developers, strong testing culture, and where the use of static analyzers and fuzzing is widespread.
Yes, C also has these problems. Both C and C++ represent significant safety risks, despite powering some of our absolute most security critical applications (the linux kernel and our web browsers). Other languages don't give you these footguns.
They might know how to design a language such that it tends to produce exceptionally readable codebases, good performance, and improved safety, though. Maybe not all three at once, but some mix of those that’s better than existing languages, perhaps.