Skip to content

Commit

Permalink
Merge pull request #41 from sroller/Typos
Browse files Browse the repository at this point in the history
Typos and inconsistencies
  • Loading branch information
pedropark99 authored Sep 21, 2024
2 parents dc8ce74 + 3ebde66 commit c9ffa78
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 95 deletions.
122 changes: 57 additions & 65 deletions Chapters/01-zig-weird.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ understanding and exploring the exciting world of Zig.

I assume you have previous experience with some programming
language in this book, not necessarily with a low-level one.
So, if you have experience with Python, or Javascript, for example, is fine.
So, if you have experience with Python, or Javascript, for example, it will be fine.
But, if you do have experience with low-level languages, such as C, C++, or
Rust, you will probably learn faster throughout this book.

Expand All @@ -49,19 +49,19 @@ This philosophy becomes clear with the following phrase from the official websit
This phrase is specially true for C++ programmers. Because C++ is a gigantic language,
with tons of features, and also, there are lots of different "flavors of C++". These elements
are what makes C++ so much complex and hard to learn. Zig tries to go in the opposite direction.
are what makes C++ so complex and hard to learn. Zig tries to go in the opposite direction.
Zig is a very simple language, more closely related to other simple languages such as C and Go.

The phrase above is still important for C programmers too. Because, even C being a simple
language, it is still hard sometimes to read and understand C code. For example, pre-processor macros in
C are an evil source of confusion. They really makes it hard sometimes to debug
C are a frequent source of confusion. They really make it sometimes hard to debug
C programs. Because macros are essentially a second language embedded in C that obscures
your C code. With macros, you are no longer 100% sure about which pieces
of code are being sent to the compiler. It obscures the actual source code that you wrote.
of the code are being sent to the compiler, i.e.
they obscures the actual source code that you wrote.

You don't have macros in Zig. In Zig, the code you write, is the actual code that get's compiled by the compiler.
You don't have evil features that obscures you code.
You also don't have hidden control flow happening behind the scenes. And, you also
You also don't have a hidden control flow happening behind the scenes. And, you also
don't have functions or operators from the standard library that make
hidden memory allocations behind your back.

Expand Down Expand Up @@ -127,7 +127,8 @@ The `ìnit` command also creates two additional files in our working directory:
This script is executed when you call the `build` command from the `zig` compiler.
In other words, this file contain Zig code that executes the necessary steps to build the entire project.

In general, low-level languages normally use a compiler to build your

Low-level languages normally use a compiler to build your
source code into binary executables or binary libraries.
Nevertheless, this process of compiling your source code and building
binary executables or binary libraries from it, became a real challenge
Expand All @@ -147,9 +148,9 @@ As a result, in C/C++ projects, you have not only to install and
manage your C/C++ compilers, but you also have to install and manage
these build systems separately.

But instead of using a separate build system, in Zig, we use the
Zig language itself to write build scripts.
In other words, Zig contains a native build system in it. And
In Zig, we don't need to use a separate set of tools to build our projects,
because a build system is embedded inside the language itself.
Therefore, Zig contains a native build system in it, and
we can use this build system to write small scripts in Zig,
which describes the necessary steps to build/compile our Zig project[^zig-build-system].
So, everything you need to build a complex Zig project is the
Expand All @@ -169,14 +170,14 @@ or the `Cargo.toml` file in Rust projects.
### The file `root.zig` {#sec-root-file}

Let's take a look into the `root.zig` file.
You might have notice that every line of code with an expression ends with a semicolon (`;`).
You might have noticed that every line of code with an expression ends with a semicolon (`;`).
This follows the syntax of a C-family programming language[^c-family].

[^c-family]: <https://en.wikipedia.org/wiki/List_of_C-family_programming_languages>

Also, notice the `@import()` call at the first line. We use this built-in function
to import functionality from other Zig modules into our current module.
In other words, this `@import()` function works similarly to the `#include` pre-processor
This `@import()` function works similarly to the `#include` pre-processor
in C or C++, or, to the `import` statement in Python or Javascript code.
In this example, we are importing the `std` module,
which gives you access to the Zig Standard Library.
Expand Down Expand Up @@ -205,13 +206,13 @@ The function returns an integer of the type `i32` as result.
Zig is not exactly a strongly-typed language. Because you can (if you want to) omit
the type of an object in your code, if this type can be derived from the assigned value.
But there are other situations where you do need to be explicit.
For example, you do have to explicitly specify the type of every single function argument, and also,
For example, you do have to explicitly specify the type of each function argument, and also,
the return type of every function you create in Zig. So, at least in function declarations,
Zig is a strongly-typed language.

We specify the type of an object or a function argument in Zig, by
We specify the type of an object or a function argument in Zig by
using a colon character (`:`) followed by the type after the name of this object/function argument.
With the expressions `a: i32` and `b: i32`, we know that, both `a` and `b` arguments have type `i32`,
With the expressions `a: i32` and `b: i32`, we know that both `a` and `b` arguments have type `i32`,
which is a signed 32 bit integer. In this part,
the syntax in Zig is identical to the syntax in Rust, which also specifies types by
using the colon character.
Expand All @@ -222,46 +223,40 @@ a signed 32 bit integer (`i32`) value.

Notice that we also have an `export` keyword before the function declaration. This keyword
is similar to the `extern` keyword in C. It exposes the function
to make it available in the library API.


In other words, if you have a project where you are currently building
a library for other people to use, you need to expose your functions
so that they are available in the library's API, so that users can use it.
to make it available in the library API. Therefore, if you are writing
a library for other people to use, you have to expose the functions
you write in the public API of this library by using this `export` keyword.
If we removed the `export` keyword from the `add()` function declaration,
then, this function would be no longer exposed in the library object built
by the `zig` compiler.


Having that in mind, the keyword `export` is a keyword used in libraries written in Zig.
If you are not currently writing a library in your project, then, you do not need to
care about this keyword.


### The `main.zig` file {#sec-main-file}

Now that we have learned a lot about Zig's syntax from the `root.zig` file,
let's take a look at the `main.zig` file.
A lot of the elements we saw in `root.zig` are also present in `main.zig`.
But we have some other elements that we did not have seen yet, so let's dive in.
But there are some other elements that we haven't seen yet, so let's dive in.

First, look at the return type of the `main()` function in this file.
We can see a small change. Now, the return
We can see a small change. The return
type of the function (`void`) is accompanied by an exclamation mark (`!`).
What this exclamation mark is telling us, is that this `main()` function
might also return an error.

So, in this example, the `main()` function can either return `void`, or, return an error.
This is an interesting feature of Zig. If you write a function, and, something inside of
the body of this function might return an error, then, you are forced to:

- either add the exclamation mark to the return type of the function, to make it clear that
this function might return an error.
- or explicitly handle this error that might occur inside the function, to make sure that,
if this error does happen, you are prepared, and your function will no longer return an error
because you handled the error inside your function.

In most programming languages, we normally handle (or deals with) an error through
This exclamation mark tells us that this `main()` function
might return an error.

In this example, the `main()` function can either return `void` or return an error.
This is an interesting feature of Zig. If you write a function and something inside of
the body of this function might return an error then you are forced to:

- either add the exclamation mark to the return type of the function and make it clear that
this function might return an error
- explicitly handle this error inside the function

<!-- is it different in Zig or not?
C++ has try/catch
Zig has try if i understand correctly. is there a catch somewhere?
I don't understand what's said in the follwing paragraphs. -->
In most programming languages, we normally handle (or deal with) an error through
a *try catch* pattern, and Zig, this is no different. But, if we look at the `main()` function
below, you can see that we do have a `try` keyword in the 5th line. But we do not have a `catch` keyword
in this code.
Expand All @@ -272,28 +267,30 @@ we are not treating (or dealing with) this error.
So, if this expression do return an error, we are not catching and solving this error in any way.
That is why the exclamation mark was added to the return type of the function.

So, in essence, the `try` keyword executes the expression `stdout.print()`. If this expression
returns a valid value, then, the `try` keyword do nothing essentially. It simply passes this value forward. But, if the expression do
return an error, then, the `try` keyword will unwrap and return this error from the function, and also print it's
The `try` keyword executes the expression `stdout.print()`. If this expression
returns a valid value then the `try` keyword do nothing. It only passes the value forward. But if the expression does
return an error then the `try` keyword will unwrap <!-- the error? -->and return this error from the function and also print its
stack trace to `stderr`.

This might sound weird to you, if you come from a high-level language. Because in
This might sound weird to you if you come from a high-level language. Because in
high-level languages, such as Python, if an error occurs somewhere, this error is automatically
returned and the execution of your program will automatically stops, even if you don't want
returned and the execution of your program will automatically stop even if you don't want
to stop the execution. You are obligated to face the error.

But if you come from a low-level language, then, maybe, this idea do not sound so weird or distant to you.
Because in C for example, normally functions doesn't raise errors, or, they normally don't stop the execution.
<!-- confusing explanation about best practices of error handling in C. As C programmer I might disagree
but it has nothing to do with Zig. just confuses the reader -->
But if you come from a low-level language then this idea doesn't sound so weird to you.
Because in C for example, functions don't raise errors and they don't stop the execution.
In C, error handling
is done by constantly checking the return value of the function. So, you run the function,
and then, you use an if statement to check if the function returned a value that is valid,
or, if it returned an error. If an error was returned from the function, then, the if statement
is done by checking the return value of the function. You run the function, then you use an if statement to check if the function returned a value that is valid if it returned an error. If an error was returned from the function then the if statement
will execute some code that fixes this error.
<!-- there are other options to check return values, eg. switch/case, ?, while, for, ... -->

So, at least for C programmers, they do need to write a lot of if statements to
constantly check for errors around their code. And because of that, this simple feature from Zig, might be
C programmers must write a lot of if-statements
checking for errors around their code. And because of that, this simple feature from Zig, might be
extraordinary for them. Because this `try` keyword can automatically unwrap the error,
and warn you about this error, and let you deal with it, without any extra work from the programmer.
<!-- i'm looking forward to learn more about Zig because what you wrote doesn't sound convincing :-) -->


```{zig}
Expand All @@ -307,22 +304,17 @@ pub fn main() !void {
}
```

Now, another thing that you might have noticed in this code example, is that
the `main()` function is marked with the `pub` keyword. This keyword means
"public". It marks the `main()` function as a *public function* from this module.
Another thing that you might have noticed in this code example, is that
the `main()` function is marked with the `pub` keyword. It marks the `main()` function as a *public function* from this module.

In other words, every function that you declare in your Zig module is, by default, a private (or "static")
function that belongs to this Zig module, and can only be used (or called) from within this same module.
Every function in your Zig module is by default private to this Zig module and can only be called from within the module.
Unless, you explicitly mark this function as a public function with the `pub` keyword.
This means that the `pub` keyword in Zig do essentially the opposite of what the `static` keyword
do in C/C++.

By making a function "public", you allow other Zig modules to access and call this function,
and use it for they own purposes.
all these other Zig modules need to do is, to import your module with the `@import()`
built-in function. Then, they get access to all public functions that are present in
your Zig module.

By making a function "public" you allow other Zig modules to access and call it.
A calling Zig module imports the module with the `@import()`
built-in. That makes all public functions from the imported module visible.

### Compiling your source code {#sec-compile-code}

Expand Down
4 changes: 2 additions & 2 deletions _freeze/Chapters/01-zig-weird/execute-results/html.json

Large diffs are not rendered by default.

Loading

0 comments on commit c9ffa78

Please sign in to comment.