Skip to content

Latest commit

 

History

History

README.md

dart_scope_functions (@libsrcdev's fork)

dart_scope_functions is a Dart utility library that implements Kotlin-inspired scope functions. These functions provide a convenient way to execute a block of code within the context of an object, making the code more readable and expressive.

Features

  • Execute blocks of code within the context of an object.
  • Chain multiple operations on an object in a readable manner.
  • Conditional operations on objects, including nullable types.

Installation

Add dart_scope_functions to your pubspec.yaml file:

dependencies:
  dart_scope_functions:
    git:
      url: https://github.com/libsrcdev/dart-packages.git
      path: dart_scope_functions
      ref: main

Then, run pub get to install the package.

Usage

Import the library:

import 'package:dart_scope_functions/dart_scope_functions.dart';

Example

void main() {
  var result = 'Hello'.also((it) {
    print(it); // Prints 'Hello'
  }).let((it) {
    return it.length;
  });

  print(result); // Prints 5

  var conditionResult = 42.takeIf((it) => it > 40);
  print(conditionResult); // Prints 42

  var parsed = '42'.tryLet((it) => int.parse(it));
  print(parsed); // Prints 42

  var fallback = null.letOrElse((it) => it * 2, orElse: 0);
  print(fallback); // Prints 0

  var runResult = run(() {
    return 'Running a block';
  });
  print(runResult); // Prints 'Running a block'

  var runWithResult = runWith(21, (it) => it * 2);
  print(runWithResult); // Prints 42
}

API

Extensions on Any Type [T]

T also(void Function(T it) block)

Calls the specified function block with this value as its argument and returns this value.

  • block: A function to execute with the value.
  • Returns: The original value.

R let<R>(R Function(T it) block)

Calls the specified function block with this value as its argument and returns its result.

  • block: A function to execute with the value.
  • Returns: The result of block.

R? tryLet<R>(R Function(T it) block)

Calls the specified function block with this value as its argument and returns its result, or null if the block throws an exception.

  • block: A function to execute with the value.
  • Returns: The result of block, or null if an exception was thrown.

T? takeIf(bool Function(T it) predicament)

Returns this value if it satisfies the given predicament or null if it doesn't.

  • predicament: A condition to evaluate.
  • Returns: The value if it satisfies the condition, otherwise null.

T? takeUnless(bool Function(T it) predicament)

Returns this value if it does not satisfy the given predicament or null if it does.

  • predicament: A condition to evaluate.
  • Returns: The value if it does not satisfy the condition, otherwise null.

Extensions on Nullable Type [T?]

R letOrElse<R>(R Function(T it) block, {required R orElse})

Calls the specified function block with this value as its argument and returns its result. If this is null, it returns the provided orElse value.

  • block: A function to execute with the value if it's not null.
  • orElse: A default value to return if this is null.
  • Returns: The result of block or orElse.

Global Functions

R run<R>(R Function() block)

Calls the specified function block and returns its result.

  • block: A function to execute.
  • Returns: The result of block.

R runWith<T, R>(T value, R Function(T it) block)

Calls the specified function block with value as its argument and returns its result. Useful as a top-level alternative to let when method chaining is not possible or desirable.

  • value: The value to pass to block.
  • block: A function to execute with the value.
  • Returns: The result of block.

Kotlin Parity: Why apply and Extension run Are Not Included

In Kotlin, apply and run (as extension functions) differ from also and let respectively only in how the lambda receives the object:

Kotlin function Receives object as Returns
also { it.foo() } lambda argument (it) this
apply { foo() } lambda receiver (this) this
let { it.foo() } lambda argument (it) lambda result
run { foo() } lambda receiver (this) lambda result

Dart lambdas do not support receiver-based scoping — there is no way to make this inside a lambda refer to the outer object. As a result, apply and extension run would be byte-for-byte identical to also and let:

// These pairs are completely identical in Dart — there is no distinction:
value.apply((it) { it.foo(); })  // same as also
value.also((it) { it.foo(); })

value.run((it) => it * 2)        // same as let
value.let((it) => it * 2)

Including them would add confusing aliases with no behavioural difference, so they are intentionally omitted.