Skip to content

Commit

Permalink
Doc/do notation documentation (#140)
Browse files Browse the repository at this point in the history
  • Loading branch information
SandroMaglione committed Dec 14, 2023
2 parents d2d21ad + 3b4028f commit 6e7c875
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 7 deletions.
58 changes: 58 additions & 0 deletions examples/do_constructor_pitfalls/bin/do_constructor_pitfalls.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import 'package:fpdart/fpdart.dart';

/// This file demonstrates some common pitfalls when using the `Do` constructor in the `fpdart` package.
/// These are practices that should be avoided when using it.
void main(List<String> args) {}

/// This function demonstrates that the `Do` constructor should not contain a `throw` statement.
/// Throwing an exception inside a `Do` constructor can lead to unexpected behavior and should be avoided.
/// Instead, use the `Option` type to handle errors.
void doConstructorShouldNotContainThrow() {
const testOption = const Option<String>.of('test');
Option.Do(
($) {
if ($(testOption) == 'test') {
// Do not throw inside a Do constructor
throw Exception('Error');
}
return 'success';
},
);
}

/// This function demonstrates that the `Do` constructor should not contain an `await` statement without executing the `$` function.
void doConstructorShouldNotAwaitWithoutExecutingDollarFunction() {
Future<String> future = Future.value('test');
const testOption = const Option<String>.of('test');
Option.Do(
($) async {
// Do not use `await` without executing the `$` function
await future;
return $(testOption);
},
);
}

// This function demonstrates that the `Do` constructor should not be nested.
/// Nesting `Do` constructors can lead to unexpected behavior and should be avoided.
void doConstructorShouldNotBeNested() {
const testOption = const Option<String>.of('test');
// Do not nest Do constructors
Option.Do(
($) => Option.Do(
($) => $(testOption),
),
);
}

/// This function demonstrates that the `Do` constructor should not call the `$` function inside a callback.
void doConstructorShouldNotCallDollarFunctionInCallback() {
const testOption = const Option<List<String>>.of(['test']);
Option.Do(
($) => $(testOption).map(
// Do not call the `$` function inside a callback
(stringValue) => $(optionOf(stringValue)),
),
);
}
18 changes: 18 additions & 0 deletions examples/do_constructor_pitfalls/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: fpdart_do_constructor_pitfalls
publish_to: none
version: 0.1.0
homepage: https://www.sandromaglione.com/
repository: https://github.com/SandroMaglione/fpdart
description: Example of Functional programming in Dart and Flutter using fpdart. Pitfalls to avoid when using the do constructor.

environment:
sdk: ">=3.0.0 <4.0.0"

dependencies:
fpdart:
path: ../../packages/fpdart

dev_dependencies:
lint: ^2.1.2
test: ^1.24.3
mocktail: ^0.3.0
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
void main() {}
24 changes: 17 additions & 7 deletions packages/fpdart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,13 +331,13 @@ Everything looks more **linear and simple** by using the Do notation:
```dart
/// Using the Do notation
String goShoppingDo() => Option.Do(
(_) {
final market = _(goToShoppingCenter().alt(goToLocalMarket));
final amount = _(market.buyAmount());
($) {
final market = $(goToShoppingCenter().alt(goToLocalMarket));
final amount = $(market.buyAmount());
final banana = _(market.buyBanana());
final apple = _(market.buyApple());
final pear = _(market.buyPear());
final banana = $(market.buyBanana());
final apple = $(market.buyApple());
final pear = $(market.buyPear());
return 'Shopping: $banana, $apple, $pear';
},
Expand All @@ -346,12 +346,22 @@ String goShoppingDo() => Option.Do(
);
```


You initialize the Do notation using the **`Do()` constructor**.

You have access to a `_` function, that you can use to extract and use the value inside each `Option`, without using `flatMap`.
You have access to a `$` function, that you can use to extract and use the value inside each `Option`, without using `flatMap`.

> **Note**: We recommend using the Do notation whenever possible to improve the legibility of your code 🤝
> ⚠️ **Warning**: Pay attention to avoid the following mistakes when using the **Do notation**:
> - Do not `throw` inside the **`Do()`** constructor
> - Do not `await` without executing the `$` function
> - Do not use a nested **`Do()`** constructor inside another one
> - Do not call the `$` function inside another callback in the **`Do()`** constructor
>
> Using the **Do notation** in these cases may fail at runtime or may produce unexpected behavior. For more information take a look at [the `Do Notation` discussion](https://github.com/SandroMaglione/fpdart/issues/26) or at this [issue](https://github.com/SandroMaglione/fpdart/issues/139).
> Examples for each of the pitfalls can be viewed here: [do-constructor-pitfalls](https://github.com/SandroMaglione/fpdart/tree/main/examples/do_constructor_pitfalls)
### 📦 Immutable Collections

> If you are going to use `fpdart` in your project, make sure to use immutable collections as well ☝️
Expand Down

0 comments on commit 6e7c875

Please sign in to comment.