From a0f5ca9b2397f219045f19c55caea08a7e0f0be4 Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 19:48:52 +0200
Subject: [PATCH 01/14] `let s = &mut String::from("hello");` -> `let mut s =
 String::from("hello");`

---
 src/language/strings.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/language/strings.md b/src/language/strings.md
index dae3cb3..9260d18 100644
--- a/src/language/strings.md
+++ b/src/language/strings.md
@@ -17,7 +17,7 @@ There are differences in working with strings in Rust and .NET, but the
 equivalents above should be a good starting point. One of the differences is
 that Rust strings are UTF-8 encoded, but .NET strings are UTF-16 encoded.
 Further .NET strings are immutable, but Rust strings can be mutable when declared
-as such, for example `let s = &mut String::from("hello");`.
+as such, for example `let mut s = String::from("hello");`.
 
 There are also differences in using strings due to the concept of ownership. To
 read more about ownership with the String Type, see the [Rust Book][ownership-string-type-example].

From 39b5e936d9b731aca4fde6495a53073f5eae9718 Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 19:49:53 +0200
Subject: [PATCH 02/14] `Box::new("")` creates `Box<&str>`, not `Box<str>`. It
 needs to be `let str: Box<str> = Box::from("")`

Or `let str = Box::<str>::from("")`
---
 src/language/strings.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/language/strings.md b/src/language/strings.md
index 9260d18..fcc3cee 100644
--- a/src/language/strings.md
+++ b/src/language/strings.md
@@ -44,7 +44,7 @@ Rust:
 
 ```rust
 let span: &str = "Hello, World!";
-let str = Box::new("Hello World!");
+let str: Box<str> = Box::from("Hello World!");
 let mut sb = String::from("Hello World!");
 ```
 

From 8d8e9ab3c37ece3b04198e4ed4db0445bb87c850 Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 19:52:29 +0200
Subject: [PATCH 03/14] Note that `format!()` only supports bare identifiers in
 the string

There is place to expand more on the possibilities with it (e.g `{0}` or `{name}, name = `, but it can be seen in the documentation.
---
 src/language/strings.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/language/strings.md b/src/language/strings.md
index fcc3cee..09a76f7 100644
--- a/src/language/strings.md
+++ b/src/language/strings.md
@@ -116,6 +116,9 @@ let age = 42;
 let str = format!("Person {{ name: {name}, age: {age} }}");
 ```
 
+Note that `format!` only supports embedding variable names in the string; more complex
+expressions are spelled like `format!("1 + 1 = {}", 1 + 1)`.
+
 Custom classes and structs can also be interpolated in C# due to the fact that
 the `ToString()` method is available for each type as it inherits from `object`.
 

From 96a17ef323e642a13d821188b4487269263e7d57 Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 19:53:10 +0200
Subject: [PATCH 04/14] Mention the `:#?` format specifier

---
 src/language/strings.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/language/strings.md b/src/language/strings.md
index 09a76f7..f7e5455 100644
--- a/src/language/strings.md
+++ b/src/language/strings.md
@@ -186,6 +186,8 @@ println!("{person:?}");
 
 > Note: Using the :? format specifier will use the `Debug` trait to print the
 > struct, where leaving it out will use the `Display` trait.
+>
+> You can also use the `:#?` specifier to pretty-print the debug format.
 
 See also:
 

From 22fdebd832db46a16ebfd7ef25d358886c921416 Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 19:55:02 +0200
Subject: [PATCH 05/14] Mention `to_string()`

---
 src/language/strings.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/language/strings.md b/src/language/strings.md
index f7e5455..1725497 100644
--- a/src/language/strings.md
+++ b/src/language/strings.md
@@ -162,6 +162,10 @@ let person = Person {
 println!("{person}");
 ```
 
+For converting values to string using `Display` without formatting, you can use
+the `std::string::ToString` trait. Its `to_string()` method is equal to the `ToString()`
+method in .NET, and implemented automatically whenever you implement `Display`.
+
 Another option is to use the `std::fmt::Debug` trait. The `Debug` trait is
 implemented for all standard types and can be used to print the internal
 representation of a type. The following example shows how to use the `derive`

From 7f46afe5c4c15669aa8a2d02da38936f9e373d83 Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 19:58:41 +0200
Subject: [PATCH 06/14] Mention properties are rare in Rust, as opposed to in
 C#

---
 src/language/custom-types/members.md | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/language/custom-types/members.md b/src/language/custom-types/members.md
index 0616770..820b223 100644
--- a/src/language/custom-types/members.md
+++ b/src/language/custom-types/members.md
@@ -162,6 +162,11 @@ impl Rectangle {
 }
 ```
 
+> Note: While in C# it is idiomatic to expose a property for every field and keep
+> the fields private, in Rust it is more common to expose the fields directly when possible,
+> since there is no syntax sugar for accessor methods and they also have complexities
+> with the borrow checker.
+
 ## Extension Methods
 
 Extension methods in C# enable the developer to attach new statically-bound

From 4b5728dcf0dd101a07ef93d4b736652f7d67b3e9 Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 19:59:13 +0200
Subject: [PATCH 07/14] Fix typo

---
 src/language/custom-types/members.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/language/custom-types/members.md b/src/language/custom-types/members.md
index 820b223..40ac745 100644
--- a/src/language/custom-types/members.md
+++ b/src/language/custom-types/members.md
@@ -277,7 +277,7 @@ The table below is an approximation of the mapping of C# and Rust modifiers:
 
 ## Mutability
 
-When designing a type in C#, it is the responsiblity of the developer to
+When designing a type in C#, it is the responsibility of the developer to
 decide whether the a type is mutable or immutable; whether it supports
 destructive or non-destructive mutations. C# does support an immutable design
 for types with a _positional record declaration_ (`record class` or `readonly

From 7f39a45052eaf74c0674911e8f2a18790540ab9a Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 20:06:47 +0200
Subject: [PATCH 08/14] Mention `std::ptr::eq()` as the equivalence to
 reference equality in Rust

---
 src/language/equality.md | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/src/language/equality.md b/src/language/equality.md
index c242598..385cc34 100644
--- a/src/language/equality.md
+++ b/src/language/equality.md
@@ -70,6 +70,21 @@ fn main() {
 }
 ```
 
+There is no direct equivalence to reference equality in Rust, since not everything is a reference.
+However, when you have two references, you can check for their reference equality with `std::ptr::eq()`
+
+```rust
+fn main() {
+    let a = 1;
+    let b = 1;
+    println!("{}", a == b); // true
+    println!("{}", std::ptr::eq(&a, &b)); // false
+    println!("{}", std::ptr::eq(&a, &a)); // true
+}
+```
+
+Another way to compare for reference equality is to convert the references to raw pointers and compare them using `==`.
+
 See also:
 
 - [`Eq`][eq.rs] for a stricter version of `PartialEq`.

From a68e7ff83f459d5c67f2f0cf61e5c8ab6de79e64 Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 20:10:08 +0200
Subject: [PATCH 09/14] Mention the `T: Trait` shortcut to `where` clauses

---
 src/language/generics.md | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/src/language/generics.md b/src/language/generics.md
index 9de6041..b6967e3 100644
--- a/src/language/generics.md
+++ b/src/language/generics.md
@@ -73,12 +73,25 @@ impl<T> Timestamped<T> {
 }
 
 impl<T> PartialEq for Timestamped<T>
-    where T: PartialEq {
+where
+    T: PartialEq,
+{
+    fn eq(&self, other: &Self) -> bool {
+        self.value == other.value && self.timestamp == other.timestamp
+    }
+}
+```
+
+A shortcut for `where` clauses that exists in Rust is constraining the parameters
+directly at their declaration:
+```rust
+impl<T: PartialEq> PartialEq for Timestamped<T> {
     fn eq(&self, other: &Self) -> bool {
         self.value == other.value && self.timestamp == other.timestamp
     }
 }
 ```
+Although `where` clauses are somewhat more powerful, since they can constrain arbitrary types (e.g. `i32: PartialEq<T>`).
 
 Generic type constraints are called [bounds][bounds.rs] in Rust.
 

From 23e97963119efe58ca43c5a3c7fcc53aa4734cdd Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 20:12:57 +0200
Subject: [PATCH 10/14] Mention `std::error::Error` isn't strictly required

---
 src/language/exception-handling.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/language/exception-handling.md b/src/language/exception-handling.md
index 2fa9595..48a9602 100644
--- a/src/language/exception-handling.md
+++ b/src/language/exception-handling.md
@@ -54,6 +54,9 @@ The equivalent to the .NET `Exception.InnerException` property is the
 implementation for `Error::source()`, the blanket (default) implementation
 returns a `None`.
 
+> Note: Unlike in C#, in Rust it is not strictly required for an error to implement `std::error::Error`
+> (it can be used in `Result` even without that). But it is strongly encouraged, especially for public errors.
+
 ## Raising exceptions
 
 To raise an exception in C#, throw an instance of the exception:

From 6d06e527fa177878401dba2c0b20c619c43484ad Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 20:27:27 +0200
Subject: [PATCH 11/14] Demonstrate how `and_then()` is a replacement to C#'s
 `?` operator

The example is a bit complicated, but I haven't found a better one.
---
 src/language/nullability-and-optionality.md | 29 ++++++++++++++++++---
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/src/language/nullability-and-optionality.md b/src/language/nullability-and-optionality.md
index bee1de7..0006963 100644
--- a/src/language/nullability-and-optionality.md
+++ b/src/language/nullability-and-optionality.md
@@ -48,21 +48,41 @@ if let Some(max) = max {
 ## Null-conditional operators
 
 The null-conditional operators (`?.` and `?[]`) make dealing with `null` in C#
-more ergonomic. In Rust, they are best replaced by using the [`map`][optmap]
-method. The following snippets show the correspondence:
+more ergonomic. In Rust, they are best replaced by using either the [`map`][optmap]
+method or the [`and_then`][opt_and_then] method, depending on the nesting of the `Option`.
+The following snippets show the correspondence:
 
 ```csharp
 string? some = "Hello, World!";
 string? none = null;
-Console.WriteLine(some?.Length); // 13
+Console.WriteLine(some?.Length); // Hello, World!
 Console.WriteLine(none?.Length); // (blank)
+
+record Name(string FirstName, string LastName);
+record Person(Name? Name);
+
+Person? person1 = new Person(new Name("John", "Doe"));
+Console.WriteLine(person1?.Name?.FirstName); // John
+Person? person2 = new Person(null);
+Console.WriteLine(person2?.Name?.FirstName); // (blank)
+Person? person3 = null;
+Console.WriteLine(person3?.Name?.FirstName); // (blank)
 ```
 
 ```rust
 let some: Option<String> = Some(String::from("Hello, World!"));
 let none: Option<String> = None;
-println!("{:?}", some.map(|s| s.len())); // Some(13)
+println!("{:?}", some.map(|s| s.len())); // Some("Hello, World!")
 println!("{:?}", none.map(|s| s.len())); // None
+
+struct Name { first_name: String, last_name: String }
+struct Person { name: Option<Name> }
+let person1: Option<Person> = Some(Person { name: Some(Name { first_name: "John".into(), last_name: "Doe".into() }) });
+println!("{:?}", person1.and_then(|p| p.name.map(|name| name.first_name))); // Some("John")
+let person1: Option<Person> = Some(Person { name: None });
+println!("{:?}", person1.and_then(|p| p.name.map(|name| name.first_name))); // None
+let person1: Option<Person> = None;
+println!("{:?}", person1.and_then(|p| p.name.map(|name| name.first_name))); // None
 ```
 
 ## Null-coalescing operator
@@ -98,4 +118,5 @@ there is no need to use a substitute for it.
 
 [option]: https://doc.rust-lang.org/std/option/enum.Option.html
 [optmap]: https://doc.rust-lang.org/std/option/enum.Option.html#method.map
+[opt_and_then]: https://doc.rust-lang.org/std/option/enum.Option.html#method.and_then
 [unwrap-or]: https://doc.rust-lang.org/std/option/enum.Option.html#method.unwrap_or

From dc23171bc186c475e8957c0426f29d2b1483ff9b Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 20:29:44 +0200
Subject: [PATCH 12/14] Mention the `?` operator in Rust

---
 src/language/nullability-and-optionality.md | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/language/nullability-and-optionality.md b/src/language/nullability-and-optionality.md
index 0006963..c810cda 100644
--- a/src/language/nullability-and-optionality.md
+++ b/src/language/nullability-and-optionality.md
@@ -85,6 +85,16 @@ let person1: Option<Person> = None;
 println!("{:?}", person1.and_then(|p| p.name.map(|name| name.first_name))); // None
 ```
 
+The `?` operator (mentioned in the previous chapter), can also be used to handle `Option`s.
+It returns from the function with `None` if a `None` is encountered, or else continues with the
+`Some` value:
+```rust
+fn foo(optional: Option<i32>) -> Option<String> {
+    let value = optional?;
+    Some(value.to_string())
+}
+```
+
 ## Null-coalescing operator
 
 The null-coalescing operator (`??`) is typically used to default to another

From 11b2b010a2156fc3b2206585cfb20631b596edb6 Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 20:31:53 +0200
Subject: [PATCH 13/14] Mention `unwrap()` and `expect()`

---
 src/language/nullability-and-optionality.md | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/language/nullability-and-optionality.md b/src/language/nullability-and-optionality.md
index c810cda..89c3948 100644
--- a/src/language/nullability-and-optionality.md
+++ b/src/language/nullability-and-optionality.md
@@ -124,9 +124,14 @@ lazily initialize the default value.
 
 The null-forgiving operator (`!`) does not correspond to an equivalent construct
 in Rust, as it only affects the compiler's static flow analysis in C#. In Rust,
-there is no need to use a substitute for it.
+there is no need to use a substitute for it. [`unwrap`][opt_unwrap] is close,
+though: it panics if the value is `None`. [`expect`][opt_expect] is similar but allows
+you to provide a custom error message. Note that as previously said, panics should
+be reserved to unrecoverable situations.
 
 [option]: https://doc.rust-lang.org/std/option/enum.Option.html
 [optmap]: https://doc.rust-lang.org/std/option/enum.Option.html#method.map
 [opt_and_then]: https://doc.rust-lang.org/std/option/enum.Option.html#method.and_then
 [unwrap-or]: https://doc.rust-lang.org/std/option/enum.Option.html#method.unwrap_or
+[opt_unwrap]: https://doc.rust-lang.org/std/option/enum.Option.html#method.unwrap
+[opt_expect]: https://doc.rust-lang.org/std/option/enum.Option.html#method.expect

From fa0ade54c99b35c6085edc1a24d86349b9d2c039 Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman <chayimfr@gmail.com>
Date: Wed, 10 Jan 2024 20:38:38 +0200
Subject: [PATCH 14/14] Mention scoped threads

---
 src/threading/index.md | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/threading/index.md b/src/threading/index.md
index 42778db..7e116fc 100644
--- a/src/threading/index.md
+++ b/src/threading/index.md
@@ -119,6 +119,11 @@ A few things to note:
   `data` must be copied or cloned (depending on what the type of the value
   supports).
 
+  Since Rust 1.63.0, it is possible to use [scoped threads] to use non-static data
+  (including references to not-`move`d values) in threads. The trade-off is that
+  since the data must remain alive until the thread's end, it is forcibly joined
+  by the end of the scope.
+
 - Rust thread can return values, like tasks in C#, which becomes the return
   value of the `join` method.
 
@@ -126,3 +131,5 @@ A few things to note:
   Rust example, but the C# version does not need to worry about ownership
   since the memory behind the data will be reclaimed by the GC once no one is
   referencing it anymore.
+
+[scoped threads]: https://doc.rust-lang.org/stable/std/thread/fn.scope.html