Thursday, January 13, 2011

More on statements as expressions

I've been playing around with this idea some more, and I'm starting to like some of the results.

Here's the specific changes that would be made to the language syntax:

  • The following statements will be able to be used as expressions:
    • if
    • switch
    • classify, which will be renamed 'match'.
    • with
  • Statement blocks can be used as expressions.
    • The last statement in the block is the result.
    • The semicolon after the last statement is now optional - meaning that semicolon now becomes a statement separator rather than a statement terminator.
    • Braces are still always required around statement blocks.
    • Return values can be type 'void' if there's no actual value to return.
    • One particularly challenging issue will be making the type inference system smart about statement blocks - that is, the type of the last statement in a block will in some cases be inferrable from the type of expression that block is assigned to.
  • The 'return if' syntax is no longer allowed ("return value if condition") since it's ambiguous.
    • We can still keep "break if" and "continue if" if desired, but it may be best to remove those as well. I need to think about it.
  • 'cond' goes away as it is no longer needed.
    • Macros can stay for the moment, as they are needed for assertions (they make it possible to print the string form of the assertion expression.)
Here's some example syntax to show how the code would look:

// All in one line
var x = if n != 0 { result1 } else { result2 }
var x = if n == 0 { result1 } else if n == 1 { result2 } else { result2 }

// Multi-line if
var x = if n == 0 {
  result1
} else if n == 1 {
  result2
} else {
  doSomethingBeforeReturning();
  result2
}

// if-statement as a function argument:
writer.printLn(

  if n == 0 { result1 }
  else if n == 1 { result2 }
  else { doSomethingBeforeReturning(); result2 });

// Match statement
var x = match n {
  as s:String { "String" }
  as t:Type { "Type" }
  as * { "Other" }
}

// Switch statement
var x = switch n {
  case 1 { "one" }
  case 2 { "two" }
  case * { "none" }
}

// With statement
var str = with f:open(file) {
  ",".join(f.lines())
}

// With statement with multiple values
var str = with (f1:open(file2), f2:open(file2)) {
  ",".join(f1.lines()) + ",".join(f2.lines())
}


In my earlier post, I suggested that try/catch also be usable as an expression, however there's a bit of a problem there, which is what to do with 'finally'? When used without a 'finally' statement, the flow of control in a try/catch always reaches the end of one and only one block - so you know exactly which value is returned. With 'finally', however, it's not clear whether the value returned is the one at the end of the finally block, or one of the other blocks.

No comments:

Post a Comment