Skip to content

Commit

Permalink
Merge pull request #53 from pedropark99/revision-4
Browse files Browse the repository at this point in the history
Add revision for Chapters 4, 5 and 6
  • Loading branch information
pedropark99 authored Oct 3, 2024
2 parents bf7add2 + c10dd6b commit d8b65fe
Show file tree
Hide file tree
Showing 49 changed files with 555 additions and 545 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ foo.txt
*.aux
*.log
*.toc

Chapters/15-vectors_files/
201 changes: 93 additions & 108 deletions Chapters/01-base64.qmd

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Chapters/01-memory.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ object you declare is stored:
One key aspect about Zig, is that there are "no hidden-memory allocations" in Zig.
What that really means, is that "no allocations happen behind your back in the standard library" [@zigguide].

This is a known problem, specially in C++. Because in C++, there are some operators that do allocate
This is a known problem, especially in C++. Because in C++, there are some operators that do allocate
memory behind the scene, and there is no way for you to known that, until you actually read the
source code of these operators, and find the memory allocation calls.
Many programmers find this behaviour annoying and hard to keep track of.
Expand Down
10 changes: 5 additions & 5 deletions Chapters/01-zig-weird.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,7 @@ try stdout.print("{any}\n", .{c});
### Runtime versus compile-time known length in slices

We are going to talk a lot about the differences between compile-time known
and runtime known across this book, specially at @sec-compile-time.
and runtime known across this book, especially at @sec-compile-time.
But the basic idea is that a thing is compile-time known, when we know
everything (the value, the attributes and the characteristics) about this thing at compile-time.
In contrast, a runtime known thing is when the exact value of a thing is calculated only at runtime.
Expand Down Expand Up @@ -1065,7 +1065,7 @@ const object: []const u8 = "A string object";
Zig always assumes that this sequence of bytes is UTF-8 encoded. This might not be true for every
sequence of bytes you have it, but is not really Zig's job to fix the encoding of your strings
(you can use [`iconv`](https://www.gnu.org/software/libiconv/)[^libiconv] for that).
Today, most of the text in our modern world, specially on the web, should be UTF-8 encoded.
Today, most of the text in our modern world, especially on the web, should be UTF-8 encoded.
So if your string literal is not UTF-8 encoded, then, you will likely
have problems in Zig.

Expand Down Expand Up @@ -1418,7 +1418,7 @@ the data produced by all of this technology becomes one of the most important
(and also, one of the most dangerous) assets that we have.

This is probably the main reason why modern low-level programming languages
have been giving great attention to safety, specially memory safety, because
have been giving great attention to safety, especially memory safety, because
memory corruption is still the main target for hackers to exploit.
The reality is that we don't have an easy solution for this problem.
For now, we only have techniques and strategies that mitigates these
Expand Down Expand Up @@ -1453,7 +1453,7 @@ pattern.

In contrast, the Zig language is not a memory safe language by default.
There are some memory safety features that you get for free in Zig,
specially in arrays and pointer objects. But there are other tools
especially in arrays and pointer objects. But there are other tools
offered by the language, that are not used by default.
In other words, the `zig` compiler does not obligates you to use such tools.

Expand Down Expand Up @@ -1482,7 +1482,7 @@ We already learned a lot about Zig's syntax, and also, some pretty technical
details about it. Just as a quick recap:

- We talked about how functions are written in Zig at @sec-root-file and @sec-main-file.
- How to create new objects/identifiers at @sec-root-file and specially at @sec-assignments.
- How to create new objects/identifiers at @sec-root-file and especially at @sec-assignments.
- How strings work in Zig at @sec-zig-strings.
- How to use arrays and slices at @sec-arrays.
- How to import functionality from other Zig modules at @sec-root-file.
Expand Down
69 changes: 41 additions & 28 deletions Chapters/02-debugging.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ knitr::opts_chunk$set(

# Debugging Zig applications

Being able to debug your programs is essential to any programmer who wants to
Being able to debug your applications is essential for any programmer who wants to
do serious programming in any language. That is why, in this chapter, we are going to talk about the
available strategies and tools to debug applications written in Zig.


## Printing debugging
## Print debugging

We begin with the classic and battle-tested *print debugging* strategy.
The key advantage that debugging offers you is *visibility*.
With *print statements* you can easily see what results and objects
that are being generated within your functions.
are being produced by your application.

That is the essence of *print debugging*. Is to use
print expressions to see the values that are being generated by your program,
Expand All @@ -37,20 +37,20 @@ is behaving.

Many programmers often resort to the print functions in Zig, such as the `stdout.print()`,
or, the `std.debug.print()`, to get a better understanding of their programs.
This is an known and old strategy that is very simple and effective, and it is better known within
This is a known and old strategy that is very simple and effective, and it is better known within
the programming community as *print debugging*.
In Zig, you can either print information to the `stdout` or `stderr` streams of your system.
In Zig, you can print information to the `stdout` or `stderr` streams of your system.

Let's begin with `stdout`. First, you
need to get access to the `stdout`, by calling the `getStdOut()` method, from
the Zig standard library. This method returns a *file descriptor* object,
the Zig Standard Library. This method returns a *file descriptor* object,
and, through this object you can read/write to the `stdout`.
I recommend you to check out all methods available in this object, by [checking the page in
the Zig Standard Library Official Reference for the type `File`](https://ziglang.org/documentation/master/std/#std.fs.File)[^zig-fiile-reference].

[^zig-fiile-reference]: <https://ziglang.org/documentation/master/std/#std.fs.File>.

For our purpose here, which is to write something to the `stdout`, specially to debug our
For our purpose here, which is to write something to the `stdout`, especially to debug our
program, I recommend you to use the `writer()` method, which gives your a *writer* object.
This *writer* object offers some helper methods to write stuff into the file descriptor object
that represents the `stdout` stream. In special, the `print()` method.
Expand All @@ -64,7 +64,7 @@ in the second argument, you provide a list of values (or objects) that you want
into your template message.

Ideally, the template string in the first argument should contain some format specifier.
Each format specifier is matched to a value (or object) that you listed in the second argument.
Each format specifier is matched to a value (or object) that you have listed in the second argument.
So, if you provided 5 different objects in the second argument, then, the template string
should contain 5 format specifiers, one for each object provided.

Expand All @@ -80,7 +80,7 @@ Here is a quick list of the most used format specifiers:
- `x`: for printing hexadecimal values.
- `any`: use any compatible format specifier (i.e. it automatically selects a format specifier for you).

The code example below, gives you an example of use of this `print()` method
The code example below gives you an example of use of this `print()` method
with the `d` format specifier.

```{zig}
Expand Down Expand Up @@ -122,11 +122,23 @@ pub fn main() !void {
Result: 50
```

You could also achieve the exact same result by getting a file descriptor object to `stderr`,
then, creating a *writer* object to `stderr`, then, using the `print()` method of this
*writer* object, like in the example below:

```{zig}
#| eval: false
const std = @import("std");
const stderr = std.io.getStdErr().writer();
// some more lines ...
_ = try stderr.print("Result: {d}", .{result});
```



## Debugging through debuggers

Although *print debugging* is a valid and very useful strategy,
Although *print debugging* being a valid and very useful strategy,
most programmers prefer to use a debugger to debug their programs.
Since Zig is a low-level language, you can use either GDB (GNU Debugger),
or LLDB (LLVM Project Debugger) as your debugger.
Expand All @@ -136,28 +148,28 @@ You choose the debugger of your preference, and you work with it.
In this book, I will use LLDB as my debugger on the examples.


### Compile your source code in Debug mode {#sec-compile-debug-mode}
### Compile your source code in debug mode {#sec-compile-debug-mode}

In order to debug your program through a debugger, you must compile
your source code in Debug mode. Because when you compile your
source code in other modes (such as Release), the compiler usually
your source code in `Debug` mode. Because when you compile your
source code in other modes (such as `Release`), the compiler usually
strips out some essential information that is used by the debugger
to read and track your program, like PDB (*Program Database*) files.

By compiling your source code in Debug mode, you ensure that the debugger
By compiling your source code in `Debug` mode, you ensure that the debugger
will find the necessary information in your program to debug it.
By default, the compiler uses the Debug mode. Having this in mind,
when you compile your program with the `build-exe`
command (that we exposed at @sec-compile-code), if you don't specify an explicit mode through the `-O` command-line [^oargument]
argument, then, the compiler will compile your code in Debug mode.
By default, the compiler uses the `Debug` mode when compiling your code.
Having this in mind, when you compile your program with the `build-exe`
command (which was described at @sec-compile-code), if you don't specify
an explicit mode through the `-O` command-line [^oargument]
argument, then, the compiler will compile your code in `Debug` mode.

[^oargument]: See <https://ziglang.org/documentation/master/#Debug>.


### Let's debug a program

As an example, let's debug some Zig code, and demonstrate
how can we use LLDB to navigate and check the following
As an example, let's use LLDB to navigate and investigate the following
piece of Zig code:

```{zig}
Expand All @@ -182,7 +194,7 @@ pub fn main() !void {
There is nothing wrong with this program. But it is
a good start for us. First, we need to compile
this program with the `zig build-exe` command.
For this example, suppose that I compiled the above
For this example, suppose that I have compiled the above
Zig code into a binary executable called `add_program`.

```bash
Expand Down Expand Up @@ -226,12 +238,12 @@ Process 8654 stopped
14 }
```
I can start to navigate through the code, and investigating the variables
that are being generated. If you not familiar with the commands
I can start navigating through the code, and checking the objects
that are being generated. If you are not familiar with the commands
available in LLDB, I recommend you to read the official documentation
of the project[^lldb].
You can also look for cheat sheets. Which quickly describes all commands
available for you, and, as a result, are also good resources for you[^lldb-quick-list].
You can also look for cheat sheets, which quickly describes all commands
available for you[^lldb-quick-list].
[^lldb]: <https://lldb.llvm.org/>
[^lldb-quick-list]: <https://gist.github.com/ryanchang/a2f738f0c3cc6fbd71fa>.
Expand Down Expand Up @@ -271,11 +283,11 @@ Process 4798 stopped
Now, on the next line of code, we are executing the `add_and_increment()` function once again.
Why not step inside this function? Shall we? We can do that, by executing the `s` LLDB command.
Notice in the example below that, after executing this command, we entered inside the context of the
Notice in the example below that, after executing this command, we have entered into the context of the
`add_and_increment()` function.
Also notice in the example below that, I walked two more lines in the functions body, then,
I executed the `frame variable` LLDB command, to see at once, the value stored in each of the variables
Also notice in the example below that, I have walked two more lines in the function's body, then,
I execute the `frame variable` LLDB command, to see at once, the value stored in each of the variables
that were created inside the current scope.
You can see in the output below that, the object `sum` stores the value `\f`,
Expand Down Expand Up @@ -337,3 +349,4 @@ pub fn main() !void {
This function is similar to the `type()` built-in function from Python,
or, the `typeof` operator in Javascript.
2 changes: 1 addition & 1 deletion Chapters/03-structs.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ knitr::opts_chunk$set(
# Control flow, structs, modules and types

We have discussed a lot of Zig's syntax in the last chapter,
specially at @sec-root-file and @sec-main-file.
especially at @sec-root-file and @sec-main-file.
But we still need to discuss some other very important
elements of the language. Elements that you will use constantly on your day-to-day
routine.
Expand Down
4 changes: 2 additions & 2 deletions Chapters/03-unittests.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ All 1 tests passed.
One of the advantages of Zig is that it offers great tools
that hep us, programmers, to avoid (but also detect) memory problems, such as
memory leaks and double-frees. The `defer` keyword
is specially helpful in this regard.
is especially helpful in this regard.

When developing your
source code, you, the programmer, is responsible for making
Expand Down Expand Up @@ -245,7 +245,7 @@ All 1 tests passed.
In Zig, there are some different ways you can test for an equality.
You already saw that we can use `expect()` with the logical operator `==`
to essentially reproduce an equality test. But we also have
some helper functions that you should know about, specially
some helper functions that you should know about, especially
`expectEqual()`, `expectEqualSlices()` and `expectEqualStrings()`.


Expand Down
2 changes: 1 addition & 1 deletion Chapters/04-http-server.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,7 @@ into our `main.zig` module, then, I add the function calls to `send_200()`
and `send_404()`.

Notice that I'm using if statements to decide which "response function" to call,
based specially on the URI present in the HTTP Request. If the user asked for
based especially on the URI present in the HTTP Request. If the user asked for
a content (or a document) that is not present in our server, we should respond
with a 404 status code. But since we have just a simple HTTP server, with no
real documents to send, we can just check if the URI is the root path (`/`)
Expand Down
Loading

0 comments on commit d8b65fe

Please sign in to comment.