quick qn ? for the tinkerers -- is there a language these days that nicely interfaces with c i.e able to use all c libraries through ffi. without loss of performance or extra fu.
the language being small enough that all basics can be grasped in a day.
the language being complete that it will remain the same in 10 years.
while at the same time being memory safe.
btw I don't think golang applies given the bad ffi story in go.
---
edit btw:: yeah this implies the use of a GC. though it must not have massive pauses or stop the world GC.
No there really isn't. The closest thing is "Rust after you've already gotten over the learning curve", but I realize that that learning curve is why you phrased your question the way you did.
Zig is aiming for what you're talking about, but it's not yet stable. They're interested in memory safety, but they don't want to add a borrow checker and they certainly don't want to add a GC, so my outsider guess is that they'll end up tolerating memory unsafety and trying to make up for that with debug modes and tooling. I don't really have a sense of what the end result will feel like, and the problems discussed in https://youtu.be/dEIsJPpCZYg make it sound like the basic semantics still have a ways to go.
Go could've been the language you're talking about if they'd given up on goroutines and just used the C stack, but goroutines are arguably the most important feature in the entire language, and it's not clear to me that there's a market for "Go but worse for network services and better for FFI". It would be hard to carve out a niche as a systems programming language that's great at making syscalls but can't realistically implement a syscall.
> No there really isn't. The closest thing is "Rust after you've already gotten over the learning curve", but I realize that that learning curve is why you phrased your question the way you did.
I vigorously deny this claim :-)
There's an easy-to-learn and powerful language implementation, which I mentioned above, that has seamless interop with C (to the point that you can include snippets of actual C code in the source code).
I've heard good things about Zig. Interop with C libraries seems to be good, and there is some degree of memory safety (though not, as i understand it, anything like .net/Java).
Zig's probably GP's best bet. Though its still developing rapidly, it sees production use already, so while it might be radically different in 10 years, it probably won't be gone.
> the language being small enough that all basics can be grasped in a day.
The basics, certainly. You can learn the basics of Lisp syntax in about twenty minutes, the basics of looping, conditionals, datatype definitions, function definitions and all basic stuff in about a day.
> the language being complete that it will remain the same in 10 years.
Mostly, yes. ECL has mostly been the same for the previous 20 years. I see no reason that it would change substantially in the next 20.
> while at the same time being memory safe.
Caveats apply here, due to how deeply ECL can hook into C code. Even if you're doing weird things in the C code, it's unlikely you'd accidentally run into problems.
> btw I don't think golang applies given the bad ffi story in go.
What bad ffi story? I've never tried to use the FFI in go, but I haven't heard particularly bad things about it. Of course, that could be because most Go programmers aren't using the FFI anyway.
My experience with CGo is limited, but I think the reasons it has a bad rap are that 1) the performance overhead is costly in some cases, cause you have to switch stacks(?), and 2) the way it's integrated with the language and the build is super hacky, which makes complicated cases more complicated.
If you meant a compiled language then you can write code that is memory safe in C. You can even run tools against your code to measure this in various ways.
All "memory safe" languages that compile to lowest level ISA code are just memory safe "by default" and all of them necessarily offer escape hatches that turn it all off.
No "memory safe" compiled languages offers memory protections beyond what the operating system provides. If it's within the memory space of the process you can access it without limitation. "Memory safety" can reduce your exploit surface but it can't eliminate it out of an incorrectly designed program.
There isn't a binary "memory safety" choice for a given language, but C is way off on the wrong end of realistically promoting the writing of memory safe code.
Yea, but at the end of the day, your software either has memory safety bugs or it does not. Presuming that the choice of language has the largest impact on this outcome is modern folly, I suspect.
I doubt your second sentence. Considering the prevalence of memory safety bugs in C/C++ code, when both Firefox and Microsoft report a figure of ~70% of bugs involving memory safety, generous deployment of tests, fuzzing, sanitizers, and linters entails a mix of not being a silver bullet and being cumbersome to use. On the other hand, many programs written in Rust, Go, Kotlin, etc. won't need escape hatches at all and likely won't have any memory safety bugs.
The problem with your point is that it's single ended, because the scale and scope of deployed Rust or Go software has not matched that of C/C++ software. We also don't have particularly good data on how many memory safety bugs are in a project with good deployment controls versus ones that aren't.
We also don't know how well tested any of the vulnerable Microsoft code actually was and so I'd be wary of drawing any broad conclusions across languages from that simple statistic. It's also likely self reported and not likely to be rigorously gathered for this type of analysis.
The fact that there's such a large difference between C/C++ projects with respect to historically discovered vulnerabilities to me suggests that it can't be down to the language but how the project deployments are engineered.
You're one unnoticed checkin of an "unsafe" construct in any of these languages away from having the dreaded memory safety vulnerability introduce itself into your project. Even worse, you could have a crate that has an unsafe block you didn't previously call, but a new checkin now calls this extant and disregarded method. So, what do you do? The language hasn't done anything for you here. Use an analysis and/or fuzzing tool? So, how are we anywhere different because of the language?
Even for Go, a language I love quite a bit, if you forget to synchronize shared maps with simultaneous reads and writes you're in for a panic, and possibly real safety bugs. The GC and the fact that "unsafe.Pointer" are "slightly hard" to use isn't a huge attribute as it leaves entire classes of bugs on the floor with the tines pointed straight up.
I think there is a strong culture in the Rust community to use `unsafe` carefully, somehow fostered by the overt advertisement, features, and/or design philosophy of Rust. The infamous actix-web debacle suggests that Rust users tend to be overzealous about avoiding `unsafe`, even. I think the design philosophy plays a big part to develop the culture: `unsafe` is less seen as the thing that only super hacker wizards use, and more as a tool that should be used judiciously but still out in the open.
So I suppose it's not literally just the Rust language itself, but given the context of Rust's development, there seems to be an intertwined culture that was more likely to arise than not.
> is there a language these days that nicely interfaces with c i.e able to use all c libraries through ffi
> the language being small enough that all basics can be grasped in a day.
That would be Zig. You can directly import C headers and compile C code with the Zig compiler and also cross-compile C code without requiring a separate compiler toolchain.
Currently it's also possible to compile C++ and ObjC (but not import C++ or ObjC headers), but that functionality will probably be delegated to a separate Clang toolchain in the future.
> the language being complete that it will remain the same in 10 years.
...that will take a while (also depending on whether you consider the stdlib part of the language or not).
> while at the same time being memory safe.
...that wouldn't be Zig then ;) (TBF, Zig is much stricter than C or C++, which helps to avoid some typical memory corruption problems in C or C++, but it's by far not as watertight as Rust when it comes to static memory safety - Zig does have a couple of runtime checks though, like array bounds checks - dangling pointers are still a problem though and are only caught at runtime via a special allocator.
They also wanted "without loss of performance" (compared to C, I think, based on the context), which also has tension with the other requirements. I don't think it's possible to make a memory-safe language that has easy C FFI with no overhead and doesn't require you to think about C stuff. The esoterica of C have to be addressed somewhere.
You can have fairly cheap (but not entirely free) runtime memory safety at interface boundaries in any language that supports arrays via "tagged index handles" (basically weak references which protect against dangling access). To be efficient this requires a specific module design philosophy though (you basically want to avoid converting between a handle and a pointer for each memory access, only at the interface boundary, and interfaces should be designed so that they avoid "high frequency functions" with handle parameters).
Interestingly this approach is also somewhat popular in Rust to workaround borrow checker restrictions.
The instant that you have hassle-free FFI, it seems like you've given up on memory safety. Heck, just yesterday I got a segfault in a Python project because a library that I pulled in was just a wrapper for a faulty C module.
You can have all the memory safety in the world within the bounds of your own language, but it mostly gives you an illusion of security if the common pattern in the community is to just wrap C libraries. Having FFI be a bit of a hassle can actually go a long way towards shaping the community towards stronger memory safety.
All points are subjective and many people would claim this is false for all bullet points.
> [x] nicely interfaces with c
Unfortunately, that's only if you can avoid D Strings. Otherwise, you'll need to use toStringZ which makes copies of each string to ensure they have a null terminator.
> [x] the language being small enough that all basics can be grasped in a day
I'm still learning new stuff after several weeks using D. The basics are indeed simple, but there's A LOT of stuff in D.
> [x] the language being complete that it will remain the same in 10 years (the 1.0 release was 23 years ago)
D is evolving slowly but evolving. With the new ideas about making parts of the stdlib GC-free and the borrowing concepts being slowly introduced, the language is changing... people are making a lot of pressure to add new "cool features" from other languages, like the recently accepted string interpolation proposal. It will not be the same in 10 years, but it's true that most of it will be unchanged.
> [x] while at the same time being memory safe.
D is not memory safe by default, you need to use `@safe` which is annoying because currently , a lot of the stdlib is not `@safe` (but it could be!). It's true it's much, much harder to mess up in D than in C, but compared to Rust, I think it's quite unsafe (which is why it's introducing borrowing, to catch more unsafety bugs).
> Unfortunately, that's only if you can avoid D Strings. Otherwise, you'll need to use toStringZ which makes copies of each string to ensure they have a null terminator.
There's nothing that would prevent them from using C strings. Since they want a safe language, I doubt this would be a reason they don't want to use D.
> I'm still learning new stuff after several weeks using D. The basics are indeed simple, but there's A LOT of stuff in D.
This is a bad question, because there really is no language in 2024 that you can learn everything in a day.
> D is evolving slowly but evolving.
Again, a bad question. Even C is evolving. The main complaint about D is that it isn't evolving fast enough, with too much emphasis on avoiding breaking changes. If they implement editions, it actually would work as OP wants, because code that compiles today will compile forever in the future.
C strings are just...bad, bad, bad. C++, D, Zig, Go, Rust have ALL decided to not use C strings as their primary string type. But converting is as simple as a function call. (And literals are null terminated)
What features of D are deep?
A feature like string interpolation is modest syntax sugar. The kind of change that takes 40 seconds to understand.
> Rust
Bwhahahaha if D is not simple or simple, IDK what to call Rust.
memory safety doesn't mean just one thing, but probably it requires either a lot of rust-like features, a tracing garbage collector, or automatic reference counting.
the language being small enough that all basics can be grasped in a day
that disqualifies taking the rust-like path.
able to use all c libraries through ffi. without loss of performance or extra fu.
that disqualifies most (all?) advanced tracing gc strategies
it must not have massive pauses or stop the world GC.
that disqualifies simpler tracing gc strategies
depending on what precisely you're looking for, it's possible it might be a pipe dream. but it's also possible you'll find what you want in one of D, Nim or Swift. Swift is probably the closest to what you want on technical merit, but obviously extremely tied to Apple. D and Nim strap you with their particular flavor of tracing gc, which may or may not be suited to your needs.
If you're willing to tolerate a GC, Gambit Scheme may be the closest. You can learn the basics of Scheme in a short time (but any programming language will take time to master). The C FFI is also pretty straightforward to use, but developing complete Scheme interfaces to large C libraries can get tedious.
Gambit is also reputed as the second fastest Scheme compiler out there; only Chez Scheme produces faster code.
the language being small enough that all basics can be grasped in a day.
the language being complete that it will remain the same in 10 years.
while at the same time being memory safe.
btw I don't think golang applies given the bad ffi story in go.
--- edit btw:: yeah this implies the use of a GC. though it must not have massive pauses or stop the world GC.