Skip to content

Commit

Permalink
Merge branch 'exercism:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Falilah authored Jan 2, 2025
2 parents db24098 + 20ddbc8 commit 5906ee6
Show file tree
Hide file tree
Showing 48 changed files with 1,281 additions and 170 deletions.
5 changes: 5 additions & 0 deletions concepts/associated-items/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"blurb": "Associated implementations in Cairo allow you to enforce relationships between types and their trait implementations, ensuring type safety and consistency.",
"authors": ["0xNeshi"],
"contributors": []
}
127 changes: 127 additions & 0 deletions concepts/associated-items/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Associated Items

Associated items are items declared in traits or defined in implementations.

These include:

- **Associated functions** (like methods)
- **Associated types**
- **Associated constants**
- **Associated implementations**

They group logically related functionality with a type.

For example, the `is_some` method in `Option` is intrinsically tied to `Option`.

## Associated Types

Associated types define placeholders for types in traits, which are specified by implementors.

This keeps trait definitions flexible and concise.

Example:

```rust
trait Pack<T> {
type Result;

fn pack(self: T, other: T) -> Self::Result;
}

impl PackU32Impl of Pack<u32> {
type Result = u64;

fn pack(self: u32, other: u32) -> Self::Result {
let shift: u64 = 0x100000000; // 2^32
self.into() * shift + other.into()
}
}
```

Here, `Result` is an associated type determined by each implementation.

A function using this trait doesn't need to specify extra generics:

```rust
fn combine<T, impl PackImpl: Pack<T>>(a: T, b: T) -> PackImpl::Result {
a.pack(b)
}
```

## Associated Constants

Associated constants are fixed values tied to a type and defined in a trait or its implementation.

Example:

```rust
trait Shape<T> {
const SIDES: u32;
fn describe() -> ByteArray;
}

struct Triangle {}

impl TriangleShape of Shape<Triangle> {
const SIDES: u32 = 3;
fn describe() -> ByteArray {
"I am a triangle."
}
}

struct Square {}

impl SquareShape of Shape<Square> {
const SIDES: u32 = 4;
fn describe() -> ByteArray {
"I am a square."
}
}
```

This ties constants like `SIDES` to `Shape` instead of hardcoding them elsewhere.

## Associated Implementations

Associated implementations enforce relationships between types and traits.

For example:

```rust
// Collection type that contains a simple array
#[derive(Drop)]
pub struct ArrayIter<T> {
array: Array<T>,
}

// T is the collection type
pub trait Iterator<T> {
type Item;
fn next(ref self: T) -> Option<Self::Item>;
}

impl ArrayIterator<T> of Iterator<ArrayIter<T>> {
type Item = T;
fn next(ref self: ArrayIter<T>) -> Option<T> {
self.array.pop_front()
}
}

/// Turns a collection of values into an iterator
pub trait IntoIterator<T> {
/// The iterator type that will be created
type IntoIter;
impl Iterator: Iterator<Self::IntoIter>;

fn into_iter(self: T) -> Self::IntoIter;
}

impl ArrayIntoIterator<T> of IntoIterator<Array<T>> {
type IntoIter = ArrayIter<T>;
fn into_iter(self: Array<T>) -> Self::IntoIter {
ArrayIter { array: self }
}
}
```

This guarantees `Array` can always be converted into an iterator (`IntoIter`), ensuring consistency and type safety.
5 changes: 5 additions & 0 deletions concepts/associated-items/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Introduction

Associated implementations in Cairo allow you to enforce relationships between types and their trait implementations, ensuring type safety and consistency.
By specifying that an associated type must implement a particular trait, you create a strong, compile-time guarantee that the necessary functionality is provided.
This feature is especially useful for building modular, extensible, and type-safe abstractions.
6 changes: 6 additions & 0 deletions concepts/associated-items/links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"url": "https://book.cairo-lang.org/ch12-10-associated-items.html",
"description": "Associated Items in the Cairo book"
}
]
2 changes: 1 addition & 1 deletion concepts/control-flow/.meta/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"blurb": "Control flow in Cairo uses `if` expressions to conditionally execute code and loops to run code repeatedly.",
"blurb": "Control flow in Cairo uses `if` expressions to conditionally execute code, and loops to run code repeatedly.",
"authors": ["Falilah"],
"contributors": ["0xNeshi"]
}
2 changes: 1 addition & 1 deletion concepts/control-flow/links.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[
{
"url": "https://book.cairo-lang.org/ch02-05-control-flow.html",
"description": "Control flow concept in cairo book"
"description": "Control Flow Concept in The Cairo Book"
}
]
6 changes: 2 additions & 4 deletions concepts/method-syntax/.meta/config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{
"blurb": "<todo>",
"authors": [
"<your_gh_username>"
],
"blurb": "In Cairo, methods and associated functions allow you to organize functionality around specific types, making your code modular and intuitive.",
"authors": ["0xNeshi"],
"contributors": []
}
60 changes: 60 additions & 0 deletions concepts/method-syntax/about.md
Original file line number Diff line number Diff line change
@@ -1 +1,61 @@
# Method Syntax

Methods in Cairo are similar to functions, but they are tied to a specific type through traits.

Their first parameter is always `self`, representing the instance on which the method is called.

While Cairo doesn’t allow defining methods directly on a type, you can achieve the same functionality by defining a trait and implementing it for the type.

Here’s an example of defining a method on a `Rectangle` type using a trait:

```rust
#[derive(Copy, Drop)]
struct Rectangle {
width: u64,
height: u64,
}

#[generate_trait]
impl RectangleImpl of RectangleTrait {
fn area(self: @Rectangle) -> u64 {
(*self.width) * (*self.height)
}
}

fn main() {
let rect = Rectangle { width: 30, height: 50 };
println!("Area is {}", rect.area());
}
```

In the example above, the `area` method calculates the area of a rectangle.

Using the `#[generate_trait]` attribute simplifies the process by automatically creating the required trait for you.

This makes your code cleaner while still allowing methods to be associated with specific types.

## Associated Functions

Associated functions are similar to methods but don’t operate on an instance of a type—they don’t take `self` as a parameter.

These functions are often used as constructors or utility functions tied to the type.

```rust
#[generate_trait]
impl RectangleImpl of RectangleTrait {
fn square(size: u64) -> Rectangle {
Rectangle { width: size, height: size }
}
}

fn main() {
let square = RectangleTrait::square(10);
println!("Square dimensions: {}x{}", square.width, square.height);
}
```

Associated functions, like `Rectangle::square`, use the `::` syntax and are namespaced to the type.

They make it easy to create or work with instances without requiring an existing object.

By organizing related functionality into traits and implementations, Cairo enables clean, modular, and extensible code structures.
4 changes: 4 additions & 0 deletions concepts/method-syntax/introduction.md
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
# Introduction

In Cairo, methods and associated functions allow you to organize functionality around specific types, making your code modular and intuitive.
Methods operate on an instance of a type and always include `self` as their first parameter, while associated functions, such as constructors, don’t require an instance.
Together, they enable a clean and structured approach to defining behavior and utilities for your types.
7 changes: 6 additions & 1 deletion concepts/method-syntax/links.json
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
[]
[
{
"url": "https://book.cairo-lang.org/ch05-03-method-syntax.html",
"description": "Method Syntax in The Cairo Book"
}
]
6 changes: 2 additions & 4 deletions concepts/operator-overloading/.meta/config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{
"blurb": "<todo>",
"authors": [
"<your_gh_username>"
],
"blurb": "Operator overloading in Cairo enables you to redefine standard operators like `+` and `-` for custom types by implementing specific traits.",
"authors": ["0xNeshi"],
"contributors": []
}
49 changes: 49 additions & 0 deletions concepts/operator-overloading/about.md
Original file line number Diff line number Diff line change
@@ -1 +1,50 @@
# Operator Overloading

Operator overloading is a feature in some programming languages that allows the redefinition of standard operators, such as addition (`+`), subtraction (`-`), multiplication (`*`), and division (`/`), to work with user-defined types.

This can make the syntax of the code more intuitive, by enabling operations on user-defined types to be expressed in the same way as operations on primitive types.

In Cairo, operator overloading is achieved through the implementation of specific traits.

Each operator has an associated trait, and overloading that operator involves providing an implementation of that trait for a custom type.
However, it's essential to use operator overloading judiciously.

Misuse can lead to confusion, making the code more difficult to maintain, for example when there is no semantic meaning to the operator being overloaded.

Consider an example where two `Potions` need to be combined.

`Potions` have two data fields, mana and health.

Combining two `Potions` should add their respective fields.

```rust
struct Potion {
health: felt252,
mana: felt252,
}

impl PotionAdd of Add<Potion> {
fn add(lhs: Potion, rhs: Potion) -> Potion {
Potion { health: lhs.health + rhs.health, mana: lhs.mana + rhs.mana }
}
}

fn main() {
let health_potion: Potion = Potion { health: 100, mana: 0 };
let mana_potion: Potion = Potion { health: 0, mana: 100 };
let super_potion: Potion = health_potion + mana_potion;
// Both potions were combined with the `+` operator.
assert(super_potion.health == 100, '');
assert(super_potion.mana == 100, '');
}
```

In the code above, we're implementing the `Add` trait for the `Potion` type.

The add function takes two arguments: `lhs` and `rhs` (left and right-hand side).

The function body returns a new `Potion` instance, its field values being a combination of `lhs` and `rhs`.

As illustrated in the example, overloading an operator requires specification of the concrete type being overloaded.

The overloaded generic trait is `Add<T>`, and we define a concrete implementation for the type `Potion` with `Add<Potion>`.
4 changes: 4 additions & 0 deletions concepts/operator-overloading/introduction.md
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
# Introduction

Operator overloading in Cairo enables you to redefine standard operators like `+` and `-` for custom types by implementing specific traits.
This allows user-defined types to interact intuitively with operators, similar to primitive types.
When used thoughtfully, operator overloading enhances code readability and expressiveness while preserving clarity and intent.
11 changes: 10 additions & 1 deletion concepts/operator-overloading/links.json
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
[]
[
{
"url": "https://book.cairo-lang.org/ch12-03-operator-overloading.html",
"description": "Operator Overloading in The Cairo Book"
},
{
"url": "https://book.cairo-lang.org/appendix-02-operators-and-symbols.html",
"description": "Operators and Symbols in The Cairo Book"
}
]
4 changes: 2 additions & 2 deletions concepts/printing/.meta/config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"blurb": "<todo>",
"blurb": "Printing in Cairo allows you to display messages, debug information, or formatted values during program execution.",
"authors": [
"<your_gh_username>"
"0xNeshi"
],
"contributors": []
}
Loading

0 comments on commit 5906ee6

Please sign in to comment.