In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-21 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly explains "is Zig a long-awaited substitute for C language?" interested friends might as well take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn "is Zig a long-awaited substitute for C language?"
Comparison with previous C competitors (for example, C + +, DMagol Java Personality, Java Personality, Personality GoMagery Rust and Swift).
In many ways, my entire programming career seems to have been a long wait for an alternative to C. Twenty years ago, even though I used C +. With the passage of time, I learned that C + is a complex monster that can never be tamed no matter how many books I have read.
I think Yossi Kreinin and his C + + FAQ (https://yosefk.com/c++fqa/)) are good at summing up all the aspects I hate about C + +.
Therefore, when I become a professional C + programmer, I always focus on other options. The first promising alternative is D. D looked promising at first, but after careful examination, I think D is actually a clean-up version of a fundamentally bad idea. One of the main problems of C + is its receiver language design method.
When implementing a simple game engine in C and Lua, I realized that there are actually fewer ideas to retain both languages than C + +. It brought me a new love for C. Despite all its limitations, C is a fairly simple language that can provide a lot of control.
Java and C # are just trying to reimplement C + + in many ways. They may have made things easier, but ended up getting caught up in virtual machines and object-oriented programming hype in the 1990s. It's not that Java or C # is bad, many of which may be related to communities that support bloated IDE and overdesigned languages.
C the return of simplicity
Moving from Google to Go is a farewell to superfluous C + +, DJE Java and C #. Go takes us back to where we started, back to C. Go reimagined what C might be if you didn't take the risk of taking the C + path. What we get is a simple language that fixes many of the problems I often encounter in the C language.
But the story is not over yet. Right after Go, we got Rust. At first, I thought Rust was actually D's goal all the time. A real rethink of what C + + should be. Rust maintains low-level control, advanced abstraction mechanisms, and manual memory management, but adds unparalleled type safety. Everything looks so good, unbelievable.
Frankly, I think so. I remember being able to write some good programs in Go in two days. Julia, my current favorite is a little similar. On the other hand, learning Rust is like learning Haskell. You only need to know a lot of concepts and theories before you do anything useful.
If C + + has taught me anything, it's about simplicity, and Rust won't do it.
Later, I learned from the comments of many Rust users on the Internet that Rust repeated one of the main shortcomings of C + +. Its compilation time is really slow. I don't think there's anything like waiting for C + to compile to ruin the fun of my programming. Sounds like Rust is getting worse. That's a factor that undermines the deal.
Swift-, I want the language of love.
I have been a big fan of Apple for 20 years. I loved the Cocoa GUI library and programmed Objective-C before iPhone, and all of a sudden, everyone and their pet were programming in Objective-C.
Yes, Objective-C is a bit clumsy, but its simplicity has a certain sense of beauty. Unlike C +, it is a fairly simple supplement to the C language. As a rule of thumb, you can actually teach junior developers Objective-C really quickly.
Therefore, the release of Swift makes me feel that I have achieved the necessary skill of programming. In the end, a very modern language integrates well with Objective-C, so we can still use great Apple libraries, such as Cocoa.
Swift borrowed a lot of ideas from Rust, and in many ways, I think we finally got Rust for ordinary people. You can learn Swift in a relatively short time.
But my experience with Swift has been mixed. Even today, I still can not correctly express the problem of language, because it seems to solve a lot of problems.
I migrated iPhone applications from Objective-C to Swift. One of my best experiences is that Swift has discovered a lot of errors just because of strict type systems that catch problems that are not visible in Objective-C, which is at least about types at compile time, which is well known.
I would say Swift is a better language than C + +, C # and Java. Swift solves almost all of my specific C + + problems. But every time I use Go, I realize that writing Go programs is much more interesting than Swift. But Go's error handling is a bit poor, repeating multimillion-dollar errors with null pointers. Swift avoids these two problems.
When I returned to Swift after a long time with Julia, I saw that some of the problems with Swift became clearer:
Swift syntax is not suitable for functional programming
The Smalltalk heuristic syntax inherited from Objective-C works well in object-oriented programming, but very bad for functional programming. When using a function as a first-class citizen, you don't have to bother to make sure that the parameter name is correct.
A truce between object-oriented programming and functional programming. Swift tries to serve two different owners and suffers from it. When doing very practical style programming, you want your functions to be mainly free functions. These are easier to pass and use in function settings.
But in the end, Swift is mainly aimed at OOP people, putting functions in the method. Once you have done a lot of functional programming, this becomes troublesome.
Where does Zig fit in the programming world?
So Swift never really became my ultimate universal programming language. If I wanted to program at a higher level of abstraction, get high performance, and get the job done, I would choose Julia.
But this still leaves unfilled space for alternatives such as C. Julia can't really replace C. It eats up memory, cannot produce small binaries, and is not suitable for libraries that make other languages available. You don't want to use it to create an OS kernel or to program a microcontroller.
Both Go and Rust are really close to replacing C. Go gets rid of the simplicity and sense of using C #. But it uses garbage collection and can not completely replace C. More control over memory usage in Go is still worthless than Java, because you can get pointers and actually create your own secondary allocator.
Rust reduces manual memory allocation, but fails to replicate the simplicity and feel of C. Maybe is there any space between the two languages that can be filled?
Yes, there is. I think this is Zig. Zig is more complex than Go, but easier to learn and use than Rust.
However, such a Zig summary does not make the language fair. Zig brings a lot of new ideas to tables, which makes sense and makes the experience of Zig coding unique. But before we go any further, let's take a look at the basics.
Master the basic knowledge correctly
If we are going to learn another C-like language, we will not be able to repeat the worst-case scenario of C +, such as poor compile time. How does Zig solve these problems?
I ran into a test conducted by Alexander Medvednikov, the creator of the V programming language. This is a test for compiling a file with a 400K function:
C 5.2 second gcc test
C + + 1 minute 25 seconds g + + test.cpp
Zig 10.1s Zig build-exe test.zig
Nim 45 seconds nim c test.nim
Rust stops after 30 minutes of Rust rustc test.rs
Swift stops after 30 minutes of swiftc testing
D 6 minutes later segfault dmd test.d
V 0.6 second v test v
Both Rust,Swift and D failed. Medvednikov further tested these languages with fewer lines, and Rust once again showed the worst expectations.
As you can see in the list, Zig is the most outstanding actor. Although it's hard not to notice that the V language does everything in less than a second. This reminds me of exploring V in more detail. A quick scan shows that it can manually allocate memory, generic and optional (null pointers must be explicitly allowed).
Zig memory allocation
Without manual memory management, you will not be able to use C language. People who do C-style programming want to do this. If I don't need it, then I can program for Julia.
Zig does not provide the highest level of security that Rust provides, but if it does not, it gets a model that is easier for beginners to master and use.
Anything that needs to be allocated in Zig takes the allocator as a parameter. So Zig makes it very clear when memory management is needed.
This is a simple function I wrote that takes a 32-bit unsigned integer n and splits it into decimal numbers:
Fn decimals (alloc: * Allocator, n: U32)! Array (U32) {var x = n; var digits = Array (U32) .init (alloc); errdefer digits.deinit (); while (x > = 10) {try digits.append (x% 10); xx = x / 10;} try digits.append (x); return digits;}
Note that you must use an allocator, which is an argument to the decimal function, to allocate array digits that hold individual decimal digits.
This is the real light of Zig. Make sure you don't forget that it's hard to allocate memory in the C language. And it's easy to end memory in the wrong place. Zig copied the concept of latency from Go. But besides postponing it, there is also errdefer. If you don't know Go, latency is essentially a way to defer the execution of a line or block of code until the function exits.
Why is it so good? Because it allows you to ensure that some code runs, no matter what complex if-else statements are used before exiting the function.
Errdefer digits.deinit ()
The above line is different from the normal Go delay because it is executed only if an error code is returned. So, if everything goes well, it will never run.
At the calling site, we will use regular delays to ensure that we do not forget to free the memory allocated to the digits.
Const digits = try decimals (allocator, 4123); defer digits.deinit (); for (digits.items) | digit | {try print ("{},",. {digit});}
From my limited experience in playing games on Zig, I would say that this is a good system. The combination of allocator and defer gives you a clear idea of where memory is to be allocated and freed, and that it can be allocated easily and correctly.
C compatible
The problem with many C-like languages is that they cannot be used with C. This means that it should be easy to call C functions from that language, and it should be easy to call functions from C to that language.
In addition, the general way you write your program should be fully compatible with C, so you don't have to create a larger level of C abstraction. For example. C + + is not very friendly to the C language because typical C + libraries cannot be used in C without a lot of packaging.
But Zig is very C because it doesn't expose strange things that C doesn't get. There is no vtable (virtual function table in C + +) in the structure. There is no constructor or destructor that C knows how to call. Without any exception, C will also encounter difficulties in capturing.
It's easy to use C from Zig. In fact, the creators of Zig will claim that Zig is better at using C libraries than C itself.
Const c = @ cImport ({@ cDefine ("_ NO_CRT_STDIO_INLINE", "1"); @ cInclude ("stdio.h");}); pub fn main () void {_ = c.printf ("hello\ n");}
As you can see, there is no problem with Zig parsing the C header file and including the types and functions from C. Zig is actually a full-fledged C compiler. You can use Zig to compile C programs as needed.
Similarly, it is easy to expose Zig functions to C #. This is a Zig function that takes a 32-bit integer and returns a 32-bit integer.
Export fn add (a: i32, b: i32) i32 {return a + b;}
By putting export in front of it, we can make it accessible to the C code that we link to the program. In fact, our main functionality is defined in the C code section and uses the functionality defined in Zig.
# include int32_t add (int32_t a, int32_t b); int main (int argc, char * * argv) {assert (add (42, 1337) = = 1379); return 0;}
This means that you can easily start converting parts of a larger C program to Zig and continue compiling. This is a very powerful feature when porting programs. What made it easy for me to migrate from Objective-C to Swift in the past was that I could replace the Objective-C method one at a time with a version of Swift, compile and see that everything still works.
In fact, Zig makes it easier by allowing you to automatically convert C programs into Zig code. This is built into the Zig compiler:
$zig translate-c foobar.c
Of course, the code is not optimal and can be a bit confusing. But this is a bit like using Google translation for natural language translation. This is a good starting point and can save a lot of physical labor. You can fix the details manually later.
Minimalism
Minimalism first attracts a lot of people to use C programming. This is what Go is right about and makes programming very happy. You can easily keep the whole program in mind.
Now, if you start reading Zig and take a look at the source code example I give you here, it may look complicated. Some language structures may seem strange. It is easy to feel that it is a complex language.
So, it's actually very useful to figure out everything Zig doesn't support:
There is no class inheritance, such as C + +, Java,Swift, etc.
There is no runtime polymorphism through interfaces such as Go.
There are no generics. You cannot specify a generic interface as you would in the Swift checked at compile time.
There are no function overloads. You cannot write a function with the same name multiple times with different parameters.
No exception was thrown.
There is no closure.
There is no garbage collection.
The constructor and destructor that are not used for resource acquisition are RAII.
However, by skillfully using some core features, Zig can provide almost the same functionality:
Types can be passed like objects at compile time.
Label union. It is also called a summation type or variant in other programming languages.
Function pointer.
Real number pointer and pointer arithmetic.
Zig code can be partially evaluated at compile time. You can use the comptime keyword to mark your code as executable at compile time.
Functions and types can be associated with a structure, but cannot be physically stored in the structure, so the C code is not visible.
Simulate generics in Zig
For example. By taking advantage of the ability to run code at compile time, something similar to a template is created in Julia. Loris Cro has a good article that describes this in more detail. I'll use only the examples in this article to quickly understand the idea.
We can define, for example, a function called LinkedList, which can only be called at compile time, takes the type of the elements in the linked list, and then returns the linked list type that contains the following elements:
Fn LinkedList (comptime T: type) type {return struct {pub const Node = struct {prev:? * Node = null, next:? * Node = null, data: t,}; first:? * Node = null, last:? * Node = null, len: usize = 0,};}
This takes advantage of the fact that the structure can be anonymous. You don't need to give them a name. However, this feature requires a little packaging. Note this part:
Pub const Node = struct {prev:? * Node = null, next:? * Node = null, data: t,}
There are a lot of Zig-specific features at work here that need some explanation. In Zig, you can assign values to structure members when you define a structure. Members can be fields that exist at compile time or run time. The previous:? * Node = null is an example of a structure field that exists at compile time, but its default value is null. What about the crazy * prefix?
In Zig, * Node represents a pointer to an object of type Node similar to C / C + +. However, since Zig does not allow pointers to be null unless explicitly allowed,? must be added. Indicates that the pointer can be null.
The node itself is set to the field of the surrounding anonymous structure. However, because it is defined as const, it exists only at compile time. If the memory of the LinkedList structure is checked at run time, the area corresponding to the Node cannot be found.
Also keep in mind that although you can use types as any other object at compile time, they do not exist in Zig at run time. So basically what we're doing here is to create a structure with nested types.
Let me use one of the examples of Loris Cro for a better explanation. First, he creates a linked list of points and assigns it to a variable named PointList that exists only at compile time:
Const PointList = LinkedList (Point)
We can then instantiate an empty list using this newly created type.
Var my_list = PointList {}
We do not need to specify any initial values for first,last and len because they have default values.
Here, we use nested types to create a Node object to hold our point data:
Const p = Point {.x = 0, .y = 2, .z = 8}; var node = PointList.Node {.data = p}; my_list.first = & node; my_list.last = & node; my_list.len = 1
Simulate the interface in Zig
Although Zig does not have keywords for interfaces such as classes or object-oriented languages, we can still build our own run-time polymorphic systems, similar to what C programmers have done for years.
You only need to use function pointers to define the structure. In the Unix kernel, you see a similar operation that allows general processing of any file descriptor, whether they are files, sockets, or pipes.
Typedef struct _ File {void (* write) (void * fd, char * data); void (* read) (void * fd, char * buffer, int size); void (* close) (void * fd);} File
This is not exactly how it is defined. I just do this from memory. What this allows us to do is to provide different open functions for files, sockets and pipes. However, because they all give us File structures, other functions can use the function pointers they contain to manipulate this, thus abstracting the differences in the underlying structure.
In Zig, we use a similar method that Nathan Michaels describes in more detail here. Zig provides better functionality than C, so you'll see that Zig uses more functionality in creating generic iterators, allocators, readers, writers, and more operations in Zig.
One might ask, why not include this kind of content in the language? If you have ever used Lua, you will learn some advantages instead of giving you blocks to create an object-oriented system, rather than hardwiring it.
With Zig, you can build C + +-style object-oriented systems, similar to Go or even object-oriented programming in more dynamic languages such as Objective-C.
This self-developed approach can be very effective. We have seen LISP programmers use it to build object-oriented programming systems in LISP and even create multi-scheduling systems similar to Julia.
At this point, I believe you have a deeper understanding of "is Zig a long-awaited substitute for C language?" you might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.