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

Viewed 8732

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,

9 Answers

With the new Dart extension functions, we can define:

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

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

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) {

})

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.

Using this extension:

extension Ext on Object? {
    void ifNotNull(Function() action) {
        if(this != null){
            action();
        }
    }
}

You can achieve something similar:

object.ifNotNull(() => {
    // safe code
});

I guess a closure does what you want

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

Even though Dart doesn't have the let like behavior as of Kotlin but we can certainly emulate it with concise and readable code. Maybe something like this:

void main() {
  String str = null;

  str?.isEmpty ?? Function.apply(() {
    print("Hey there you cheeky null valued variable");
  }, []);
}

i implemented let function with extension function like this:

extension KotlinLet on Object?{
  void let(Function callback ){
    if (this != null) {
      callback();
    }
  }
 Object? also(){
    if (this != null) {
     return this;
    }
  }
}

There is no direct equivalent, because there is no need for it in Dart. Dart is a lot more like Java and you often end up with similar solutions.

There is almost no syntactic sugar in Dart. It's supposed to be easy to learn.

Also, Dart does not enforce strict null checks, all variables are nullable, and the language is single-threaded. That's why there is no need for let. Use if instead:

if(variable != null) {
  doStuff();
  doABitMoreStuff();
  logStuff();
}
Related