Types aren't a safety mechanism in C, they're an annotation for other programmers. There are no safety mechanisms in C, because there is no reason to have such a thing. C is the machine, and the machine's job is to do what you've written, even if you've written something stupid.
Even gcc's output is legible if you use -Os. So you look at the compiler's output, you look at C, one of C's really nice parts is that you can tell what the compiler's going to do while you're writing.
> why can't we have something like C but typesafe?
Okay, this is going to sound like sarcasm, but I am really asking a real question because I don't understand why you'd want that from C. What do you want a safety mechanism for? What does "safe" even mean? Safe from what? Again, real questions. In general, what would safety mean?
> D seems quite close
Fun language, I think I never picked it up because of some weird licensing thing they were doing with the compiler back in the day; I don't remember, though.
@p slices and bounds checking would be nice. Sure I can do that manually in C but, a toddler can do that. But it's nice not to have to do it and do other non-toddler things instead. Or, (de)referencing should be implicit in most cases. i should never have to write mystruct->deadcopsinmybasedment to access members of a struct. mystruct.deadcopsinmybasedment doesn't mean anything. or when passing something that's supposed to be a pointer then just pass it as a pointer.
@lucy I would like to be clear, because I shat a bunch of words onto the page and it's going to look argumentative: I don't think you're wrong in general; some of the specifics I disagree with. I do think some of what you want is wrong to try to get into C, but mainly I don't know what you want so I'm trying to figure that out.
:dmr: Dennis Ritchie had a proposal for variable-length arrays, but by the time he had the idea, it was already out of his hands and in the hands of the standards committee, and they hated everything he ever suggested.
> slices and bounds checking would be nice.
C doesn't have arrays; it has some syntax around pointers. If you try to give it "real" arrays, then the runtimes for all of these other dingus languages stop working, because sometimes what you want is a contiguous region of memory.
Maybe you have a contiguous region of memory (framebuffer) and you don't know how big it is at compile-time: now there's a runtime library the compiler has to hook into. The way this problem is solved in C is that you get a segfault: the OS has built-in memory safety. Or say you've got to call a special instruction to get the dimensions of the framebuffer stored in a register: if you couldn't fudge types in C, you'd have to implement most of that in assembly instead of just one or two instructions.
C is the machine, though, and the machine doesn't have bounds-checking because it doesn't have bounds. Sometimes it has an MMU, sometimes it has ridiculous segment registers and an A20 line and stuff like that, sometimes it has memory-mapped I/O registers. If what you want is a "real" array, you probably don't want C for this task.
> Or, (de)referencing should be implicit in most cases.
This would be a disaster for cases where you care about that kind of thing; for cases where you don't care and are fine with it being implicit, you should probably not use C.
A nice thing about C is that you can translate what you've written into what it's doing: you see an `->` and you know that there's a read. This matters when it's timing-sensitive (say, an :terry: interrupt handler :terrylol2:) or time-sensitive (factoring prime numbers). Importantly, it also matters when you are debugging, because you can see a pointer is being read through. A memory-safe language, you don't have that concern.
I had a bug a long time back: it was segfaulting...nowhere. Just initializing a variable that wasn't even a pointer. Pretty reliably, too: same function, same variable, every time. I blamed the compiler (gcc treats ARM like a second-class citizen still) and looked at the exact address. No arbitrary pointers being dereferenced, it was just pushing to the stack...just pushing to the stack. I followed the stack pointer around, expecting that it had been corrupted...somehow. Nope. I had linked against libSDL, this build of SDL linked against libpulse, the kernel defaulted to 16kB of stack per thread, libpulse was eating more than 16kB of stack just for having been initialized. (Giving it more stack via sysctl fixed it, telling SDL to use ALSA instead of Pulse fixed it, turning off sound fixed it, and that's what I eventually went with, because I didn't need sound.) This was a pain in the ass, cost me half a day, and it was one of the very few implicit mechanic. And, you know, you add n implicit mechanics, you get n! complexity. Bounds-checking doesn't save you from this kind of thing, and worse, this is stuff that you've got to worry about *somewhere*: high-level languages are going to have problems like this, and there has to be a region where you can debug it, there has to be something between the bytecode VM's runtime and the machine. If it's not C, then it's just machine code. There has to be a language that is just the machine: no more, no less. If this stuff worms its way into C, then there has to be something under C.
> or when passing something that's supposed to be a pointer then just pass it as a pointer.
C++ has references in declarations and they are a nightmare; you see codebases where the style guide forbids their use. It makes debugging a nightmare. `f(&x)` means you get to see right there that you're passing an address.
But this is a feature list. What is "safety"? Page faults don't happen? That's what I'm trying to get at; I think the machine is safe already as long as you don't try to eat any of its components and it doesn't catch fire. Like, it has to mean something; if it means bounds-checking, that's a feature: you must mean that you are safe from running off the end of the array or safe from page-faults, something.
> you can have both pointers and arrays in a language.
Sure. I mean, you can do memory-safe pointers. That's not quite what C has, though. If C were to start doing this, then low-level non-assembly would need a new language.
> bad code either not compiling successfully, or predictably failing at runtime.
I think it's still poorly defined.
> i mean if you try to do something your code isn't supposed to do.
This is an unsolved problem in computer science; it's just a matter of degree.
> decades of "just don't write bad code" didn't prevent people from writing bad code.
It wasn't supposed to. You can write bad code in *any* language: if you want your program to work, don't do that. There is no way to enforce this for other people's code. People will fuck it up. The only thing you have control over is what *you* write: don't fuck it up and you're fine.
> ada's contracts would be so nice to have in C.
I think if you want codified invariants in C, you use an assert() macro: that makes it fail predictably at runtime. People don't like assertions because they get abused for error-handling or people write assertions that have side-effects, and it's understandable, but the fact that someone else might fuck it up doesn't make a tool any less useful. assert() (or rolling your own version) gets you 90% of the way there, guard clauses cover the rest.
@p > C doesn't have arrays; it has some syntax around pointers. If you try to give it "real" arrays, then the runtimes for all of these other dingus languages stop working, because sometimes what you want is a contiguous region of memory.
you can have both pointers and arrays in a language.
> What is "safety" bad code either not compiling successfully, or predictably failing at runtime. and not when you try to do something illegal on the machine, i mean if you try to do something your code isn't supposed to do. decades of "just don't write bad code" didn't prevent people from writing bad code. ada's contracts would be so nice to have in C.
@p > Sure. I mean, you can do memory-safe pointers. That's not quite what C has, though. If C were to start doing this, then low-level non-assembly would need a new language.
I don't wanna introduce these things to C. I want a new language that does.
@p i want a language that allows me to write freestanding software that doesn't require an OS to already run, but at the same time provides features to write code that doesn't break as easily when you're doing something wrong. maybe i just want ada..
@lucy Well, if the requirement is that it can't depend on an OS existing, that narrows it way down. Maybe you do want Ada; maybe you would like to try Forth.
@lucy I was gonna suggest Objective C, unironically, because it seems like it'd give you most of the things you want (first-class strings/arrays, message-passing, etc.) but I don't think Objective C can be used without a kernel (though I'm not sure about that; I guess it depends on the runtime library).
It's kind of an astonishing language once you really *get* it. It's like, as expressive as Lisp, but it also is usable without an OS.
> what dialect would you recommend for that specifically?
I used gForth a while but I don't think I really understood Forth until I spent a day working through Jonesforth.
The thing about Forth is that it barely even exists and is kind of just a style of programming. (Chuck Moore didn't like the standardization very much, he felt like it missed the point.) That having been said, it's hard to grasp until you use it some, and an ANS Forth is probably your best bet at being able to understand and be understood or find documentation, so gForth is probably a good place to start. (Or just get to hacking on DuskOS. YMMV.)
That's Apple; the language exists independently of Apple, Apple just adopted it. (Strictly speaking, :next: adopted it and Apple acquired NeXT.) If it was just Apple, I wouldn't have suggested it.
> Didn't swift take over fully?
I think, even within Apple, Swift:ObjC::VB.NET:C++, but I don't follow what they're doing so closely.
> Originally developed by Brad Cox and Tom Love in the early 1980s, it was selected by NeXT for its NeXTSTEP operating system. Due to Apple macOS’s direct lineage from NeXTSTEP,[4] Objective-C was the standard language used, supported, and promoted by Apple for developing macOS and iOS applications (via their respective application programming interfaces (APIs), Cocoa and Cocoa Touch) from 1997, when Apple purchased NeXT until the introduction of the Swift language in 2014.
> Objective-C programs developed for non-Apple operating systems or that are not dependent on Apple's APIs may also be compiled for any platform supported by GNU GNU Compiler Collection (GCC) or LLVM/Clang.
@p@lucy pforth has been my favourite forth so far, easy to understand and some nice debugging words. Apparently it has also been used freestanding a lot
@lucy@Yoruka It has a runtime library like you'd expect from a language of its type, and you can use it for regular stuff; in a better world, it would have been what people used instead of C++, because it fits in the same places. If you mean Apple's stuff, sure, Apple has its own ecosystem that has diverged from OpenStep but the OpenStep stuff still works so you can even do full desktop GUI stuff with it and talk to the icon tray and all the stuff you expect. But you can just write a webserver in it or whatever. It's in gcc, and the full DE stuff is still available: https://en.wikipedia.org/wiki/GNUstep .
@lucy@netzsphaere.xyz@p@fsebugoutzone.org the answer that you'll be unhappy with is that all of that exists in C, it's called cpp and the cppstdlib. more seriously though, you should try writing 2024 standard cpp, it really is like a different language almost
@shibao@phttps://wiki.osdev.org/C++ certain features of C++ require a runtime, you'd have to disable them (or ship a freestanding runtime) for freestanding code. that is, code that runs on hardware (like a kernel) without an underlying OS.
@eris@p.enes.lv@p@fsebugoutzone.org yeah and my perception is that it's baked into the executable so it's fair to just consider that as part of your program, unless you're talking about dlls that you might need to execute the program.
i didn't understand what you meant by "it still is" but i get it now, you should read into the new module imports and all the other changes with the latest cpp definitions, they've been hard at work basically defining an entirely new standard library and conventions that give you the safety that you're looking for. even if you can still technically use a random naked pointer or other c stuff, i would argue that modern cpp gives you that security if you don't use the old c-style of doing stuff
You can probably live without stuff like runtime type information and exceptions in a kernel. What remains is trivial stuff like global constructors, stuff like file access which you will be implementing yourself anyways, and stuff that requires dynamic allocation, like std::vector, std::string, but those have template arguments for specifying custom allocators. And if you're not #includeing the specific headers, you don't need to support that shit ¯\_(ツ)_/¯
@eris@p.enes.lv@p@fsebugoutzone.org or like have you ever worked with a codebase that's used RAII instead of plain c stuff? if not then i can understand how it would feel that way
@lucy@Yoruka It's missing a bunch of shit that I use all the time. (`ssh -X`/`ssh -Y` is one. I don't know if VNC is still fucked on Wayland but I use VNC every day of the week.) If rio does $x and X11 does $x, I don't need a thing that doesn't do $x: it hasn't caught up to the 90s. Non-trivial cost of moving, it doesn't do things I want it to do, so I'd be heating up my GPU without a benefit: this is the definition of bloat.
You can say *anything* exists in C++ because there exists nothing that they wouldn't cram into it. It's like the Common Lisp of the ALGOL family, it's like compiled Perl.
I obviously don't have much experience in testing the entire stdlib, but yes, AFAIK, a lot of it is templated and concepted magic which should Just Work(R)
@shibao@eris@lucy But the guy keeps calling it "cpp" and the C Pre-Processor is already called that. People that are concerned about "+" being a special character usually call it "cxx".
Back in the late 1990s and early 2000s, fpc's advocates used to say it was "Pascal written in Pascal" as opposed to gpc, which was a Pascal front-end for gcc. But I still had a machine where Turbo Pascal 7 worked, so I didn't care.
@i@p i find pascal quite pleasant to look at, other than c :hehecat: im going for c rn and maybe replacing some parts in pascal to see how it goes and compare it better. my main concern is fpc being superglued to gcc but apparently you can use it with llvm since very recently? I'd have to check that first.