TLDR: The author discuss its subjectivity towards the language. In short, they're not a fan of how zig handles errors, some loop constructs and the language design regarding keywords and built-in functions. They will not use the language even though it comes with interesting innovations.
On the first two points, it's disappointing not to see a discussion on the goals of zig and why these choices were made [0]. Like any trade-off, there is a reason behind it.
The third point, which occupies the biggest paragraph, is somewhat irrelevant to me.
An interesting take but which remains at the surface. Might not be worth the 5 minutes it takes to read it.
why is this downvoted? I like the short description. I spent a few hours two weeks ago to walk through ziglang's tutorial(to see how fit it is to replace c/c++ for system programming), my summary so far is: interesting stuff, but not good enough for me to switch yet. Will be on my watch list for next few years.
Did similar thing with rust(ziglang to c vs rust to c++), decided to stay with modern c++ but will keep an eye on rust as well.
This was my first assessment for my own use as well. Seems very much a 'kitchen sink' language that has everything, but nothing in particular that draws me to it. If I had pick out one differentiator it would be that the weird case/camel-insensitivity makes integrating convenient.
if (optional_foo) |foo| {
doSomethingWithFoo(foo);
}
..could be flow sensitive with optional_foo being non-? inside the block like some languages have done.
Well the In-depth Overview ticks all my boxes giving Zig worth a deeper look:
> Zig 0.5.0 introduced async functions. This feature has no dependency on a host operating system or even heap-allocated memory. That means async functions are available for the freestanding target.
> Zig infers whether a function is async, and allows async/await on non-async functions, which means that Zig libraries are agnostic of blocking vs async I/O. Zig avoids function colors.
> The Zig Standard Library implements an event loop that multiplexes async functions onto a thread pool for M:N concurrency. Multithreading safety and race detection are areas of active research.
It's got really cool metaprogramming features too, if you like those. Kind of like C++ consteval/constexpr but on steroids. Language BDFL doesn't recommend using it in prod yet, but I've really enjoyed a couple of hobby projects.
As mentioned in a reply to your other post, Zig has no such feature except within number literals. `12345E04` is equivalent to `12_345e04`, but `identifierName` is wholly separate from `identifier_name`.
Note that a really common use case for assembly files (.S files) is to expect that the file be transformed with the C preprocessor.
It would be interesting to imagine a replacement with a rust equivalent but I can't help thinking that it's difficult or impossible to come up with an architecture / exec format independent replacement (other than m4). gas and cc1as support .macro directives - maybe that would suffice? But compatibility with existing assembly source files would suffer.
You could have a build.rs script preprocess them with the C preprocessor if you really wanted. Or write a proc macro implementing a limited C preprocessor... ugh
And the first example of using `catch` in the docs[0] does this. It may be useful to also use the non-error return value of `write` though, because partial writes will return an amount of written bytes less than the amount you asked to write. You need `writeAll` if you want to ignore this concern, and then you don't have to write `_ = ` because the non-error part of the error union is void (so you don't have to use it). Then you get
Sorry, I suppose you could infer that but it was not my intent. It was merely my suggestion that someone's new exposure to Zig might be 'tainted' by previous exposure to C++ syntax.
That's how I've always interpreted it unless its a convo about slices which are few. Everyone knows slices are the bees knees item 9, so not often does it need discussing.
One 'catch' that makes me uncomfortable with Zig is the camel/underscore-insensitivity. How do you find all references of a method? Does your editor/IDE know how to find writeAll when I search for references of write_all? Do you have lint rules that are enforced for a project's source?
Unless something has drastically changed since I last used Zig, it doesn't have the feature you're talking about except in the case of number literals. `write_all` is a completely different identifier from `writeAll`.
Correct, though the case insensitivity hasn't ever cause me issues in Nim. Searching is easy or at most takes a simple regex. It's actually saved me from a few dumb overshadowing issues (as in "you can't redefine 'is_active' see 'isActive' here").
Rust implements this at the library level via common crates like 'anyhow' and 'thiserror', on top of a tagged type and a standard "Error" trait. The latter was recently extended to allow for implementation of these features.
The error thing to me hints more at how people use errors in the wild than anything specifically about Zig per se. The example that comes to mind is propagating parsing errors from a recursive descent parser. Typically one just wants to unwind the stack with some user friendly string error message indicating what exactly went wrong, but philosophically speaking, a parse error isn't really exceptional, it's an expected code path for invalid input.
The way zig seems to think about errors is that early returns via `try` shouldn't be leveraged as a control flow mechanism to bail and bubble up values across the call stack. I think rather than saying why the error handling is done the way it is, it'd be more valuable if there were documentation on how one is supposed to go about coding to be able to use this bail-to-bubble-up-values pattern. Currently, the workaround is indeed somewhat verbose as it requires mimicking the `try` mechanism (and/or using some sort of global error store or whatever).
The problem (which is a deliberate design decision) is that Zig's error unions, which have special built-in support at the syntax level, are just tagged unions with an integer payload. In other words, when you return an error (either implicitly via `try` or directly with `return error.MyError`), that error payload is just an integer indicating which error was returned. So to use OP's parser example, there's not a built-in way to attach some sort of diagnostic info to the error itself, the way you would with, for example, python exceptions. Using the built-in syntax, you can't do the equivalent of `raise ParserException(token, line_number)` and then unpack that error later in your code to display a nice error message.
The workaround would be to store that info in some sort of global struct (which has all the usual drawbacks of global variables); add a context/diagnostics parameter to your function, or manually manage your own error union in userspace, which means you lose the nice `try` syntax.
The problem is that in other languages, it's common to do this sort of idiom
throw new Error("Expected foo, found bar at line " + line)
// ...then elsewhere
catch (e) {
log("In file " + file + ":\n" + e.message);
}
In zig, you can't attach arbitrary strings to errors because errors are effectively enums (in the sense of that constant names map exclusively to ints). You can only do this `try callMe() catch return error.Something` (The `return error.Something` part is zig's "equivalent" to `throw error`, but notice how I can't tack on the error message string to the error)
`try` only shortcircuits into the `catch return` expression for errors, but for cases like parsers you want to shortcircuit and bubble up error messages simultaneously. You can kinda do weird workarounds by having a pointer to an error field in your input struct and mutating that prior to returning an error value, and/or doing weird nullable-to-sentinel-value-promotion shenanigans with idioms like `callMeMaybe() orelse return someSentinel("Expected foo")` to simulate the early-return-from-expression semantics from `try callMe() catch return error.Something`.
If you want to handle the error and also bubble it up, maybe even changing the what error bubbles up, you can just return an error from within the catch block after doing whatever handling you want. Either the captured error or something else.
Specifically for recursive descent parsers, I pass around a reference to an regular struct that acts as an ErrorInfo object, and use that to pass diagnostic information up the stack. Control flow is still managed by the error returns, any additional info goes in the parameter.
There is (was?) a proposal to add that capability to the language but Im not sure it had much traction.
Yeah I think a lot of people have been settling for that pattern, but it's admittedly not ideal, in the same way that it's generally preferable to work with discrete values in a functional/pure fashion than shuffling values in and out of an out param list everywhere.
And a parse error should (I will argue) not be what Zig thinks of as an error.
There are languages where try/catch became in effect the poor man's coroutine, and it's doubly confusing with parser "errors" because this is not something we need to handle as equivalent to an actual error in our program. A parser error is normal control flow.
I would suggest that in Zig one might use suspend/resume to pass a parser error to something which prints an error, possibly returning with a 'fix' which lets parsing continue and maybe find more errors. https://ziglearn.org/chapter-5/
I agree that conflating errors with stack unwinding is an unfortunate reality of how exceptions work in most languages. I'm not sure if I agree that suspend/resume are good alternatives. Conceptually, they seem most similar to C's setjmp, which I think we all can agree is generally not the first tool of choice for pretty much anything that isn't a complete hackjob.
The other workarounds at least look somewhat transparent about their costs. Even continuation passing style might be something I could grok. But what is the cost of a suspension frame? I legitimately have no idea.
Another issue is that suspend/resume are conceptually highly procedural and I personally find it difficult to reason about in recursive contexts (e.g. can I/should I pass suspension frames around? What idiomatic idioms from other languages does doing such a thing map to? Do I need to manually allocate heap for recursion like I need to for async recursion? Is it reasonable to expect a e.g. golang person to be ok with that sort of stuff?)
It's also hard for me to tell if Zig's async mechanism is a good choice here, tbh.
Stackful asymmetric coroutines are a good choice, these are stackless but an error is one stack frame so it's unclear that's a problem in practice.
I shrug a little too much when it comes to Zig, although documentation and tutorials improve every time I come back to take a look.
My main point is that a parse error isn't a program error, even if it's implemented with exceptions unwinding the stack for one reason or another (and this should be avoided if possible).
I think more importantly, the error return mechanism in zig creates a trace, and for parser early returns you don't want a trace, so a 'richer' struct union mechanism makes sense.
I made a tiny roguelike game in Zig a few months back and was really impressed.
One thing I really appreciate about the language is the emphasis on keeping things simple. I heard someone put it really well yesterday: when you're programming in Zig, you spend your time tackling the original problem, not tackling the language.
Also, the article's complaints may be valid, but most of them are very superficial, which speaks to good language design, in my opinion.
Hmm, I didn't find that quite to be the case. I wrote a toy GPU-accelerated (using OpenGL via C) terminal emulator in Zig. My take is that I'll probably wait for at least a 1.0 before I start hacking my side projects in it again.
My main issue was around finding good documentation and (not-outdated) examples, which I guess just comes with using a bleeding-edge language. The biggest thing I find lacking is a "Learn Zig" book that takes you through the whole language. Sure, https://ziglearn.org/ exists, but it needs about 10 more chapters. Zig types can get somewhat complex, especially when interfacing with C, for example - I remember some difficulty deciphering those. For many things I ended up just reading Zig's source code itself, especially when looking up standard library stuff.
I mean I get it, who wants to write a book for a language whose features are unstable?
On the plus side, I agree that I fought Zig a _lot_ less than when I first started learning Rust. And I still fight Rust if anything involving generics and/or nontrivial annotations is involved.
D had its chance. It made the mistake of trying to be a paid language (like Rebol) and failed at it, because clearly unless you're target a niche but lucrative industry, languages with a paid compiler are mostly a failure in the era of GCC and co. It's too late to develop a significant community around D. Rust clearly got the community aspect right.
Rust is a failure because it takes an eternity to build projects, and is now infected by NPM-hell dependency management
Imagine you have to wait for hours for your tests to compile and then to run, and then your micro services to compile to deploy a security update for a major CVS
Rust is poorly designed with poor syntax with a poor foundation that can't scale in today day and age
I've been doing a lot of translating C to Rust lately, and the Rust variants are much cleaner and more explicit. Especially regarding namespaces (ie no need to name_space_name_every_data_structure), explicitly declaring array types and references of instead of using pointers, and state management.
There's perhaps some tiny kernel of truth in this, but as a generalisation it's obviously horribly wrong.
Imagine trying to rewrite GCC in Bourne shell, or trying to rewrite the Linux kernel as Java. The results are not going to "look better" they're going to be awful, these languages are a terrible fit for the problem.
What people keep finding with Rust is that it's a really nice language to write software you might otherwise write in C or C++. The defaults are correct, the tooling is great, the errors are superb, it's just a very nice experience.
That is like discussing about sports car, and someone telling that they managed to do the same route in a bycicle.
No designer, no localization workflows, no integration with UI/UX tooling, assistive tech stuck in the days Sun sponsored the project, no component ecosystem.
I can't say what you might call "a very nice experience" only tell you what my experience was like for me. Maybe you have examples of a "real" sports car GUI which you were able to re-write in Bourne shell using your preferred toolkit ? An HPC application which was a real joy to maintain once you'd converted it from C to Java ?
That's the thrust of what's being discussed here, rewrites to another language, the__alchemist says they rewrote from C to Rust and it made their code "much cleaner and more explicit", Shadonototra insists this would happen for any language, and I opined (with some practical experience) that this just isn't so.
Nice experience is using CUDA with NInsights, Unreal with Blueprints and C++ live coding/HotReload, QtDesigner/WPF Blend/SwiftUI/Cocoa, MetalKit and its GPU debugger.
Distributed computing stuff in Akka and Orleans.
HPC example? Plenty of stuff converted from Fortran/C LEP days into C++ at CERN during LHC rampup.
Rust in the worst case only requires recompiling a crate at a time, and in the best case you can enable incremental compilation. I don't find compiling any slower than C or C++. If you're endlessly recompiling the same thing because you build from scratch every single time you'll have that issue with any compiled language.
Also what dependency hell? Rust allows multiple versions of the same crate in the same binary so not everybody has to upgrade at the same time. Eliminates 99% of the hell for me. Cargo is awesome.
Zig and D comes at it from different ends. With D, it feels like the C replacement aspect of it is an afterthought, an add-on (I don't remember it being a big focus at all when I used it).
Zig aims to be a C replacement from the start, including being a much better toolchain for cross-compiling C code than any other C compiler.
For embedded development, which is what is relevant to me, I never found D a good option. If that has changed they need to work on the marketing.
As an object-oriented garbage collected language with various nice features, I don't see what sets it significantly apart from C# anymore. Well, you can compile proper binaries. But dotnet core interpreters seems to be spreading on our Linux boxes, so then being able to run the same .exe in Linux and Windows is actually a nice thing. Then again I'm not in the market for such a language, so I probably shouldn't comment.
D is a natural evolution of C, fixes its issues (bounds checking and use after free for example), and adds some niceties that makes it pragmatic and polyvalent on top of a solid alternative to MACROs and metaprogramming capabilities
You can do native system development, embedded development, high-level tasks thanks to the optional GC and it can also becomes a scripting language
Something you can't have with Zig, but that's not its goal anyways
Also D is one of the rare languages that maintains its own backend, its own compiler (with optimizations available!) and a community that grows organically without needing major corporations support, it is a true labor of love, and it still gets new features today (ImportC)
Why i stick with D? because of all of the above! it's an unmatched language, that compiles code SUPER FAST!
.. and the syntax remains similar to C/C++; no need to learn new syntax gymnastic
I get the impression that D has languished because it never placed itself as a language good for application development. In contrast, look where Pascal/Object Pascal (Delphi) went. When Pascal/Object Pascal got nudged out by C/C++ in system and embedded development, despite being and still is a strong alternative, it made itself useful in application development. IDE (Delphi & Lazarus), GUI framework (VCL and LCL), multi-OS apps, etc... It found a place to flourish, and is still being championed by various companies and taught in various school systems.
Where with D, it seems to just be sitting in a corner, waiting to be noticed as a C++ replacement. But, people are not checking for D and hearing little about it. There is a long list of interesting languages, but if people don't see an almost immediate ROI for learning them, they will just sit and collect dust. Even if a language gets a bit of publicity, it still takes luck, timing, or corporate interest to move up the ranks.
It all seemed like valid criticism to me. It wasn't at all pattern-matching to things they know, it was evaluating and critiquing in each in term, and preferring one or the other for various reasons.
"No idea though where pointer dereferencing as foo.* = 42" I have no idea either, but it does remind me of BLISS; I remember there being BLISS-10 (for pdp-10) and BLISS-11 (for pdp-11), came out of CMU. (Apparently there were even more versions https://en.wikipedia.org/wiki/BLISS )
All variables were pointers; and so a common BLISS statement would be:
.Z = .X + .Y which in 'C' would of course be z = x + y
I actually love the foo.* syntax. Think about it like this: if foo were a struct, then foo.x would give you the x field. But what if you want all the fields? Then you'd write foo.* -- a Unix glob!
Since variables are names of addresses, you have to de-reference the X and Y addresses, add them, and, (crucially), the result gets stored: in the place pointed to by Z --- you don't care what .Z is anymore, as you are about to overwrite it.
When you think of it that way, z = x + y seems 'wrong' because the meaning of a variable name is different on the LHS and the RHS of '='
Nyet, other guys change logo. Zig not yielding. Zig strong.
If start moving over anytime some fucker claims ownership of some symbol, you're gonna have a bad time. Much easier in the long term to stick to your guns (eh) and make it clear that you 1 - were there first and 2 - have nothing to do with those little сука
Given we have a tipi that has a symbol that looks like something some jack_ss German used, I agree. Being there first needs to be respected. Damned if you should let the evil doer win.
Interesting. Perhaps the writer might find Vlang (https://vlang.io/, https://github.com/vlang/v) to his liking. But many of these newer languages haven't hit 1.0 yet, so are in alpha and beta stages, so it's hard to say how the finished product will be embraced or how popular they might end up becoming.
In many cases, these languages are alternatives to C++ (because of how messy it has become) and are positioned as a kind of "next step evolution" of C that also makes interop with it easier. Though much older, we could put D in that category as well.
I don't think the audience of the newer languages is so much for hardcore C or C++ programmers. The newer languages would be more attractive to newer programmers, those coming from scripting languages that want to learn a compiled language, or older casual programmers actively looking for something different that still has C-like syntax. Otherwise, much older (and battle tested) Delphi/Object Pascal (which is about as powerful and as fast as C++) would be on more radars for switch-over, if not for the excessive C-like syntax bias.
75 comments
[ 2.6 ms ] story [ 127 ms ] threadOn the first two points, it's disappointing not to see a discussion on the goals of zig and why these choices were made [0]. Like any trade-off, there is a reason behind it.
The third point, which occupies the biggest paragraph, is somewhat irrelevant to me.
An interesting take but which remains at the surface. Might not be worth the 5 minutes it takes to read it.
[0] https://ziglang.org/learn/overview/
Did similar thing with rust(ziglang to c vs rust to c++), decided to stay with modern c++ but will keep an eye on rust as well.
I'll have to give Zig a read and make an actual assessment. Glad for the possibilities!
Well the In-depth Overview ticks all my boxes giving Zig worth a deeper look:
> Zig 0.5.0 introduced async functions. This feature has no dependency on a host operating system or even heap-allocated memory. That means async functions are available for the freestanding target.
> Zig infers whether a function is async, and allows async/await on non-async functions, which means that Zig libraries are agnostic of blocking vs async I/O. Zig avoids function colors.
> The Zig Standard Library implements an event loop that multiplexes async functions onto a thread pool for M:N concurrency. Multithreading safety and race detection are areas of active research.
> and I wish rustc would have a stand-alone assembly files support
Rustc now supports inline assembly and global assembly in Rust 1.59 (the very latest release). So this is now possible:
Which will cause asmfile.s to be assembled and included in the rust library.But also, I'd love to see support for C and assembly files in rustc.
It would be interesting to imagine a replacement with a rust equivalent but I can't help thinking that it's difficult or impossible to come up with an architecture / exec format independent replacement (other than m4). gas and cc1as support .macro directives - maybe that would suffice? But compatibility with existing assembly source files would suffer.
[0] https://nim-lang.org/docs/manual.html#lexical-analysis-ident...
WRT having error unions just be a userland tagged union type, here's a reason why we don't do that: https://ziglang.org/documentation/master/#Error-Return-Trace...
The way zig seems to think about errors is that early returns via `try` shouldn't be leveraged as a control flow mechanism to bail and bubble up values across the call stack. I think rather than saying why the error handling is done the way it is, it'd be more valuable if there were documentation on how one is supposed to go about coding to be able to use this bail-to-bubble-up-values pattern. Currently, the workaround is indeed somewhat verbose as it requires mimicking the `try` mechanism (and/or using some sort of global error store or whatever).
The workaround would be to store that info in some sort of global struct (which has all the usual drawbacks of global variables); add a context/diagnostics parameter to your function, or manually manage your own error union in userspace, which means you lose the nice `try` syntax.
`try` only shortcircuits into the `catch return` expression for errors, but for cases like parsers you want to shortcircuit and bubble up error messages simultaneously. You can kinda do weird workarounds by having a pointer to an error field in your input struct and mutating that prior to returning an error value, and/or doing weird nullable-to-sentinel-value-promotion shenanigans with idioms like `callMeMaybe() orelse return someSentinel("Expected foo")` to simulate the early-return-from-expression semantics from `try callMe() catch return error.Something`.
Specifically for recursive descent parsers, I pass around a reference to an regular struct that acts as an ErrorInfo object, and use that to pass diagnostic information up the stack. Control flow is still managed by the error returns, any additional info goes in the parameter.
There is (was?) a proposal to add that capability to the language but Im not sure it had much traction.
And a parse error should (I will argue) not be what Zig thinks of as an error.
There are languages where try/catch became in effect the poor man's coroutine, and it's doubly confusing with parser "errors" because this is not something we need to handle as equivalent to an actual error in our program. A parser error is normal control flow.
I would suggest that in Zig one might use suspend/resume to pass a parser error to something which prints an error, possibly returning with a 'fix' which lets parsing continue and maybe find more errors. https://ziglearn.org/chapter-5/
The other workarounds at least look somewhat transparent about their costs. Even continuation passing style might be something I could grok. But what is the cost of a suspension frame? I legitimately have no idea.
Another issue is that suspend/resume are conceptually highly procedural and I personally find it difficult to reason about in recursive contexts (e.g. can I/should I pass suspension frames around? What idiomatic idioms from other languages does doing such a thing map to? Do I need to manually allocate heap for recursion like I need to for async recursion? Is it reasonable to expect a e.g. golang person to be ok with that sort of stuff?)
Stackful asymmetric coroutines are a good choice, these are stackless but an error is one stack frame so it's unclear that's a problem in practice.
I shrug a little too much when it comes to Zig, although documentation and tutorials improve every time I come back to take a look.
My main point is that a parse error isn't a program error, even if it's implemented with exceptions unwinding the stack for one reason or another (and this should be avoided if possible).
One thing I really appreciate about the language is the emphasis on keeping things simple. I heard someone put it really well yesterday: when you're programming in Zig, you spend your time tackling the original problem, not tackling the language.
Also, the article's complaints may be valid, but most of them are very superficial, which speaks to good language design, in my opinion.
My main issue was around finding good documentation and (not-outdated) examples, which I guess just comes with using a bleeding-edge language. The biggest thing I find lacking is a "Learn Zig" book that takes you through the whole language. Sure, https://ziglearn.org/ exists, but it needs about 10 more chapters. Zig types can get somewhat complex, especially when interfacing with C, for example - I remember some difficulty deciphering those. For many things I ended up just reading Zig's source code itself, especially when looking up standard library stuff.
I mean I get it, who wants to write a book for a language whose features are unstable?
On the plus side, I agree that I fought Zig a _lot_ less than when I first started learning Rust. And I still fight Rust if anything involving generics and/or nontrivial annotations is involved.
Would you say it's as good or better than Lisp?
It is the perfect language, don't sleep on it!
Imagine you have to wait for hours for your tests to compile and then to run, and then your micro services to compile to deploy a security update for a major CVS
Rust is poorly designed with poor syntax with a poor foundation that can't scale in today day and age
Imagine trying to rewrite GCC in Bourne shell, or trying to rewrite the Linux kernel as Java. The results are not going to "look better" they're going to be awful, these languages are a terrible fit for the problem.
What people keep finding with Rust is that it's a really nice language to write software you might otherwise write in C or C++. The defaults are correct, the tooling is great, the errors are superb, it's just a very nice experience.
Maybe in a couple of years.
No designer, no localization workflows, no integration with UI/UX tooling, assistive tech stuck in the days Sun sponsored the project, no component ecosystem.
That's the thrust of what's being discussed here, rewrites to another language, the__alchemist says they rewrote from C to Rust and it made their code "much cleaner and more explicit", Shadonototra insists this would happen for any language, and I opined (with some practical experience) that this just isn't so.
Distributed computing stuff in Akka and Orleans.
HPC example? Plenty of stuff converted from Fortran/C LEP days into C++ at CERN during LHC rampup.
My little part was in Atlas-TDAQ HLT.
Also what dependency hell? Rust allows multiple versions of the same crate in the same binary so not everybody has to upgrade at the same time. Eliminates 99% of the hell for me. Cargo is awesome.
Zig aims to be a C replacement from the start, including being a much better toolchain for cross-compiling C code than any other C compiler.
For embedded development, which is what is relevant to me, I never found D a good option. If that has changed they need to work on the marketing.
As an object-oriented garbage collected language with various nice features, I don't see what sets it significantly apart from C# anymore. Well, you can compile proper binaries. But dotnet core interpreters seems to be spreading on our Linux boxes, so then being able to run the same .exe in Linux and Windows is actually a nice thing. Then again I'm not in the market for such a language, so I probably shouldn't comment.
D is a natural evolution of C, fixes its issues (bounds checking and use after free for example), and adds some niceties that makes it pragmatic and polyvalent on top of a solid alternative to MACROs and metaprogramming capabilities
You can do native system development, embedded development, high-level tasks thanks to the optional GC and it can also becomes a scripting language
Something you can't have with Zig, but that's not its goal anyways
Also D is one of the rare languages that maintains its own backend, its own compiler (with optimizations available!) and a community that grows organically without needing major corporations support, it is a true labor of love, and it still gets new features today (ImportC)
Why i stick with D? because of all of the above! it's an unmatched language, that compiles code SUPER FAST!
.. and the syntax remains similar to C/C++; no need to learn new syntax gymnastic
Where with D, it seems to just be sitting in a corner, waiting to be noticed as a C++ replacement. But, people are not checking for D and hearing little about it. There is a long list of interesting languages, but if people don't see an almost immediate ROI for learning them, they will just sit and collect dust. Even if a language gets a bit of publicity, it still takes luck, timing, or corporate interest to move up the ranks.
I don’t think this has any value.
(Not that there might not be valid criticisms of zig or insights into its value... But this article doesn’t contain them.)
All variables were pointers; and so a common BLISS statement would be:
.Z = .X + .Y which in 'C' would of course be z = x + y
Z = .X + .Y
Since variables are names of addresses, you have to de-reference the X and Y addresses, add them, and, (crucially), the result gets stored: in the place pointed to by Z --- you don't care what .Z is anymore, as you are about to overwrite it.
When you think of it that way, z = x + y seems 'wrong' because the meaning of a variable name is different on the LHS and the RHS of '='
If start moving over anytime some fucker claims ownership of some symbol, you're gonna have a bad time. Much easier in the long term to stick to your guns (eh) and make it clear that you 1 - were there first and 2 - have nothing to do with those little сука
In many cases, these languages are alternatives to C++ (because of how messy it has become) and are positioned as a kind of "next step evolution" of C that also makes interop with it easier. Though much older, we could put D in that category as well.
I don't think the audience of the newer languages is so much for hardcore C or C++ programmers. The newer languages would be more attractive to newer programmers, those coming from scripting languages that want to learn a compiled language, or older casual programmers actively looking for something different that still has C-like syntax. Otherwise, much older (and battle tested) Delphi/Object Pascal (which is about as powerful and as fast as C++) would be on more radars for switch-over, if not for the excessive C-like syntax bias.