Heavily inspired by kotlin and groovy, what would the following syntax simplication enable?
a {}
// syntact sugar for
a(function() {});
?
Really great considetations here!
http://wirfs-brock.com/allen/files/jshistory/continue-break-lambda.pdf
This only works for statements (so, not allowed inside expressions), but ...
function unless(block) {
if (!expr) {
return block();
}
}
while (true) {
unless (false) {
break;
}
}
Could desugar to:
while (true) {
{
let result = unless (false, function() {
return {break: true};
});
if (result.break) {
break;
} else if (result.continue) {
break;
} else if (result.return){
return result.value;
}
// otherwise, just carry on ...
}
}
Here is how ruby deals with these challenges:
def foreach(list)
puts "Running foreach on #{list}"
# you can call the block using the yield keyword
for i in list
puts yield(i)
end
puts "End of method"
end
puts ""
puts ""
puts "Sample #1: basic usage of blocks"
puts ""
puts ""
foreach (0..2) {
# This is how you declare arguments to the block
|value|
puts "Hi from the block with args: #{value}"
'A return value!'
}
puts ""
puts ""
puts "Sample #2: breaks inside blocks"
puts ""
puts ""
# breaks just return from the block and return null.
result = foreach (2..3) {
puts "Hi from block with break!"
break
}
puts "Result is nil, right? #{result == nil}."
puts ""
puts ""
puts "Sample #3: breaks inside blocks with for-loops nested"
puts ""
puts ""
# For example, break inside a lambda doesn't leave the
# outer lambda:
for i in 0..2
puts "Iterating: #{i}!"
foreach (0..i) {
|value|
puts "Iterating #{value}"
# This only leaves the inner foreach, not the outer for
break
}
end
puts ""
puts ""
puts "Sample #4: what does continue do?"
puts ""
puts ""
# For example, break inside a lambda doesn't leave the
# outer lambda:
for i in 0..2
puts "Iterating: #{i}!"
foreach (0..i) {
|value|
puts "Iterating #{value}"
# This only leaves the inner foreach, not the outer for
next
}
end
puts ""
puts ""
puts "Sample #5: what does return do?"
puts ""
puts ""
def foo
foreach (0..0) {
return "hello world"
}
return "not this"
end
# Returns "hello world" rather than "not this".
foo()
And console:
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]
Sample #1: basic usage of blocks
Running foreach on 0..2
Hi from the block with args: 0
A return value!
Hi from the block with args: 1
A return value!
Hi from the block with args: 2
A return value!
End of method
Sample #2: breaks inside blocks
Running foreach on 2..3
Hi from block with break!
Result is nil, right? true.
Sample #3: breaks inside blocks with for-loops nested
Iterating: 0!
Running foreach on 0..0
Iterating 0
Iterating: 1!
Running foreach on 0..1
Iterating 0
Iterating: 2!
Running foreach on 0..2
Iterating 0
Sample #4: what does continue do?
Iterating: 0!
Running foreach on 0..0
Iterating 0
End of method
Iterating: 1!
Running foreach on 0..1
Iterating 0
Iterating 1
End of method
Iterating: 2!
Running foreach on 0..2
Iterating 0
Iterating 1
Iterating 2
End of method
Sample #5: what does return do?
Running foreach on 0..0
=> "hello world"
Another example in Ruby:
def iffy(condition)
if (condition) then
yield()
end
end
iffy (true) {
puts "This gets executed!"
}
iffy (false) {
puts "This does not"
}
for i in 0..1
puts "Running: #{i}"
iffy (i == 0) {
# This does not break from the outer loop!
# Prints
#
# Running: 0
# Running: 1
break
}
end
for i in 0..1
iffy (i == 0) {
# This does not continue from the outer loop!
# Prints
#
# Running: 0
# Running: 1
next
}
puts "Running: #{i}"
end
def foo()
iffy (false) {
return "never executed"
}
iffy (true) {
return "executed!"
}
return "blargh, never got here!"
end
# Prints "executed!"
foo()
Kotlin disallows break
and continue
inside blocks:
fun unless(condition: Boolean, block: () -> Unit) {
if (condition) {
block()
}
}
fun main(args: Array<String>) {
println("Hello, world!")
while (true) {
unless(true) {
println("hello")
// Error:(11, 12) 'break' or 'continue' jumps
// across a function or a class boundary
// break
// 'return' is not allowed here
// return
}
}
}
fun case(condition: Boolean, block: () -> Unit) {
println("This gets called!")
block()
}
fun select(condition: Boolean, block: () -> Unit) {
block()
}
fun main(args: Array<String>) {
var expr: Boolean = true;
select (expr) {
case (true) {
println("Totally true")
}
case (true) {
println("Totally false")
}
}
}
Interesting use case in constructors for Ruby:
https://mixandgo.com/blog/mastering-ruby-blocks-in-less-than-5-minutes
let car = new Car() {
::color = 1;
::size = "large";
}
Could that lead to something like abstract classes?
sort([2, 3, 1, 4], new Comparator() {
::compare do (a, b) {
return a < b;
}
})
continue
andbreak
break
can break out of any block. For example:Apparently, you need to be lexically nested to
break
to labels. For example:Works with
if
:Whether it is a modifier that gets used in the call site (e.g.
for each(array) {}
) or at the declaration site (e.g. ```loop function foreach() { ... }). For example, you used a modifier in the function call:It gets desugared to:
For example:
For example:
FAQ
What happens with nested block params? E.g.
Annex
continue
andbreak
can take a label as a parameter:labels