What is Dart's equivalent to Kotlin's let?

Recently I've been delving into Flutter's ecosystem and Dart has proven itself a neat and simple language.

Currently, I am looking for a best practice to run methods if an optional variable is not null.

In other words, I am looking for something in Dart that is like Kotlin's let operator :

variable?.let {
    doStuff();
    doABitMoreStuff();
    logStuff();
}

Anyone got any ideas or best practices around this?

I've looked into Dart's documentation and have found nothing that would fit my requirements.

King regards,


Solution 1:

With the new Dart extension functions, we can define:

extension ObjectExt<T> on T {
  R let<R>(R Function(T that) op) => op(this as T);
}

This will allow to write x.let(f) instead of f(x).

Solution 2:

Dart's equivalent would be a null-aware cascade operator: The Dart approach would be a to use a null-aware cascade:

SomeType? variable = ...

variable
   ?..doStuff()
    ..doABitMoreStuff()
    ..logStuff();

The null-aware cascade works like the normal cascade, except that if the receiver value is null, it does nothing.


You could make your own using a static function though:

typedef T LetCallback<T>(T value);

T let<T>(T value, LetCallback<T> cb) {
  if (value != null) {
    return cb(value);
  }
}

Then used like that:

let<MyClass>(foo, (it) {

})

Solution 3:

We can do it with Dart 2.6 or later.

extension ScopeFunctionsForObject<T extends Object> on T {
  ReturnType let<ReturnType>(ReturnType operation_for(T self)) {
    return operation_for(this);
  }
}

usage: https://github.com/YusukeIwaki/dart-kotlin_flavor#let

Solution 4:

The difference between x?.let{ } and if (x != null) { } in Kotlin is that the former promotes x to be non-nullable. Since Kotlin has non-nullable types, it prevents you from needing to write x!! to assert the non-nullability inside the block.

Dart doesn't have non-nullable types (yet), so that distinction isn't important in Dart. Just use if (x != null) { ... }. If Dart gets non-nullable types, you can be assured that the null check in the condition will also promote x to non-nullable inside the block (if x is a local variable, is not mutated inside the block, other restrictions may apply). (EDIT: Dart now has nullable types, and x != null promotes x to non-null.)

From your other comments, it sounds like you might be wanting the Kotlin behavior of x?.run { ... } instead, which binds this to x inside the lambda block. There is no corresponding feature in Dart. You cannot override this, it's always bound to the the object that the current method was called on, even inside nested closures which captures the value of this just as they capture other variables.

Solution 5:

I guess a closure does what you want

class Foo {
  var x = 42;
  void bar() {
    () {
      print(x);
      doStuff();
      doABitMoreStuff();
      logStuff();
    }();
  }
}