Skip to content
This repository was archived by the owner on Jul 20, 2025. It is now read-only.

Commit cb76333

Browse files
committed
commit
1 parent 0dc490b commit cb76333

File tree

7 files changed

+199
-212
lines changed

7 files changed

+199
-212
lines changed

src/asynchronous-programming/index.md

Lines changed: 52 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
# Asynchronous Programming
22

3-
Both .NET and Rust support asynchronous programming models, which look similar
3+
Both JavaScript and Rust support asynchronous programming models, which look similar
44
to each other with respect to their usage. The following example shows, on a
5-
very high level, how async code looks like in C#:
5+
very high level, how async code looks like in JavaScript:
66

7-
```csharp
8-
async Task<string> PrintDelayed(string message, CancellationToken cancellationToken)
9-
{
10-
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
11-
return $"Message: {message}";
7+
```js
8+
async function printDelayed(message, cancellationToken) {
9+
await new Promise(resolve => setTimeout(resolve, 1000));
10+
return `Message: ${message}`;
1211
}
1312
```
1413

@@ -26,20 +25,18 @@ async fn format_delayed(message: &str) -> String {
2625
```
2726

2827
1. The Rust [`async`][async.rs] keyword transforms a block of code into a state
29-
machine that implements a trait called [`Future`][future.rs], similarly to
30-
how the C# compiler transforms `async` code into a state machine. In both
28+
machine that implements a trait called [`Future`][future.rs]. In both
3129
languages, this allows for writing asynchronous code sequentially.
3230

33-
2. Note that for both Rust and C#, asynchronous methods/functions are prefixed
31+
2. Note that for both Rust and JavaScript, asynchronous methods/functions are prefixed
3432
with the async keyword, but the return types are different. Asynchronous
35-
methods in C# indicate the full and actual return type because it can vary.
36-
For example, it is common to see some methods return a `Task<T>` while others
37-
return a `ValueTask<T>`. In Rust, it is enough to specify the _inner type_
33+
methods in JavaScript indicate the full and actual return type because it can vary.
34+
In Rust, it is enough to specify the _inner type_
3835
`String` because it's _always some future_; that is, a type that implements
3936
the `Future` trait.
4037

41-
3. The `await` keywords are in different positions in C# and Rust. In C#, a
42-
`Task` is awaited by prefixing the expression with `await`. In Rust,
38+
1. The `await` keywords are in different positions in JavaScript and Rust. In C#, a
39+
`Promise` is awaited by prefixing the expression with `await`. In Rust,
4340
suffixing the expression with the `.await` keyword allows for _method
4441
chaining_, even though `await` is not a method.
4542

@@ -57,15 +54,14 @@ See also:
5754
From the following example the `PrintDelayed` method executes, even though it is
5855
not awaited:
5956

60-
```csharp
61-
var cancellationToken = CancellationToken.None;
62-
PrintDelayed("message", cancellationToken); // Prints "message" after a second.
63-
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
57+
```js
58+
let cancellationToken = undefined;
59+
printDelayed("message", cancellationToken); // Prints "message" after a second.
60+
await new Promise(resolve => setTimeout(resolve, 2000));
6461

65-
async Task PrintDelayed(string message, CancellationToken cancellationToken)
66-
{
67-
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
68-
Console.WriteLine(message);
62+
async function printDelayed(message, cancellationToken) {
63+
await new Promise(resolve => setTimeout(resolve, 1000));
64+
console.log(message);
6965
}
7066
```
7167

@@ -111,8 +107,8 @@ automatically when using the macro.
111107

112108
## Task cancellation
113109

114-
The previous C# examples included passing a `CancellationToken` to asynchronous
115-
methods, as is considered best practice in .NET. `CancellationToken`s can be
110+
The previous JavaScript examples included passing a `CancellationToken` to asynchronous
111+
methods, as is considered best practice in JavaScript. `CancellationToken`s can be
116112
used to abort an asynchronous operation.
117113

118114
Because futures are inert in Rust (they make progress only when polled),
@@ -131,27 +127,27 @@ for cases where implementing the `Drop` trait on a `Future` is unfeasible.
131127

132128
## Executing multiple Tasks
133129

134-
In .NET, `Task.WhenAny` and `Task.WhenAll` are frequently used to handle the
130+
In JavaScript, `Promise.race` and `Task.WhenAll` are frequently used to handle the
135131
execution of multiple tasks.
136132

137-
`Task.WhenAny` completes as soon as any task completes. Tokio, for example,
133+
`Promise.race` completes as soon as any task completes. Tokio, for example,
138134
provides the [`tokio::select!`][tokio-select] macro as an alternative for
139-
`Task.WhenAny`, which means to wait on multiple concurrent branches.
135+
`Promise.race`, which means to wait on multiple concurrent branches.
140136

141-
```csharp
142-
var cancellationToken = CancellationToken.None;
137+
```js
138+
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
143139

144-
var result =
145-
await Task.WhenAny(Delay(TimeSpan.FromSeconds(2), cancellationToken),
146-
Delay(TimeSpan.FromSeconds(1), cancellationToken));
140+
const delayMessage = async (delayTime) => {
141+
await delay(delayTime);
142+
return `Waited ${delayTime / 1000} second(s).`;
143+
};
147144

148-
Console.WriteLine(result.Result); // Waited 1 second(s).
145+
const delay1 = delayMessage(1000);
146+
const delay2 = delayMessage(2000);
149147

150-
async Task<string> Delay(TimeSpan delay, CancellationToken cancellationToken)
151-
{
152-
await Task.Delay(delay, cancellationToken);
153-
return $"Waited {delay.TotalSeconds} second(s).";
154-
}
148+
Promise.race([delay1, delay2]).then(result => {
149+
console.log(result); // Output: Waited 1 second(s).
150+
});
155151
```
156152

157153
The same example for Rust:
@@ -178,16 +174,16 @@ async fn delay(delay: Duration) -> String {
178174

179175
Again, there are crucial differences in semantics between the two examples. Most
180176
importantly, `tokio::select!` will cancel all remaining branches, while
181-
`Task.WhenAny` leaves it up to the user to cancel any in-flight tasks.
177+
`Promise.race` leaves it up to the user to cancel any in-flight tasks.
182178

183-
Similarly, `Task.WhenAll` can be replaced with [`tokio::join!`][tokio-join].
179+
Similarly, `Promise.all` can be replaced with [`tokio::join!`][tokio-join].
184180

185181
[tokio-select]: https://docs.rs/tokio/latest/tokio/macro.select.html
186182
[tokio-join]: https://docs.rs/tokio/latest/tokio/macro.join.html
187183

188184
## Multiple consumers
189185

190-
In .NET a `Task` can be used across multiple consumers. All of them can await
186+
In JavaScript a `Promise` can be used across multiple consumers. All of them can await
191187
the task and get notified when the task is completed or failed. In Rust, the
192188
`Future` can not be cloned or copied, and `await`ing will move the ownership.
193189
The `futures::FutureExt::shared` extension creates a cloneable handle to a
@@ -229,32 +225,31 @@ async fn background_operation(cancellation_token: CancellationToken) {
229225

230226
## Asynchronous iteration
231227

232-
While in .NET there are [`IAsyncEnumerable<T>`][async-enumerable.net] and
233-
[`IAsyncEnumerator<T>`][async-enumerator.net], Rust does not yet have an API for
228+
Rust does not yet have an API for
234229
asynchronous iteration in the standard library. To support asynchronous
235230
iteration, the [`Stream`][stream.rs] trait from [`futures`][futures-stream.rs]
236231
offers a comparable set of functionality.
237232

238-
In C#, writing async iterators has comparable syntax to when writing synchronous
233+
In JavaScript, writing async iterators has comparable syntax to when writing synchronous
239234
iterators:
240235

241-
```csharp
242-
await foreach (int item in RangeAsync(10, 3).WithCancellation(CancellationToken.None))
243-
Console.Write(item + " "); // Prints "10 11 12".
244-
245-
async IAsyncEnumerable<int> RangeAsync(int start, int count)
246-
{
247-
for (int i = 0; i < count; i++)
248-
{
249-
await Task.Delay(TimeSpan.FromSeconds(i));
250-
yield return start + i;
236+
```js
237+
async function* RangeAsync(start, count) {
238+
for (let i = 0; i < count; i++) {
239+
await new Promise(resolve => setTimeout(resolve, i * 1000));
240+
yield start + i;
251241
}
252242
}
243+
244+
(async () => {
245+
for await (const item of RangeAsync(10, 3)) {
246+
console.log(item + " "); // Prints "10 11 12".
247+
}
248+
})();
253249
```
254250

255251
In Rust, there are several types that implement the `Stream` trait, and hence
256-
can be used for creating streams, e.g. `futures::channel::mpsc`. For a syntax
257-
closer to C#, [`async-stream`][tokio-async-stream] offers a set of macros that
252+
can be used for creating streams, e.g. `futures::channel::mpsc`. [`async-stream`][tokio-async-stream] offers a set of macros that
258253
can be used to generate streams succinctly.
259254

260255
```rust
@@ -287,8 +282,6 @@ fn range(start: i32, count: i32) -> impl Stream<Item = i32> {
287282
}
288283
```
289284

290-
[async-enumerable.net]: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.iasyncenumerable-1
291-
[async-enumerator.net]: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.iasyncenumerator-1
292285
[stream.rs]: https://rust-lang.github.io/async-book/05_streams/01_chapter.html
293286
[futures-stream.rs]: https://docs.rs/futures/latest/futures/stream/trait.Stream.html
294287
[tokio-async-stream]: https://github.com/tokio-rs/async-stream
Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,55 @@
11
# Compilation and Building
22

3-
## .NET CLI
3+
## JavaScript CLI
44

5-
The equivalent of the .NET CLI (`dotnet`) in Rust is [Cargo] (`cargo`). Both
5+
There is no concept of CLI in the JavaScript standard. People often use non-browser runtimes such as Node.js and Deno to act as CLIs.The equivalent of the JavaScript CLIs in Rust is [Cargo] (`cargo`). Both
66
tools are entry-point wrappers that simplify use of other low-level tools. For
7-
example, although you could invoke the C# compiler directly (`csc`) or MSBuild
8-
via `dotnet msbuild`, developers tend to use `dotnet build` to build their
7+
example, although you could invoke the JavaScript engines, developers tend to use third-party tools such as `webpack` and `vite` to build their
98
solution. Similarly in Rust, while you could use the Rust compiler (`rustc`)
109
directly, using `cargo build` is generally far simpler.
1110

1211
[cargo]: https://doc.rust-lang.org/cargo/
1312

1413
## Building
1514

16-
Building an executable in .NET using [`dotnet build`][net-build-output]
17-
restores pacakges, compiles the project sources into an [assembly]. The
18-
assembly contain the code in Intermediate Language (IL) and can _typically_ be
19-
run on any platform supported by .NET and provided the .NET runtime is
20-
installed on the host. The assemblies coming from dependent packages are
15+
When building JavaScript, the scripts coming from dependent packages are
2116
generally co-located with the project's output assembly. [`cargo
22-
build`][cargo-build] in Rust does the same, except the Rust compiler
17+
build`][cargo-build] in Rust compiles the project sources, except the Rust compiler
2318
statically links (although there exist other [linking options][linkage]) all
2419
code into a single, platform-dependent, binary.
2520

26-
Developers use `dotnet publish` to prepare a .NET executable for distribution,
21+
Developers use different ways to prepare a JavaScript executable for distribution,
2722
either as a _framework-dependent deployment_ (FDD) or _self-contained
28-
deployment_ (SCD). In Rust, there is no equivalent to `dotnet publish` as the
23+
deployment_ (SCD). In Rust, there is no way to let the
2924
build output already contains a single, platform-dependent binary for each
3025
target.
3126

32-
When building a library in .NET using [`dotnet build`][net-build-output], it
33-
will still generate an [assembly] containing the IL. In Rust, the build output
27+
In Rust, the build output
3428
is, again, a platform-dependent, compiled library for each library target.
3529

3630
See also:
3731

3832
- [Crate]
3933

40-
[net-build-output]: https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-build#description
41-
[assembly]: https://learn.microsoft.com/en-us/dotnet/standard/assembly/
4234
[cargo-build]: https://doc.rust-lang.org/cargo/commands/cargo-build.html#cargo-build1
4335
[linkage]: https://doc.rust-lang.org/reference/linkage.html
4436
[crate]: https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html
4537

4638
## Dependencies
4739

48-
In .NET, the contents of a project file define the build options and
40+
There is no concept of dependency in the JavaScript standard. However, some JavaScript runtimes, such as Node.js and Deno, have the concept of dependencies. In Node.js and Deno, the contents of a project file (`package.json`) define the build options and
4941
dependencies. In Rust, when using Cargo, a `Cargo.toml` declares the
5042
dependencies for a package. A typical project file will look like:
5143

52-
```xml
53-
<Project Sdk="Microsoft.NET.Sdk">
54-
55-
<PropertyGroup>
56-
<OutputType>Exe</OutputType>
57-
<TargetFramework>net6.0</TargetFramework>
58-
</PropertyGroup>
59-
60-
<ItemGroup>
61-
<PackageReference Include="morelinq" Version="3.3.2" />
62-
</ItemGroup>
63-
64-
</Project>
44+
```json
45+
{
46+
"name": "your-project-name",
47+
"version": "1.0.0",
48+
"description": "Your project description",
49+
"dependencies": {
50+
"linq": "4.0.3"
51+
}
52+
}
6553
```
6654

6755
The equivalent `Cargo.toml` in Rust is defined as:
@@ -81,31 +69,30 @@ package directory contains `src/lib.rs`, the package contains a library crate
8169
with the same name as the package.
8270

8371
## Packages
84-
85-
NuGet is most commonly used to install packages, and various tools supported it.
86-
For example, adding a NuGet package reference with the .NET CLI will add the
72+
There is no concept of packages in the JavaScript standard. However, some JavaScript runtimes, such as Node.js, have the concept of packages.
73+
NPM is most commonly used to install packages for Node.js, and various tools supported it.
74+
For example, adding a Node.js package reference with the Node,js CLI will add the
8775
dependency to the project file:
8876

89-
dotnet add package morelinq
77+
npm install linq
9078

9179
In Rust this works almost the same if using Cargo to add packages.
9280

9381
cargo add tokio
9482

95-
The most common package registry for .NET is [nuget.org] whereas Rust packages
83+
The most common package registry for Node.js is [npmjs.com] whereas Rust packages
9684
are usually shared via [crates.io].
9785

98-
[nuget.org]: https://www.nuget.org/
86+
[nuget.org]: https://www.npmjs.com/
9987
[crates.io]: https://crates.io
10088

10189
## Static code analysis
10290

103-
Since .NET 5, the Roslyn analyzers come bundled with the .NET SDK and provide
91+
ESLint is an analyzer that provide
10492
code quality as well as code-style analysis. The equivalent linting tool in Rust
10593
is [Clippy].
10694

107-
Similarly to .NET, where the build fails if warnings are present by setting
108-
[`TreatWarningsAsErrors`][treat-warnings-as-errors] to `true`, Clippy can fail
95+
Clippy can fail
10996
if the compiler or Clippy emits warnings (`cargo clippy -- -D warnings`).
11097

11198
There are further static checks to consider adding to a Rust CI pipeline:
@@ -115,6 +102,5 @@ There are further static checks to consider adding to a Rust CI pipeline:
115102
file is up-to-date.
116103

117104
[clippy]: https://github.com/rust-lang/rust-clippy
118-
[treat-warnings-as-errors]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/errors-warnings
119105
[cargo-doc]: https://doc.rust-lang.org/cargo/commands/cargo-doc.html
120106
[cargo-check]: https://doc.rust-lang.org/cargo/commands/cargo-check.html#manifest-options

src/conditional-compilation/index.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,28 @@ order to control conditional compilation.
88

99
```js
1010
//#if DEBUG
11-
Console.WriteLine("Debug");
11+
console.log("Debug");
1212
//#else
13-
Console.WriteLine("Not debug");
13+
console.log("Not debug");
1414
//#endif
1515
```
1616

17+
An example that uses vanilla JavaScript:
18+
```js
19+
let isDebug = true;
20+
21+
if(isDebug)
22+
{
23+
window.eval(`
24+
console.log("Debug");
25+
`);
26+
} else {
27+
window.eval(`
28+
console.log("Not debug");
29+
`);
30+
}
31+
```
32+
1733
In addition to predefined symbols, it is also possible to use the compiler
1834
option _[DefineConstants]_ to define symbols that can be used with `#if`,
1935
`#else`, `#elif` and `#endif` to compile source files conditionally.

src/language/variables.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Variables
22

3+
⚠️Be Sure to learn about the [ownership](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html) in Rust before reading this article.
4+
35
Consider the following example around variable assignment in JavaScript:
46

57
```js

0 commit comments

Comments
 (0)