The real issue is the C and C++ languages are horrible languages. They're too high-level to correspond to any real machine, yet so low-level so as to make such an abstract machine useful. The C language leaves the precise lengths of types up for grabs, as merely one example. As for Rust, I'd figure it's poor as well, considering it follows in the footsteps of C++.
I can compile an Ada program that has an uninitialized variable and use it, but I get a warning; there's also a Valid attribute that acts as a predicate for whether a scalar value has an acceptable value or not.
To @userbinator , you're mistaken to believe the C has much design behind it. There are many things where one requires a certain range of values and C forces the programmer to use a type that's much larger than necessary and cope with unwanted values. The C language leaves details to the underlying machine, so long as that machine is determined to pretend it's a PDP-11. Most languages that have a standard expect the programmer to follow it; since most C programmers don't know what the standard says, having been lied to about it being a simple and base language, they're offended when they do something they never should've done; they shouldn't be using C anyway, however.
Abstract language details are necessary for a high-level language and can work quite well if the language is designed well; this then leaves high-level features to be implemented in whichever way is best for the machine; the C language doesn't do this well at all, however, and precisely specifies the nature of irrelevant details and so hinders the machine and implementation possibilities.
The C language doesn't even have true boolean values or arrays thereof. You're expected to use an entire integer that's zero or not and you're left to your own devices if you want an array of these values that isn't grotesque in its wastefulness. Meanwhile, most proper languages have the concept of types that only have two values and can easily use an underlying machine representation for efficiently representing these, without involving the programmer.
In closing, you may argue that C is necessary because it permits specifying these low-level details, albeit required in every case instead of only where necessary. To that, I direct you to look at Ada, which permits the programmer to ignore such details wherever unneeded, and so leave them to the compiler’s discretion, but allows size, address, representation, bit-level organization, and more to be specified in those cases where it's truly necessary.
Here's a link others may like for learning more about Ada and the deficiencies of C:
- Safe code cannot access uninitialized memory under any circumstances (unless unsafe code accidentally vends it to safe code).
- The simple case you mentioned, of using a variable without initializing it, is always a hard error. This applies in both safe and unsafe code.
- ...However, unsafe code can explicitly ask for uninitialized memory, like the code in the blog post does. It's not really useful to ask for an uninitialized integer, but you may want to allocate a large struct on the stack and not initialize it.
- Unsafe code can also obtain uninitialized memory in other ways, such as by calling malloc, which allocates memory that starts in an uninitialized state. (The alternative is to zero the memory after allocating it, but that's slower.)
> Meanwhile, most proper languages have the concept of types that only have two values and can easily use an underlying machine representation for efficiently representing these, without involving the programmer.
Don't other languages still use an entire byte to represent a bool though, since memory access is at the byte level? Having a bool type in the type system is really a language usability concern, I don't think it's at all a performance optimization. And stdbool.h exists now, so that concern has been addressed. When you want a bitmap, you can just use an int of the appropriate length and do bitwise operations on it, instead of wasting space with an array of ints.
>Don't other languages still use an entire byte to represent a bool though, since memory access is at the byte level?
While at the discretion of the implementation, Common Lisp is a language that can easily and transparently perform this optimization. Common Lisp even has a specialized array type, BIT-VECTOR, which can only hold values of zero or one, which is more likely to be optimized for size than other types. Ada allows the programmer to specify data structures be optimized for size, which is nice.
Now, representing a lone true or false value is a different matter and I'd expect it to consume an entire register or whatnot under most anything, since you probably wouldn't be able to store anything else with the remaining space.
>Having a bool type in the type system is really a language usability concern, I don't think it's at all a performance optimization.
Ada has a boolean type because there are clearly boolean situations, such as predicates, and having a dedicated type reduces use errors. Programmers are encouraged to define their own boolean types, though, such as (On, Off), say.
>And when you want a bitmap, you can just use an int of the appropriate length and do bitwise operations on it.
That's what I was describing. Why should a high-level language have you making your own arrays? Don't you agree that programs would benefit from a specialized type for this that can more easily be optimized and specialized for the particular machine and whatnot?
AFAIK in Ada, deallocating memory is unsafe. So I'd say it has some catching-up to do when compared with safe Rust in that regard. And Rust of course has a two-element type, it is called `bool`.
That said, Ada certainly got many things right. it was an important milestone. But even Ada has "unchecked" operations (such as deallocation), which is exactly what unsafe Rust is, and then you have all the same problems about undefined behavior and having to describe an abstract machine to specify what exactly is (not) undefined behavior and so on.
I can compile an Ada program that has an uninitialized variable and use it, but I get a warning; there's also a Valid attribute that acts as a predicate for whether a scalar value has an acceptable value or not.
To @userbinator , you're mistaken to believe the C has much design behind it. There are many things where one requires a certain range of values and C forces the programmer to use a type that's much larger than necessary and cope with unwanted values. The C language leaves details to the underlying machine, so long as that machine is determined to pretend it's a PDP-11. Most languages that have a standard expect the programmer to follow it; since most C programmers don't know what the standard says, having been lied to about it being a simple and base language, they're offended when they do something they never should've done; they shouldn't be using C anyway, however.
Abstract language details are necessary for a high-level language and can work quite well if the language is designed well; this then leaves high-level features to be implemented in whichever way is best for the machine; the C language doesn't do this well at all, however, and precisely specifies the nature of irrelevant details and so hinders the machine and implementation possibilities.
The C language doesn't even have true boolean values or arrays thereof. You're expected to use an entire integer that's zero or not and you're left to your own devices if you want an array of these values that isn't grotesque in its wastefulness. Meanwhile, most proper languages have the concept of types that only have two values and can easily use an underlying machine representation for efficiently representing these, without involving the programmer.
In closing, you may argue that C is necessary because it permits specifying these low-level details, albeit required in every case instead of only where necessary. To that, I direct you to look at Ada, which permits the programmer to ignore such details wherever unneeded, and so leave them to the compiler’s discretion, but allows size, address, representation, bit-level organization, and more to be specified in those cases where it's truly necessary.
Here's a link others may like for learning more about Ada and the deficiencies of C:
https://annexi-strayline.com/blog