"Any sufficiently complicated C or Fortran program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp."
In modern world, any sufficiently complicated C or C++ program embeds a runtime of some higher level language. More often than not, that language is formally specified, well-supported, and fast.
Sometimes it’s indeed LISP like in AutoCAD, but more popular choices are JavaScript (all web browsers), LUA (many video games and much more, see Wireshark), Python, VBScript or VBA (older Windows software), .NET runtime (current Windows software and some cross-platform as well, like Unity3D game engine). These days, it’s rarely a custom language runtime, but it still happens, like Matlab.
Many of them are international standards, see ANSI INCITS 226-1994 for LISP, ECMA-262 and ISO/IEC 16262 for JavaScript, ECMA-334 and ISO/IEC 23270:2018 for C#. Lua and Python aren’t standardized, but even so, they both have a comprehensive formal spec.
> calling Python or JavaScript any efficient sounds a bit unwarranted
Both are much slower at number crunching compared to C or C++ but they aren’t that bad, either. Most JavaScript VMs feature a good JIT compiler. Some Python runtimes have JIT too.
> Consider any JavaScript desktop application, its power and memory usage.
There’re good ones, like VSCode. On average they’re indeed not great, but I think it’s just an unfortunate consequence of low entry barrier. It’s easy for inexperience people to get started with the technology. And the ecosystem is misjudged based on the output of these inexperienced developers.
Maybe having most of this stuff in c libs with scripts wrapped around them will make it easier to migrate. Keep the same py but swap out the lib from C to some rust that's still useful in a crate for pure rust projects.
I'm running VSCode right now with many tabs open and extensions running, and it's using less than 100mb of memory. Doesn't seem so bad to me
You know... any embedded programmer reading that comment is probably laughing hysterically. In most cheap or energy efficient microcontrolers, more than 4 Mb is considered a luxury.
There is no virtue in using less memory for the sake of it. If a desktop application is taking 100mb, you can have a lot of those running before modern boxes start to struggle.
* 32-bit vs 64-bit application(64 bit will bloat all pointers)
* Methods of loading and editing documents(modern editing attempts a lot of introspection based on highlighting syntax or project environment)
* Character encoding support(Supporting current Unicode rendering would almost immediately take you beyond 4Mb)
Interactive editing is a pretty memory-hungry task compared to a simple viewer or batch processor. There's more reason to keep things cached. If you actually go back to old text editor versions from the days of 4Mb desktops, you'll find yourself missing stuff. Not so much that you can't get by, but enough to give pause and consider taking the hit.
uh... is it ? no tabs open and less than 12 extensions, the code process itself takes 120 megabytes, and there's also 1.2 gigabyte of electron processes running along with it
More often than not? Almost none of the languages mentioned are "formally specified", and most of them are hardly fast either...
They all have written specs. Many of them even have these specs standardized, see ANSI INCITS 226-1994, ISO/IEC 16262 and ISO/IEC 23270:2018.
> most of them are hardly fast either
It’s borderline impossible to be fast compared to C or C++. By that statement I meant 2 things.
(1) They’re likely to be much faster compared to whatever ad-hoc equivalent is doable within reasonable budget. People spent tons of resources improving these runtimes and their JITs, it’s very expensive to do something comparable.
(2) On modern hardware, their performance is now adequate for many practical uses. This is true even for resource-constrained applications like videogames or embedded/mobile software, which were overwhelmingly dominated by C or C++ couple decades ago.
The only issue I have with C is that there are no good reasons for some of those missing features to be missing.
Take, for example, namespaces. Would it be a problem to implement them as, say, implicit prefixes?
Me I want range types like Ada. Real array types. I think I want blocks/coroutines.
aka CDC
#include <string.h>
__prefix__ str; /* in scope: "","str" */
strlen("Hi!"); /* try "strlen",done,ignore "strstrlen" */
len("Bye"); /* no "len",try "strlen",done */
__prefix__(foo_) { void bar(void); } /* "foo_bar" */Namespaces don't need to be mangled at all if they are interpreted as symbol prefixes.
I'd prefer that, say, namespace foo::bar resolved into foo_bar for all symbols (even that meant risking namespace naming collisions) to not having any support for namespaces in C.
In fact, this approach is already used to implement pseudo-namespaces, so that wouldn't be much of a stretch.
It seems like you want the language to be more complicated for no benefit. Why not use C++ at that point?
You're missing the whole point of namespaces. The goal is not to replace foo_bar with foo::bar. The whole point is that within a scope you can type bar instead of foo::bar, or bar instead of foo::baz::qux::bar, because you might have multiple identifiers that might share a name albeit they are expected to be distinct symbols.
using namespace kind::ofa::long_name;
or
using kind::ofa::long_name::bar;
is the point.
> a language which runs in a VM written in C [...] easily be used on any board with a C compiler with a small amount of setup, and C FFI is a first class citizen. Also coroutines
Use Lua. It has all of that already.
-Static types that match C for seamless interop.
-No GC
-First class actors
-Ahead of time declaration/allocation of actors and messages, with automatic async-like passing on a coroutine/actor waiting for an allocation, and automatic disposal of the actor after prolonged allocation failure.
-Hot swapping actors from a running system in the field
-Over the wire debugging and inspection of a running system in the field
AtomVM, an erlang VM for small devices is closer than LUA to what I'm looking for. However, I really want to create an environment made for embedded development, not try to tack a higher level runtime onto something like an ESP32 and have devices drop every 2 months from a memory leak.Rust using one of the actor libraries based on async, might suit embedded really well if cross platform support matures a bit more. Rust cross-compiling requires a C linker & compiler for the target platform but Rust doesn't respect the standard environment variables for setting them using LD/CC/CXX environment variables. Though it'd be really interesting to see if anyone can setup Rust to run on an embedded WASM to allow introspection / real co-routines. IMHO, that'd be awesome.
Currently I've settled on a Forth (in Forth style, an implementation I wrote https://github.com/elcritch/forthwith/) to give me an interactive environment without GC and stable timing (important!) with ability to add C function calls readily. Interactivity is big for me in the area I'm currently working in. Forth can easily be extended to have tasks / co-routines too, though I never tried implementing them. And of course, Forth macros are like exercises in puzzle solving.
AtomVM does look interesting, but early stage. Erlang VM actually matches embedded really well. The actor model in theory lets each process run it's own GC which makes the GC model much simpler than other dynamic languages. Modern OTP is large and not suited for embedded as you mention, but pairing it down to basic actors and processes would fit well on many modern embedded MCU's. Elixir and Nerves is great for SBC/Linux embedded computing and some boards like the Omega2/Licheepi Nano. There's also GRiSP (https://www.grisp.org/) that runs BEAM on top of RTEMS.
You can implement that for embedded systems too, but as there is no obvious best way to implement it (Von Neumann machine is so different) you'll constantly get annoyed if you are the type that likes to use the weakest hardware possible as different implementations have different costs and so you'll always be second-guessing the abstraction.
Also bitwise operators, but using functions instead isn't a huge problem (and supposedly 5.3 or so fixes that).
https://en.wikipedia.org/wiki/Forth_(programming_language)
also, system level REPL is some hardcore nerdity.
Incidentally, while Forth comes from the era of ALLCAPS language names, even its creator Chuck Moore calls it Forth: https://web.archive.org/web/20040131054056/http://www.colorf... ; and Lua never was spelled with all caps.
This is the entire reason for me. With the way IoT is blowing up C actually might be gaining market share. I've done my research and things like TinyGo exist, and you can sort-of compile Rust for microcontrollers if you use all of the right crates, but it feels pretty risky to do so.
You may want to check out Moddable's XS runtime[1], which is exactly that. It's written in portable C, and "XS in C"[2] makes it easy to interoperate with C code you may write. And even if you decide to roll your own runtime, there's tons to learn from the source code.
[1] https://www.moddable.com/faq.php#what-is-xs [2] https://github.com/Moddable-OpenSource/moddable/blob/public/...
I haven't gotten to building the VM yet, and I'm hoping to just use someone else's and then contribute the tools I need to their ecosystem.
On Windows any language able to speak COM can use it, regardless what language was used to create the COM component.
Same applies to mainframes and their language environments.
I personally only got in trouble in C when trying to be too clever.
The truth is that decades of projects written in C have clearly demonstrated that people can't write secure programs in C.
The whole idea that many eyes or 'safe' languages or some other magic bullet are going to solve this is so far off-base that it makes productive discussion impossible because everybody starts to focus on the particular tool at hand whereas the real problem is an instance of of the class 'architecture', not of the class 'tool'.
however i disagree with both of you that writing safe C is hard. most of the problems i see relate to incorrect pointer usage or memory management. use stack allocated containers from libs very well tested and pass references. this removes entire classes of bugs from popping up. one thing you can’t do with C is be lazy.
I do recall that in 1991, I was the only student in my "Introduction to Programming Using C" 101 class (as a Freshman in college) who could understand pointer arithmetic. That class ended the careers of many aspiring Computer Science majors.
I eagerly learned C++ a few years later. I did not understand at the time what shitpile OOP is. I was totally in OO because it was the "industry trend." Someday we'll fully recover from that entire folly.
I think, it even does a better job than C++ which share some of the C syntax.
The problem i guess is complexity and productivity. Zig here is a hit while Rust is a miss as much as C++.
The question Zig was trying to answer is: Can we have a simple, free and powerful language as C but with a more modern approch?
While Rust in its cruzade to be seen as a C++ competitor were not aiming at simplicity and user ergonomics.
So my feeling is, Zig is much more compeling as a C substitute than any other language out there, and probably thats the reason why your friend like it more than others.
Bookmarking that comment. Will totally quote that whenever the need arises.
It will explode and kill people eventually. That's a sure thing, no matter how good you are.
The only relevant question than is: Have you been still around or did you manage to find some safer workplace far away?
It will? Some of the stuff in this thread is really over the top.
Well there's your problem. Instead of thinking about your problem and devising a C solution, you resort to pounding the square peg into the round hole. Your problem isn't C, it's your proficiency at it. What's worse, instead of correcting said ignorance your solution is to produce more code using a new language. This only adds to the gross pile of trash that is every language/framework that tries to solve programmer ignorance and laziness with what amounts to wishful thinking. This is why software really sucks nowadays. Everyone wants results without reading the manual or putting in real effort. They want languages with built in hand holding and magic inference. That's not how any of this works.
I get it, programming and C sucks because it's so damn tedious. I suck at C too. But I actively study books and similar problems people already solved using the language. Programming is very hard. The best programmers I know are also very good with math and puzzles (e.g. Ken Thompson was a chess geek). They're puzzle solvers. They don't cheat and try to smash or duck tape the pieces together. They thrive on studying strategy meaning reading books, papers, and other people's code. Learn how to solve the puzzles strategically instead of fighting them.
When writing interrupt service routines for serial communications on an obscure architecture with multiple heaps (one 16 bit addressable and one 32 bit addressable), I could have written 2000 lines of assembly. Instead, I used a system of assembly macros and wrote about 300 lines of that.
When writing firmware in a C which lacked decent coroutines, I could have just made a giant while loop and put all of my logic in it. Instead, I wrote a quick implementation of coroutines, a scheduler, and a basic async/await implementation using the C preprocessor. This also saved thousands of lines of boilerplate code.
The fact that C has no good method of implementing a generic hashmap has nothing to do with my proficiency in the language. My proficiency in C also has nothing to do with my love of sweet, glorious type inference, or my deep felt appreciation for the conveniences modern IDEs and languages provide. Writing software has never been better!
Maybe I'm misinterpreting, but what I'm hearing is: "You don't need to use Vim to get more done, you just need to get better at typing. Not that I know anything about how fast you type." Or... you know, I could just use Vim.
That is not how your original post read to me. It sounded like you came from the dynamic/scripting language world and are trying to hammer those features into C. You sound quite proficient, I'm not trying to shit on you or anything. I'm tired, it's late, and no one cares but it sounds like you want something like an mbed that runs python or FreeRTOS? Why reinvent the wheel if someone already did this? Or is it simply that you're stuck using C on your "weird" platform? In that case, I'd say have a look at Nim, there's an embedded branch. It's a dynamic language that compiles to C89 so perhaps it's buildable on your platform. If it's a personal project then have fun.
Implementing cooroutines in C is pretty old hat: https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
If you just put together a linked list of structs which represent the routines, the time they last slept, and what they're last waiting on, you can just iterate through it and you've got most of the functionality of async/await. I never bothered to implement separate stacks and register restoration, opting to just use global variables for state that needed to be saved between awaits. It would have been neat to do that, but I think it would have turned an afternoon spent saving time into a multiday project, and left me permanently paranoid about corrupting the stack or registers. Would have been fun though.
That's actually how _all_ of this works. If we required everyone to handle the complexity of everything, we wouldn't be able to make technological progress. Yes, there's the tension (there's always a tension) between having a deep understanding of an underlying technology, and therefore be able to use it better, and trying to get to a point where you can get away with not understanding. But it's undeniably considered a success story in technology if the technology gets to a point where people can use it to basically its full potential, without needing to understand it.
C is basically it for embedded development though. I've gotten so tired of recompiling and waiting to flash a chip with C, that I've started learning ANTLR and making my own language. The idea is to have a language which runs in a VM written in C, and allows you to easily access code which has to be in C. Sort of like uPython, except it can easily be used on any board with a C compiler with a small amount of setup, and C FFI is a first class citizen. Also coroutines masquerading as first class actors with message passing, since I always end up building that in C anyway.