Language: Language suggestion: make IF and TRY/CATCH expressions (like Kotlin)

Created on 15 May 2019  路  5Comments  路  Source: dart-lang/language

I am not sure this is possible, but it will be great.

In Kotlin you can do:

var x = if (condition) {
  value1
} else {
  value2
}

And yes in Dart we can use x = aaa ? bbb : ccc; but we can't put any complex logic here (as well as use few branches)

Live example form code which I am writing right now

var entrantsValueText = '';
if (f.stakeFrom > 0 && f.stakeTo > 0) {
  entrantsValueText = '$curSymbol ${f.stakeFrom}-${f.stakeTo}';
} else if (f.stakeFrom > 0) {
  entrantsValueText = '>$curSymbol${f.stakeFrom}';
} else {
  entrantsValueText = '<$curSymbol${f.stakeTo}';
}

will be MUCH more shorter

var entrantsValueText  = if (f.stakeFrom > 0 && f.stakeTo > 0) {
  '$curSymbol ${f.stakeFrom}-${f.stakeTo}';
} else if (f.stakeFrom > 0) {
  '>$curSymbol${f.stakeFrom}';
} else {
  '<$curSymbol${f.stakeTo}';
}

I would like to see in Dart all nice features from Kotlin like when, let, with and many more. Should I create an issue for each of them? Or this is totally impossibly due the language architecture?

I know Kotlin transforms all that code inside and generates needed properties, fields and functions, but Dart don't behave like this.

Maybe this is possible to create some lib / plugin for that? If somebody will teach me how to do it and will pay for it I would love to spend 1 month for that, for example =)

Most helpful comment

Also when is another amazing things

var x = when {
  condition1 => a
  condition2 => b
  is String => d
  in 1..10 => e
  else => f
}

It works like if/else, but with super short syntax

All 5 comments

If that would be possible then I not far is losing requirement of empty braces for Function:

callBlock((){
// some logic here
});

and replace it with

callBlock({
});

or even:

callBlock {
};

It's definitely possible to introduce an expression-level if operator, but if it just has expressions as branches, then it's no more powerful than the existing conditonal operator ...?...:....

In general, you can usually take any statement-level control flow operation and change its sub-statements to sub-expressions and get an expression-level control flow operation. You have to handle the cases where no statement would be executed, because expressions always need a value (so, no if-expression without an else branch, maybe no while loop, only a do-while, or similar restrictions).
The try/catch/finally construct would work fairly well as an expression, but you might need to make rethrow an expression as well.

However, you ask for "complex logic" in the if expression. Would that mean statements?
If so, it's a much different feature: A "statement expression" where you can execute statements and then evaluate to a value.
The current approach for those is usually to have an immediately applied function expression:

var x = () {
   if (...) {
     ....
     return v1;
   } else if (...) {
     return v2;
   }
   return v3;
 }();

Being inside another function means that you cannot do non-local control flow (you can't break to a target in the outer code, or return from the outer function.

If we had actual statement expressions, say a syntax like: { statement*; => expression; }, then you could perhaps write:

var x = {
   if (...) {
     ....
     => v1
   } else if (...) {
     => v2
   }
   => v3
 }()

(For nested such expressions, we might need to be able to label the block and emit a value from a labeled containing expression block).

The real complication here is for compilers, where any sub-expression can now do control-flow operations like return, break, or continue. That could complicate compilers.

It's possible, but it may also be a risk to readability. Currently understanding control flow is reasonably simple - control flow is only in statements, expressions cannot change that. If an expression can do control flow, then we can get code like:

  var x = foo(someTest ? value : { return result; })

where the return is a return from the surrounding function. Much harder to reason about.

@lrhn

Thanks for detailed answer!

but if it just has expressions as branches, then it's no more powerful than the existing conditonal operator ...?...:....

Probably I said it wrong. I mean having 2+ branches IS the complex logic.
I don't need make any statements inside, only need more then two branches.
Yes, in Kotlin (and in you further example) you can put logic inside and then put the return value in the last line, but this is not good to write like that. If you make var x = if {...} best practice (as we all understand) is just to make return inside, no more, to keep things clear.

var x = {
   if (...) {
     ....
     => v1
   } else if (...) {
     => v2
   }
   => v3
 }()

That code is very close to what I need!
But ideally it should be

var x = if (...) {
  ....
  v1
} else if (...) {
  v2
} else {
  v3
}

What is important:

  • no return or => to return a value, just put value to the last line
  • no additional wrapping to {}()
  • make compiler show error if i have no no-conditional else branch
    (you mentioned also)
  • make compiler show error if returned values has different types

The real complication here is for compilers, where any sub-expression can now do control-flow operations like return, break, or continue. That could complicate compilers.

Yes

It's possible, but it may also be a risk to readability. Currently understanding control flow is reasonably simple - control flow is only in statements, expressions cannot change that. If an expression can do control flow, then we can get code like:

In Kotlin guys solved it that way:

fun foo() {
  listOf(1, 2, 3, 4, 5).forEach {
    if (it == 3) return@forEach // local return to the caller of the lambda, i.e. the forEach loop
      print(it)
  }
  print(" done with implicit label")
}

So they are add @anything when you are returning from nested scope, and (as far as I know) you can NOT put there pure return - it will show an error.

Also when is another amazing things

var x = when {
  condition1 => a
  condition2 => b
  is String => d
  in 1..10 => e
  else => f
}

It works like if/else, but with super short syntax

try? else?

var? a = try valueOrException(); // null if error
var a = valueOrException() else value;
Was this page helpful?
0 / 5 - 0 ratings

Related issues

ShivamArora picture ShivamArora  路  3Comments

marcelgarus picture marcelgarus  路  3Comments

stategen picture stategen  路  4Comments

creativecreatorormaybenot picture creativecreatorormaybenot  路  3Comments

wytesk133 picture wytesk133  路  4Comments