It is explained on their official page: https://ziglang.org/learn/overview/#integration-with-c-libraries-without-ffibindingsI hear this a lot. But looking through the docs, I just don't see how all that boilerplate could be easier:
https://ziglearn.org/chapter-4/
For example this wrapping example may look easier than i.e Java JNI but it is still a massive waste of time when you could just use C or C++ and avoid this time consuming, error prone step entirely. I must be missing something because Zig does embed a C compiler in it, it just doesn't seem to use it well?
So on that very page, you have some "binding glue" function such as this:It is explained on their official page: https://ziglang.org/learn/overview/#integration-with-c-libraries-without-ffibindings
This Zig code is significantly simpler than the equivalent C code, as well as having more safety protections, and all this is accomplished by directly importing the C header file - no API bindings.
Zig is better at using C libraries than C is at using C libraries.
fn sio_err(err: c_int) !void {
switch (err) {
c.SoundIoErrorNone => {},
c.SoundIoErrorNoMem => return error.NoMem,
c.SoundIoErrorInitAudioBackend => return error.InitAudioBackend,
c.SoundIoErrorSystemResources => return error.SystemResources,
c.SoundIoErrorOpeningDevice => return error.OpeningDevice,
c.SoundIoErrorNoSuchDevice => return error.NoSuchDevice,
c.SoundIoErrorInvalid => return error.Invalid,
c.SoundIoErrorBackendUnavailable => return error.BackendUnavailable,
c.SoundIoErrorStreaming => return error.Streaming,
c.SoundIoErrorIncompatibleDevice => return error.IncompatibleDevice,
c.SoundIoErrorNoSuchClient => return error.NoSuchClient,
c.SoundIoErrorIncompatibleBackend => return error.IncompatibleBackend,
c.SoundIoErrorBackendDisconnected => return error.BackendDisconnected,
c.SoundIoErrorInterrupted => return error.Interrupted,
c.SoundIoErrorUnderflow => return error.Underflow,
c.SoundIoErrorEncodingString => return error.EncodingString,
else => return error.Unknown,
}
}
I only know 'shell scripting' and 'REBOL', and I have very limited knowledge of a few other languages. You should discuss this with 'Zig programmers' rather than me.So on that very page, you have some "binding glue" function such as this:
Code:fn sio_err(err: c_int) !void { switch (err) { c.SoundIoErrorNone => {}, c.SoundIoErrorNoMem => return error.NoMem, c.SoundIoErrorInitAudioBackend => return error.InitAudioBackend, c.SoundIoErrorSystemResources => return error.SystemResources, c.SoundIoErrorOpeningDevice => return error.OpeningDevice, c.SoundIoErrorNoSuchDevice => return error.NoSuchDevice, c.SoundIoErrorInvalid => return error.Invalid, c.SoundIoErrorBackendUnavailable => return error.BackendUnavailable, c.SoundIoErrorStreaming => return error.Streaming, c.SoundIoErrorIncompatibleDevice => return error.IncompatibleDevice, c.SoundIoErrorNoSuchClient => return error.NoSuchClient, c.SoundIoErrorIncompatibleBackend => return error.IncompatibleBackend, c.SoundIoErrorBackendDisconnected => return error.BackendDisconnected, c.SoundIoErrorInterrupted => return error.Interrupted, c.SoundIoErrorUnderflow => return error.Underflow, c.SoundIoErrorEncodingString => return error.EncodingString, else => return error.Unknown, } }
This maps the different errors provided by the C API to the idiomatic Zig counterparts.
The problem is, this is fragile to maintain. In a typical audio program you might only specifically reference one or two of these. Whereas in Zig, having to create glue code for each and every one means that if anything gets *removed* or *renamed* in the C API, it will break the Zig bindings and fail to compile ("c.SoundIoErrorIncompatibleBackend undefined"). If the upstream API *adds* a new error type, your bindings will miss it and you will have some unhandled error.
Other non-C languages "solve" this by providing a language based package manager to juggle all the naff bindings. Zig bindings look lighter but honestly I still would not want to write or maintain that boilerplate.
jai would be much faster at this than the D language.Coming from an ASM background, I have great respect for optimizing compilers.
In the OS, every cycle (should) count.
In that example given I believe they are almost being deliberately misleading.You have the sentence 'This Zig code is significantly simpler than the equivalent C code' and this text is a link. If you click on the link you can see what they mean.
'Clean' is a very subjective word. 'Simple' is already a much less subjective word.In that example given I believe they are almost being deliberately misleading.
Typically in any language, if something goes wrong you want to clean up. However, if something goes right, you obviously *don't* want to clean up what you have just succeeded in creating.
So their limited example (with a while loop at the bottom to prevent the earlier allocations from being stripped under you when the function ends) demonstrates their "defer" mechanism. However they evidently have no way of saying, "only clean up the memory if the rest of the function is not successful".
Personally in this case, I would go for 2-goto.c. It is the cleaner design. And unlike Zig (it seems), it would be possible to nicely split up the code into an Initialize() and Run() function.
But I could be missing something. Perhaps the lifetime of the "deferred" object is tracked. Not sure how this would be possible for primitives without overhead or how this works with owning/non-owning observers. C is so much simpler = safety.
Yes but the C one would work when integrated within a large program. The Zig one would return deleted memory and crash the program. XDIn 2-goto.c I count 35 sentences. (I do not count the lines with one or two symbols.)
The sentences of 3-defer.zig are often a bit longer but they are only 16 sentences, which is less than half.
You mentioned you aren't really into software development so this will be difficult to debate. That said, I disagree with most of those points.I think Zig has some things where it is better than C anyway:
It seems strange to me that they would quote two solutions that are not equivalent.Yes but the C one would work when integrated within a large program. The Zig one would return deleted memory and crash the program. XD
Give me 35 *working* lines any day.
Because they are the underdog and are trying to prove their project is relevant using very contrived examplesIt seems strange to me that they would quote two solutions that are not equivalent.
https://gist.github.com/andrewrk/bb124c8de6cf78ad2858041a980951d2#file-test_rand-zig-L4Here's another example: https://gist.github.com/andrewrk/bb124c8de6cf78ad2858041a980951d2
test_rand.c = 133 lines
test_rand.zig = 54 lines
// see rand.zig in zig standard library for code. equivalent to c version in this gist
If a language doesn't call into the underlying system (written in C). Then yes, I agree. It is possible. However real software is more complex than that. Bindings *seriously* inflate code size. Zig can't win with this approach. C++, D, Objective-C have the upper edge here.More generally, I do think it's true that Zig requires less code to achieve the same results with C libraries or just your code in general.
I find precisely that libraries often seem not to be used for the most innovative software. I wonder if software like the popular Ansible uses C libraries?If a language doesn't call into the underlying system (written in C). Then yes, I agree. It is possible. However real software is more complex than that. Bindings *seriously* inflate code size. Zig can't win with this approach. C++, D, Objective-C have the upper edge here.
I doubt we can say that "language A" is faster than "language B". It's rather about compiler optimizations capabilities. And ease of these optimizations depends how "close" is the language to the underlying hardware.Zig is faster than C.
There are ways. Having a language where some things are not explicit (like the sync points and memory layout in C), a compiler can do things that are forbidden to C compilers. When it comes to numeric software, it is really hard to beat Fortran compilers, if at all. They can do things not available to C because of things like alias rules. Java may reshuffle elements of structures at startup, optimizing for cache layouts. For such analysis, I suggest valgrind. It's worth a lot.it's really challenging task to beat C compilers in generating performant code.
Where is C? Haha.Python 87.9% PowerShell 7.0% Shell 2.6% C# 2.1% Jinja 0.4% Go 0.0%
C ??
Indeed. You should use C libraries. But that doesn't make Zig fast does it? (Rebol, 87% written in C. Its a glorified text parser)But you also literally say the following: Zig will never be faster than C because it it will need to i.e marshal data into the format C requires for system libraries.
There are the following things I think about this:
1. You shouldn't really use libraries to write new software. For example, if you use REBOL you are so productive that you write your software and libraries faster than if you use C and fall back on libraries. Simply because REBOL is many times more productive than C.
Barely. Do a scan in the ports collection (ignoring bindings) and you will see 90%+ of libs are C (not even C++). There is a technical reason for this; if you want Python and C# to communicate directly with one another... you can't, you need to go through C because ultimately both are just glorified config file parsers written in C/C++. Only C can guarantee your library can be consumed by other common languages.2. There is also a lot of new software that does not fall back on C libraries, but is largely written in programming language X, Y, Z
This doesn't work well with MACROs or lifetimes of data. The Swift guys have said for years that their translator (similar approach) is good enough but Apple recently came up with a new strategy for Swift to interop with C/C++ better. They have *finally* realized they will never escape the glory that is C. Showing that regardless of what the evangelists were saying; it wasn't good enough.3. You can still translate the code of those libraries to Zig with Zig, do some optimizations, then use Zig libraries.
I think Rust has made better progress. But even so, this will not be in our lifespans. I suspect it won't be in our grandkids lives either. I wonder when it will be? Perhaps when quantum PCs are mainstream? Either way, Zig will be gone long before. I am also convinced that the first mainstream commercial quantum compiler will be C with quantum extensions (C/q)4. The goal of Zig is to still be compatible with C, but meanwhile to program the new libraries all in Zig, so that the old C libraries soon lose their importance and after X number of years are no longer needed for most software.
I've used Ansible to manage Ubuntu systems through a FreeBSD system. I've always found Ansible to be very slow and unresponsive.So ansible effectively relies on more lines of C code then most people could ever write in a lifetime. Utterly dwarfing the actual implementation written in other languages... and that isn't taking into account the dependencies that Python, C# use. Many are written in C too (with bindings glue between them, also written in C).
It is simple, easy to use and powerful. it's also incredibly slow.I link ansible. It's easy. You can configure many things with it. It's not heavy like puppet or chef.
Just the spaces and tabs can be picky.
Zig, like any other non-C language has bindings written (and maintained) by a third party to C/C++ GUI libraries. I.e FLTK:zig lacks bindings to databases and gui-toolkits as opposed to eg python.
I find precisely that libraries often seem not to be used for the most innovative software. I wonder if software like the popular Ansible uses C libraries?
Large-scale operations these days are mostly about Terrible (Terraform + Ansible), if not Kybernetes. A useful language for that is Golang. Python's limitations really opened a gap for Go.
I largely agree with you, but this is a bit harsh. There are things written in pure C# and Python. Yes, I know both languages use C under the covers....There is a technical reason for this; if you want Python and C# to communicate directly with one another... you can't, you need to go through C because ultimately both are just glorified config file parsers written in C/C++. Only C can guarantee your library can be consumed by other common languages.
The Rust guys sure are trying.You can't escape C. But you can simplify by cutting out the noise and just using C directly...
True, but in some ways overemphasizing this issue is useful when trying to explain the situation to potential non-native developers. In particular, it goes beyond "language" and more into the realms of nitty gritty implementation details.I largely agree with you, but this is a bit harsh. There are things written in pure C# and Python. Yes, I know both languages use C under the covers.
They really are. Libraries like librsvg is promising. But their crates.io cesspit does tend to undermine this because it is so easy for developers to drag in a round(ish) rock and use that rather than invent a proper wheel.The Rust guys sure are trying.
I am also convinced that the first mainstream commercial quantum compiler will be C with quantum extensions (C/q)
Quilc is an advanced optimizing compiler for the quantum instruction language Quil
I am also convinced that the first mainstream commercial quantum compiler will be C with quantum extensions (C/q)