I've been seeing this pattern of text crop up in many places. On LinkedIn, much of my feed is filled with posts of short sentences that follow this exact pattern. What's more, even the replies are obviously AI-generated.
I hear people talk like this on the phone. The one I hear a lot is: "It's not about X, it's about Y1. It's about Y2. It's about Y3." Where Y is usually something humanizing.
One thing LLMs are surprisingly bad at is producing correct LaTeX diagram code. Very often I've tried to describe in detail an electric circuit, a graph (the data structure), or an automaton so I can quickly visualize something I'm studying, but they fail. They mix up labels, draw without any sense of direction or ordering, and make other errors. I find this surprising because LaTeX/TiKZ have been around for decades and there are plenty of examples they could have learned from.
Not just too much stuff IMO. I kind of like all the features.
The main problem in my eyes is not enough volunteers (although they are doing a superhuman effort) to get it into the production level it needs to get more widespread adoption. The other problem is that Python already has a huge amount of libraries and is considered to be "good enough" feature wise, so it's hard to attract interest.
I do enjoy reading Raku code and think it is super neat as this do it all post-modern language. Inertia is hard to overcome though.
Early on, there was some attempt at syntactic macros. I tried it. But it didn't work out. I hear there are efforts for another iteration. That would be just fantastic when it lands.
I’m in the same boat. I’ve internalized Vim keybindings so much that there’s no friction between thinking and doing on the screen. If I want to place the cursor on the next line, move to the end and add a semicolon, then jump to the end of the file, I just do it. My pet theory is that because Vim keybindings are unintuitive, developing proficiency required building muscle memory, which offloads cognitive load from my brain to my fingers so text editing becomes mechanical rather than cognitive.
I’m sorry, but any non-trivial Zig code gives me PTSD flashbacks of C. I don’t understand who Zig is targeting: with pervasive mutability, manual allocation, and a lack of proper sum types, it feels like a step back from languages such as Rust. If it is indeed a different way to write code, one that embraces default memory unsafety, why would I choose it over C, which has decades of work behind it?
I love Zig precisely because it is so similar to C. Honestly, if you don't like C, I can totally understand why you wouldn't like Zig. But I love C, and I love Zig.
Zig has become my go-to for projects where I would previously have reached for C, largely because Zig has such good compatibility with other C projects.
Rust, on the other hand, is a completely different beast. It is very different from C, and it is far more complicated. That makes it harder to justify using, whereas Zig is a very easy choice as an alternative to using C itself.
C is entirely as complicated as Rust, if your goal is to write correct software that doesn't crash all the time. It's only a syntactically simple language. Actually making anything interesting with it is _not_ simple.
Quite right. I have 35 years of C under my belt. I can write it in my sleep.
But even so, I can't for the life of me write C code that's as safe as Rust. There are just too many ways to make subtle little mistakes here and there, incrementing a typed pointer by a sizeof by mistake thinking it's a uintptr_t, losing track of ownership and getting a use-after-free, messing up atomic access, mutex deadlocks oh my...
And that's with ALL warnings enabled in CLANG. It's even worse with the default warnings.
It depends on the project. Most of the projects I write in C are very simple, and getting them to work reliably is really not a problem at all.
If you are writing more complicated or "interesting" programs, then I agree, C doesn't give you a good set of tools. But if all you are writing is small libraries or utility programs, C is just fine. In these cases, Rust feels like pulling out a sniper rifle to shoot a target a meter in front of your face (i.e., overkill).
If you are writing complex, large, or very mission-critical programs, then Rust is great to have as a tool as well. But we don't have to take such a black and white view to think that Rust is always the best tool for the job. Or C or Zig or whatever languages for that matter.
I also write C all the time, and it does not crash. There are certainly memory safety concerns with C, but there are also certainly many programmers that can write C code that does not crash all the time.
Bias is a good keyword with respect to CVEs. As long as there is not much Rust code which is relevant to my daily life I think this is not comparable. And the few Rust packages which now ended up on my system, see no regular security support because they pose a maintenance burden, so actually make me less safe: https://www.debian.org/releases/trixie/release-notes/issues....
But the original claim was that "C code crashes all the time" which is blatantly wrong.
To be precise, it was "C is entirely as complicated as Rust, if your goal is to write correct software that doesn't crash all the time." and I think we wouldn't have this discussion if it were uncontroversial. As somebody writing C code and managing a team that writes C code, there is not a particular high effort needed to make C software not crash. It may be too easy to write messy C code that crashes all the time, but this is not at all the same thing.
> writing C code that does not crash all the time is significantly harder/expensive
This is just plain not true. The fact of the matter is that if you stick to good practices, writing C code that does not crash under regular usage is not at all difficult. The problem is that writing C code that is guaranteed not to contain memory issues is extremely hard. But writing programs that don't crash "all the time" is not at all difficult.
This is why I can understand the push to use memory-safe languages to avoid memory safety issues in critical or widely-relied-upon programs. But the main reason you are using it in these cases is to avoid memory safety bugs, not to help you write programs that don't "crash all the time". And even then, the main incentive is that memory safety bugs can be quite severe bugs in areas like networking code, where they might become a significant security risk. The crashes aren't even the main concern here.
It is also not "extremely difficult" to avoid memory-safety issues in most code, although I agree that Rust has a clear advantage. Essentially you need to have a clear policy on memory ownership and avoid pointer arithmetic by using safe buffer and string abstractions. That this often not done in practice is the issue, but I think the narrative that it is impossible in C or "extremely difficult" is more harmful than good as it shifts the blame to the language and rejects responsibility for sloppy or lazy code.
Easier said than done. In the real-world, in real projects, sustaining zero memory-safety bugs in large C codebases is exceedingly rare. Microsoft and Chrome have each reported that ~70% of their serious security bugs are memory‑safety issues, and curl attributes about 40% of its vulnerabilities to using C. Memory safety problems are really hard to avoid in practice in large C codebases. You can't just blame developers.
And, like what I was referring to, it is even more difficult to prove the absence of memory safety issues entirely. We have only managed to actually prove it for a handful of non-trivial programs, like the seL4 microkernel.
Now, this is all an entirely different question to whether the extra work required to write your program in Rust to avoid memory safety problems is actually worthwhile. If you are writing a program with no networking code, no privilege escalation, and no confidential information, the answer is probably that it doesn't matter. If a game has a buffer overflow in some weird edge case, it doesn't really matter. If your data processing code has a problem, you can probably spot that and it probably won't lead to any security concerns. If your file system scanner runs into a memory safety issue, it probably won't negatively impact you that much.
But if your crypto library has memory safety problems, you are in for a bad time.
The real-world is complex with many trade-offs. The real question if in a 1:1 comparable situation and using similar efforts, you could achieve good memory safety in C. I believe this to be the case. I think the statistics we have seen are highly biased and partially misleading and the actual differences in the number of CVEs have many reasons (including legacy code, priorities, usage scnarious, culture etc). I mean, why even mention Curl, a project with portability requirements so extreme that it sticks to a long obsolete C version (30 years!). Proving the absence of memory safety issues entirely may indeed be harder, but ensuring a reasonable safety level is quite possible in my opinion. One should also point out that only safe Rust has guaranteed absence of memory safety issues, but it is Rust - and not safe Rust - that is competing with C.
When a project grows in complexity, age, number of contributors, poor review culture, complex requirements, or any of 101 different things that can make a project hard, then it is hard to avoid memory safety bugs. This covers like 99% of non-trivial projects.
If your software projects are very simple, then it is easy to write simple C programs that do the job well. This is what I said before. If your project is simple, boring, and straight-forward, using C is just fine. It is complex projects where the use of C can become a problem (and complexity can sneak up on you from an unbelievable number of sources).
I would not say we agree with respect to your last point. I think also very complex C programs can be made memory safe, when this is a design goal from the beginning. That complexity can make this harder is true also for Rust, where people then often use unsafe, or, alternatively, re-engineer large parts of their project to get the structure right. C gives you the same choice at this point, but it may be more common to pick the unsafe path because memory safety is not valued high enough to justify the refactoring cost, so people often accept safety issues instead of fixing the design issues in the program.
I don't think a 100-line function signature is representative, but I will point out that the alternative is at least 100 lines of runtime checks instead. In both cases, what a nightmare.
To me that's more an indictment of Diesel than of Rust. I've been using sea-orm for a project I'm working on, and my (generic) pagination function is a hell of a lot simpler and readable than that one.
Typing code from hell for sure, but how would you write an API with the same guarantees in C? Some kind of method specific struct that composes all other kinds of structs/unions to satisfy these requirements?
This is an extremely generic interface to some meta magic DSL. It's complex but not really that complicated and yeah, it's going to be a bit long. But that's going to happen in every language where you rely on types for early validation.
Yuck. I thought some of the signatures you end up with when building “Modern C++” in the Andrei Alexandrescu style were hairy, but this looks sick. Not in a good way.
Probably does something cool for all that crazy though?
Every requirement on the types is commented on why it's necessary.
This is a generic method in the middle of some database DSL code that does a bunch of SQL operations on a type safe manner. Code like this takes "SELECT ?+* FROM ?+* WHERE ? ORDER BY ?+* LIMIT ? OFFSET ?", specifically the limit and offset part, and returns a type that will always map to the database column. If the query is selecting a count of how many Foo each Baz references, this will map to a paginated Foo to Baz count type.
The alternative is to manually write this stuff out in SQL, then manually cast the right types into the basic primitives, which is what a language like Zig probably does.
You'll find similar (though sometimes less type-safe) complex code in just about any ORM/DSL, whether it's written in Java or PHP.
I don't think you can accomplish this in C without some kind of recursive macro parser generating either structs or maybe function pointers on the fly. It'd be hell to make that stuff not leak or double free memory, though.
Better default integer type casting, ability to choose between releaseSafe/releaseFast
And probably other things.
As for comparison to Rust, you do want very low level memory handling for writing databases as an example. It is extremely difficult to write low level libraries in Rust
I think the argument is that it is also extremely difficult to write low level libraries in Zig, just as it is in C. You will just only notice the difficulty at some later point after writing the code, potentially in production.
Did you write any Zig code yet? In terms of enforced correctness in the language (e.g. no integer promotion, no implicit 'dangerous' casts, null-safety, enforced error handling, etc...) and runtime safety (range-, nullptr-, integer-overflow-checks etc...), Zig is much closer to Rust than it is to C and C++.
It "just" doesn't solve static memory safety and some (admittedly important) temporal memory safety issues (aka "use-after-free"), but it still makes it much harder to accidentially trigger memory corruption as a side effect in most situations that C and C++ let slip through via a mix of compile errors and runtime checks (and you get ASAN/UBSAN automatically enabled in debug builds, a debug allocator which detects memory leaks and use-after-free for heap-allocations (unfortunately not for stack allocations), and proper runtime stack traces - things that many C/C++ toolchains are still missing or don't enable by default).
There is still one notable issue: returning a reference to stack memory from a function - this is something that many unexperienced Zig programmers seem to stumble into, especially since Zig's slice syntax looks so 'innocent' (slices look too similar to arrays, but arrays are values, while slices are references - e.g. 'fat pointers') - and which IMHO needs some sort of solution (either a compile time error via watertight escape analysis, or at least some sort runtime check which panics when trying to access 'stale' data on the stack) - and maybe giving slices their own distinct syntax that doesn't overlap with arrays might also help a bit.
I mean, there's no question that Zig, also in its current state, is vast improvement over C or even C++ - for the "small stuff". It is much more pleasant to use.
But there is still the "big stuff" - the things that have a fundamental, architectural impact. Things like: Will my program be multithreaded? Will I have many systems that interact? Will my program be maximally memory-efficient? Do I have the capacity (or money) to ensure correctness if I say "yes" to any of that?
The most important consideration in any software project is managing architectural complexity. Zig is better, yes, but not a paradigm shift. If you say "yes" to any of the above, you are in the same world of pain (or expenses) as you would be in C or C++. This is the reason that Rust is interesting: It makes things feasible/cheap that were previously very hard/expensive, at a fundamental level.
But it doesn't have to be and it shouldn't. Rust also isn't a paradigm shift, it "just" solved static memory safety (admittedly a great engineering feat) but other languages solved memory safety too decades ago, just with more of it happening at runtime.
But in many other areas Rust copied too many bad ideas from C++ (and many of those "other things" Zig already does much better than Rust - but different people will have vastly different opinions about whether one solution is actually better than another - so discussions about those features usually run in circles).
There shouldn't be a single language that solves all problems - this will just result in stagnation, it's much better to have many languages to pick from - and even if they just differ in personal opinions of the language author of how to do things or entirely subjective 'syntax sugar' features. Competition is good, monocultures are bad.
> The most important consideration in any software project is managing architectural complexity
No language will help you managing "architectural complexity" in any meaningful way except by imposing tons of arbitrary restrictions which then get in the way for smaller projects that don't need much "architecture". We have plenty of "Enterprise-scale languages" already (Java, C#, Rust, C++, ...), what we need is more languages for small teams that don't get in the way of just getting shit done, since the really interesting and innovative stuff doesn't happen in enterprise environments but in small 'basement and bedroom teams' :)
You put "just" in scare quotes, but that word does a lot of heavy lifting there. Static memory safety is an extremely useful thing, because it enables you to do things competent programmers would never dare in C, C++, or Zig. Things like borrowing data from one thread's stack in another thread, or returning anything but `std::string` from a function. These things were simply not feasible before without a huge bulky runtime and GC.
Keep in mind that Rust's definition of "memory safety" covers much more than just use-after-free, the most important being thread safety. It is a blanket guarantee of no undefined behavior in any code that doesn't contain the word `unsafe`. Undefined behavior, including data race conditions, is a major time sink in all non-hobby C or C++ projects.
What bad ideas from C++ did Rust copy, in your opinion? I'm really not sure what you mean. Smart pointers? RAII?
There are plenty of languages that enable quick iteration, prototyping, or "just getting shit done". If that's what you need, why not use them? I'm personally more concerned about the finished product.
You know, I'm beginning to understand why people complain about the "Rust Evangelism Strike Force". Can we discuss a language without the constant "But why not Rust instead?!", pretty please?
What are you saying? Do you think I was sent here by some sinister cabal that organizes an effort to direct any discussion about programming towards Rust?
...I don't use them as "scare quotes", it's more like in "can't you just..." - e.g. something that looks simple from the outside but is hard to do / complex on the inside - e.g. I do recognize the work that went into Rust's memory safety, but I question the effort that went into it compared to more traditional memory safety methods, especially when looking at the restrictions that Rust imposed on the programmer - it's a pretty hefty tradeoff (IMHO of course).
> What bad ideas from C++ did Rust copy, in your opinion?
Mainly doing things in the stdlib that should be built into the language (e.g. Option, Result, Box, Cell, RefCell, Arc, and probably a dozen other types and traits...), resulting in what I call 'bird droppings syntax' of too many chained function calls to get to the thing you actually want (.unwrap, .into_iter, .iter, .iter_mut, .as_ref, .as_mut, .expect, .unwrap_or_else, .unwrap_or_default, .ok, .ok_or_else, .and_then, .or_else ... like, wtf?). The absurd amount of `::` and `<>` in typical Rust code. The missing separation line between stdlib and language (like for-loops using the Iterator trait, or more obviously: operator overloading). The stdlib doing memory allocations behind your back through a global allocator - which we know from C++ do be a really bad idea for decades already... etc etc... I think most Rust programmers are blind towards those issues the same way that C++ programmers are blind towards C++ issues (which is another thing both language ecosystems have in common though).
I mean, there's no winning here. Either the language is too complex and does too many things, or it's not complex enough and relegates fundamental things to the standard library.
I don't thing there is any substantial difference between `Option<Thing>` and `@Nullable Thing` or `Thing | null`, I don't think there's anything wrong with choosing `::` over `.` for namespace resolution (it means you can have local variables with the same name as a module), and you have to have some way to declare generic parameters.
Rust generally does not allocate behind your back, but custom allocators is a work in progress. The reason it takes time is precisely that they want to avoid the mistakes of C++. A couple of mistakes were already avoided - for example, async/await in Rust does not allocate behind your back, while C++ coroutines do.
> I don't thing there is any substantial difference between `Option<Thing>` and `@Nullable Thing` or `Thing | null`
I object to @Nullable and similar arrangements as a magic special case. If the sum types only solved this one issue then it's a wash but they do a lot more too.
Either of the sum types, the concrete `Option<Thing>` or the ad hoc `Thing | null` are OK because they're not magic, less magic is better.
I’m confused. You seem to think Option is magical? It is not, and neither is Result. They are regular sum types defined in the standard library, nothing special about them.
That's certainly not what I was trying to get across. Perhaps I wrote something confusing, for which I apologise, but, since we're here anyway...
Technically Option is actually magic, though it's for a subtle reason unconnected to the current topic. If you go read its source Option is a langitem, that is, Rust literally isn't allowed to exist without this type. Rust's core libraries are defined, so you shouldn't and most people never will use Rust without them, but the Rust language actually doesn't require that all of core exists, it does require a handful of types, functions etc. and those are called "langitems".
So, why is Option a langitem? Well, Rust's language has for-each loops. But what it actually does (there's literally a compiler step doing this) is treat those loops as if they'd been written as a slightly clunky loop { } block making and then consuming an Iterator. To do that the IntoIterator and Iterator traits must exist, and further as the return type from the next call needed in Iterator is an Option the Option generic type must exist too!
Technically this type wouldn't have to be called Option, the Rust compiler doesn't care what it is called, but it must exist or else the compiler doesn't know how a for-each loop can work.
Being a langitem means that the compiler can use it in desugaring, and `for ... in ...` happens to be syntactic sugar in Rust, just like `for (auto x: y) {}` is in C++. `Range` et al are also compiler builtins, because `a..b` desugars to that type. It doesn't imply that the type itself is a compiler builtin, for example.
Another example is the `Deref` trait, which roughly corresponds to `operator->()` or `operator*()`, or an implicit reference conversion. It is called implicitly so you can use `smart_ptr.foo` without special syntax for dereferencing.
I think I fundamentally don't understand why any of this is a problem?
I think maybe your fundamental misunderstanding was just a misreading of what I actually wrote?
I don't like @Nullable (or the ? syntax used in C# for example) because they're a special case magic. They handle exactly one narrow idea (Tony's Billion Dollar Mistake, the "null" pointer) and nothing else.
I prefer sum types - both Option<T> and T | null are syntax for sum types. The former, which Rust has, is an explicit generic type, while the latter is an ad hoc typing feature. I don't have a strong preference between them.
doesn't the llvm coroutines require c's malloc? this is part of the reason why zig scrapped async. i would suspect Rust's async/await does allocate behind your back
> I think the argument is that it is also extremely difficult to write low level libraries in Zig, just as it is in C.
This has been not my experience at all in the ~6 years I've been writing Zig. I started having very little experience writing C (<1000, lines all written while in university) and since day 1 Zig has been a tremendous improvement over it, even back when it was at version 0.4.0.
I'm informed by having shipped a lot of C++ code in my time, which has taught me a lot about actually delivering stable software. Being better than C is a very low bar here.
For me it was very difficult to make an io library on io_uring that is properly safe.
Also using arena and other special allocators in different sections of the program. While maintaining hard memory limits for different sections of the program.
These are possible to do in rust but it is very difficult for me so I decided to just not do it. Otherwise I have to spend 5x the normal amount of time to make sure the library cannot be misused by the user ever.
This is pretty pointless since I’m the only one who is going to use that code anyway.
Could be skill issue or w/e but I just find zig easier to make progress in
Zig is for people who want to write C, that's really it. It's not a replacement for C++ or Rust or Go or Swift or anything "serious".
As for why you would choose it over C, because C has too many problems for even the C lovers to ignore. Zig fixes a tiny amount of them, just enough to pretend it's not problematic, but not enough to be useful in any non-hobby capacity. Which is fine, very few languages do achieve non-hobby status after all.
Zig is a systems programming language. I think that's probably who it's targeting.
People do systems programming in rust, but that's not really what most of the community is doing. And it's DEFINITELY not what the standard library is designed for.
Web servers, games, and applications, that sort of thing.
Some people definitely do systems programming in, but it's a minority. The std library is not set up for it at all, you need something like rustix, but even that results in very unidiomatic ("unsafe") rust code.
In Zig it's all in the std library by default. Because it's a systems programming language, first and foremost.
Actually I was also under OPs impression... can you tell me few specific problems with using rust for systems programming? BTW, I have only ever done something that resembles systems programming in C.
Because Rust's standard library doesn't provide memory mapping you will need to use platform specific APIs.
In Zig it's exactly the same except that they decided to provide the POSIX platform specific APIs, which if you're using a POSIX system is I guess useful and otherwise it's dead weight.
It's a choice. I don't think it's a good choice but it's a choice.
Your question might hint at a questionable presumption. So let me answer your question with a question - Does one have to memory map in Rust? Perhaps there are alternatives available in Rust, that you are not considering.
I think you are moving the goal posts. You use the `memmap2` crate, or the `libc` crate if you want to be reckless about it. The question was how the standard library gets in your way, not whether it includes everything you need.
And I don't think that including every feature of every possible OS is a sensible position to have for a standard library. Or would you argue that it should also include things like `CreateWindowExW()`?
If all you use is the Rust standard library, you can be reasonably sure that your program works on all platforms, and memory mapping is something that is highly platform specific, even among POSIX-likes. I would not like to attempt designing a singular cross-platform API for it that has to be maintained in perpetuity.
(There are a few OS-specific APIs in the Rust standard library, mostly because they are required anyway for things like I/O and process management. But the limit has to be set somewhere.)
There is something remarkably beautiful about minimal websites that use primarily text, perhaps with one or two images, and only styles that enhance readability. This is unbeatable UX. Whenever I encounter sites like these, I envision an alternative universe where the internet remained as it was in the beginning: no commercial strings attached, lightweight pages on affordable hosting, and easily accessible information so that search engines actually work. The internet was one of our greatest creations, but we’ve since ruined it with our greed...
I've been using Kokoro TTS with the CLI app, audiblez, mentioned in the "Similar Projects" section of the README. The model is fast and delivers impressive quality for its small size. Some issues I have faced, however, are:
a) It doesn't distinguish periods at the end of sentences from the dots in abbreviations such as "Mr." or "Mrs." The result is an awkward pause between "Mr." and the name.
b) It doesn't handle ellipses well.
c) Words are pronounced the same way regardless of context.
I fixed that here: https://github.com/cpttripzz/audiblez
The main problem with Kokoro is how flat and lifeless it sounds. But it is very fast. I prefer Chatterbox tts but it is around 20 times slower and will not work without a GPU
Kokoro is small and fast because all the text -> phoneme conversion is done by “dumb code” and only the phoneme -> sound part is done using a neural net.
You can use an air purifier. The Hepa filters are effective in eliminating PM. Gases like NO2 and VOCs can be reduced with carbon filters. Make sure that your carbon filter is large and different get saturated too quickly.
In Paris a study showed +3 years of life expectancy for cyclists and +2 for public transport users, compared to car commuters. They correlated it with (not a surprise) the benefits of exercice. Sure the pollution effect is worse outside of your car but the gains of daily light exercise offsets the drawbacks of air pollution.