Skip to content

Commit

Permalink
chore: improve links ch08 to ch11 (cairo-book#776)
Browse files Browse the repository at this point in the history
Co-authored-by: Mathieu <60658558 [email protected]>
  • Loading branch information
TAdev0 and enitrat authored May 18, 2024
1 parent 0bf7cce commit a97aa87
Show file tree
Hide file tree
Showing 13 changed files with 84 additions and 71 deletions.
4 changes: 3 additions & 1 deletion src/ch08-00-generic-types-and-traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 2,16 @@

Every programming language has tools for effectively handling the duplication of concepts. In Cairo, one such tool is generics: abstract stand-ins for concrete types or other properties. We can express the behavior of generics or how they relate to other generics without knowing what will be in their place when compiling and running the code.

Functions can take parameters of some generic type, instead of a concrete type like `u32` or `bool`, in the same way a function takes parameters with unknown values to run the same code on multiple concrete values. In fact, we’ve already used generics in [Chapter 6](ch06-01-enums.md) with `Option<T>`.
Functions can take parameters of some generic type, instead of a concrete type like `u32` or `bool`, in the same way a function takes parameters with unknown values to run the same code on multiple concrete values. In fact, we’ve already used generics in [Chapter 6][option enum] with `Option<T>`.

In this chapter, you’ll explore how to define your own types, functions, and traits with generics.

Generics allow us to replace specific types with a placeholder that represents multiple types to remove code duplication. Upon compilation, the compiler creates a new definition for each concrete type that replaces a generic type, reducing development time for the programmer, but code duplication at compile level still exists. This may be of importance if you are writing Starknet contracts and using a generic for multiple types which will cause contract size to increment.

Then you’ll learn how to use traits to define behavior in a generic way. You can combine traits with generic types to constrain a generic type to accept only those types that have a particular behavior, as opposed to just any type.

[option enum]: ./ch06-01-enums.html#the-option-enum-and-its-advantages

## Removing Duplication by Extracting a Function

Generics allow us to replace specific types with a placeholder that represents multiple types to remove code duplication. Before diving into generics syntax, then, let’s first look at how to remove duplication in a way that doesn’t involve generic types by extracting a function that replaces specific values with a placeholder that represents multiple values. Then we’ll apply the same technique to extract a generic function! By learning how to identify duplicated code that can be extracted into a function, you'll start to recognize instances where generics can be used to reduce duplication.
Expand Down
4 changes: 2 additions & 2 deletions src/ch08-01-generic-data-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 20,7 @@ The `largest_list` function compares two lists of the same type and returns the
{{#rustdoc_include ../listings/ch08-generic-types-and-traits/no_listing_02_with_tdrop/src/lib.cairo}}
```

The new `largest_list` function includes in its definition the requirement that whatever generic type is placed there, it must be droppable. The `main` function remains unchanged, the compiler is smart enough to deduce which concrete type is being used and if it implements the `Drop` trait.
The new `largest_list` function includes in its definition the requirement that whatever generic type is placed there, it must be droppable. This is what we call _trait bounds_. The `main` function remains unchanged, the compiler is smart enough to deduce which concrete type is being used and if it implements the `Drop` trait.

### Constraints for Generic Types

Expand All @@ -40,7 40,7 @@ When indexing on `list`, the value results in a snap of the indexed element, unl
{{#rustdoc_include ../listings/ch08-generic-types-and-traits/no_listing_04_with_tcopy/src/lib.cairo}}
```

### Anonymous Generic Implementation Parameter (` ` operator)
### Anonymous Generic Implementation Parameter (` ` Operator)

Until now, we have always specified a name for each implementation of the required generic trait: `TPartialOrd` for `PartialOrd<T>`, `TDrop` for `Drop<T>`, and `TCopy` for `Copy<T>`.

Expand Down
10 changes: 4 additions & 6 deletions src/ch08-02-traits-in-cairo.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 6,9 @@ We can use _trait bounds_ to specify that a generic type can be any type that ha

> Note: Traits are similar to a feature often called interfaces in other languages, although with some differences.
While traits can be written to not accept generic types, they are most useful when used with generic types. We already covered generics in the [previous chapter](./ch08-01-generic-data-types.md), and we will use them in this chapter to demonstrate how traits can be used to define shared behavior for generic types.
While traits can be written to not accept generic types, they are most useful when used with generic types. We already covered generics in the [previous chapter][generics], and we will use them in this chapter to demonstrate how traits can be used to define shared behavior for generic types.

[generics]: ./ch08-01-generic-data-types.md

## Defining a Trait

Expand Down Expand Up @@ -106,10 108,6 @@ and pass in any instance of `NewsArticle` or `Tweet`. Code that calls the
function with any other type, such as a `String` or an `i32`, won’t compile
because those types don’t implement `Summary`. -->

<!-- TODO NOT AVAILABLE IN CAIRO FOR NOW trait bound syntax -->

<!-- TODO NOT AVAILABLE IN CAIRO FOR NOW multiple trait bounds -->

<!-- TODO NOT AVAILABLE IN CAIRO FOR NOW Using trait bounds to conditionally implement methods -->

## Managing and Using External Trait
Expand Down Expand Up @@ -153,6 151,6 @@ In Listing {{#ref negative-impls}}, we define a `ProducerType` that implements t
```

{{#label negative-impls}}
<span class="caption"> Listing {{#ref negative-impls}}: Using negative impls to enforce that a type cannot implement both Producer and Consumer traits simultaneously</span>
<span class="caption"> Listing {{#ref negative-impls}}: Using negative impls to enforce that a type cannot implement both `Producer` and `Consumer` traits simultaneously</span>

In the `main` function, we create instances of `ProducerType`, `AnotherType`, and `AThirdType`. We then call the `produce` method on the `producer` instance and pass the result to the `consume` method on the `another_type` and `third_type` instances. Finally, we try to call the `consume` method on the `producer` instance, which results in a compile-time error because `ProducerType` does not implement the `Consumer` trait.
4 changes: 3 additions & 1 deletion src/ch09-01-unrecoverable-errors-with-panic.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 66,9 @@ If you try to compile this function that includes code that may panic, you will
{{#include ../listings/ch09-error-handling/no_listing_05_nopanic_wrong/output.txt}}
```

Note that there are two functions that may panic here, `assert` and equality with `==`. We usually don't use `assert` function in practice and use `assert!` macro instead. We will discuss `assert!` macro in more detail in [Testing Cairo Programs](ch10-01-how-to-write-tests.md#checking-results-with-the-assert-macro) chapter.
Note that there are two functions that may panic here, `assert` and equality with `==`. We usually don't use `assert` function in practice and use `assert!` macro instead. We will discuss `assert!` macro in more detail in [Testing Cairo Programs][assert macro] chapter.

[assert macro]: ./ch10-01-how-to-write-tests.md#checking-results-with-the-assert-macro

## `panic_with` Attribute

Expand Down
11 changes: 8 additions & 3 deletions src/ch09-02-recoverable-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 4,16 @@ Most errors aren’t serious enough to require the program to stop entirely. Som

## The `Result` Enum

Recall from [Generic data types](ch08-01-generic-data-types.md#enums) section in Chapter 8 that the `Result` enum is defined as having two variants, `Ok` and `Err`, as follows:
Recall from [Generic data types][generic enums] section in Chapter 8 that the `Result` enum is defined as having two variants, `Ok` and `Err`, as follows:

```rust,noplayground
{{#include ../listings/ch09-error-handling/no_listing_07_result_enum/src/lib.cairo}}
```

The `Result<T, E>` enum has two generic types, `T` and `E`, and two variants: `Ok` which holds the value of type `T` and `Err` which holds the value of type `E`. This definition makes it convenient to use the `Result` enum anywhere we have an operation that might succeed (by returning a value of type `T`) or fail (by returning a value of type `E`).

[generic enums]: ./ch08-01-generic-data-types.md#enums

## The `ResultTrait`

The `ResultTrait` trait provides methods for working with the `Result<T, E>` enum, such as unwrapping values, checking whether the `Result` is `Ok` or `Err`, and panicking with a custom message. The `ResultTraitImpl` implementation defines the logic of these methods.
Expand All @@ -33,7 35,7 @@ Finally, the `is_ok` and `is_err` methods are utility functions provided by the

These methods are helpful when you want to check the success or failure of an operation without consuming the `Result` value, allowing you to perform additional operations or make decisions based on the variant without unwrapping it.

You can find the implementation of the `ResultTrait` [here](https://github.com/starkware-libs/cairo/blob/main/corelib/src/result.cairo#L20).
You can find the implementation of the `ResultTrait` [here][result corelib].

It is always easier to understand with examples. Have a look at this function signature:

Expand Down Expand Up @@ -66,12 68,15 @@ Our two test cases are:
{{#rustdoc_include ../listings/ch09-error-handling/listing_09_01/src/lib.cairo:tests}}
```

Don't worry about `#[cfg(test)]` attribute for now. We'll explain in more detail its meaning in the next [Testing Cairo Programs](ch10-01-how-to-write-tests.md) chapter.
Don't worry about `#[cfg(test)]` attribute for now. We'll explain in more detail its meaning in the next [Testing Cairo Programs][tests] chapter.

`#[test]` attribute means the function is a test function, and `#[should_panic]` attribute means this test will pass if the test execution panics.

The first one tests a valid conversion from `felt252` to `u8`, expecting the `unwrap` method not to panic. The second test function attempts to convert a value that is out of the `u8` range, expecting the `unwrap` method to panic with the error message `Invalid integer`.

[result corelib]: https://github.com/starkware-libs/cairo/blob/main/corelib/src/result.cairo#L20
[tests]: ./ch10-01-how-to-write-tests.md

### The `?` Operator

The last operator we will talk about is the `?` operator. The `?` operator is used for more idiomatic and concise error handling. When you use the `?` operator on a `Result` or `Option` type, it will do the following:
Expand Down
Loading

0 comments on commit a97aa87

Please sign in to comment.