Closure sample code?

I’m trying to figure out syntax of Closure (the syntax docs not always agree with me).

Here’s so far I figured:

!foo:  ^_
  [
  _wait(0.2) 
  println("abc ")
  ]

4._do foo

But how to declare and pass arguments? That’s well I totally lost. Any code snippets will be much appreciated!

Thanks!

Closures are one of the most powerful constructs of SkookumScript - and some of the most tricky to understand their syntax.

As you may know - what you wrote above can be written more simply (if you don’t need to store the closure for reuse in a variable) by using closure tail arguments:

4._do
  [
  _wait(0.2) 
  println("abc ")
  ]

When a closure is passed as an argument to a routine, you don’t have to specify anything other than its code block - the rest is inferred from the parameters - including all the parameters for the closure: their names and types. Also whenever the last argument of a routine is a closure, the routine parentheses are not needed. This allows you to make routines that look similar to built-in language flow control commands.

You can see a few example routines that use closures as their last argument by pressing Ctrl + Alt + G in the Skookum IDE to search for routines. Just set Script and not C++ and type in do in Search for:. You can Ctrl + mouse click on each routine to see how it is written and all have examples too.

Since closures are much simpler to use when they are passed as arguments (and they can just be simple code blocks) - I recommend that you use them that way whenever you can.

If you really want to create a closure without being initially used as an argument, you need to specify any parameters that it will take as well as an optional this/receiver.

The main areas of the syntax that use closures are closure, closure tail arguments, and invoke class. Each of these has additional footnotes. I’ll edit them in the near future to make them more clear.

I’ll add more to this entry in a bit or write up a full documentation page entry on closures.

Here are some other examples:

!triple: (Integer x)[3 * x]
triple(4) // returns 12


//==========================================
!robo1: Enemy.named("RoboChar1")
!boom_path: (Enemy robo)[robo._boom robo._path_to_actor(player_pawn)]

boom_path(robo1)

// This is the long form of boom_path above
!boom_path2: ^_ this // Make a coroutine closure using the current this
  (Enemy robo)
    [
    robo._boom()
    robo._path_to_actor(this.player_pawn())
    ]

boom_path2(robo1)

// Here is a closure using robo1 directly
// - capturing the `robo1` and `player` variables from the context
// If there are no parameters you can start a closure with () or ^
!player: player_pawn
!boom_path_r1a: ^[robo1._boom robo1._path_to_actor(player)]

boom_path_r1a()

// Here robo1 is used as the `this` for the closure

!boom_path_r1b: ^robo1[_boom _path_to_actor(player)]

boom_path_r1b()


//==========================================
// Here are some comparisons to closures in Swift just for fun
// These methods *make* closures

// Swift example #1
func make_incrementor(for_increment amount: Int) -> () -> Int
  {
  var running_total = 0
  
  func incrementor() -> Int
    {
    running_total += amount
    
    return running_total
    }
    
  return incrementor
  }
  

// Skookum
//make_incrementor().sk
(Integer amount) () Integer
  [
  !running_total: 0
  
  !incrementor: () Integer
    [
    running_total += amount
    ]
    
  incrementor  
  ]

// Simplifications
// No need to store closure in a variable
(Integer amount) () Integer
  [
  !running_total: 0
  
  () Integer
    [
    running_total += amount
    ]
  ]

// No need to store the initial 0 in a variable - make it `this`
(Integer amount) () Integer
  [
  ^0 () Integer
    [
    this += amount
    ]
  ]
  
// The `Integer` return type can be inferred
(Integer amount) () Integer
  [
  ^0 [this += amount]
  ]
  
// Instead of a method, it could be a closure that makes closures
!make_incrementor: (Integer amount) [^0 [this += amount]]



// Swift example #2
func make_incrementor(initial_value: Int = 0) -> () -> Int
  {
  func incrementor() -> Int
    {
    initial_value++
    return initial_value
    }
  return incrementor
  }
  

// Skookum
//make_incrementor().sk
(Integer initial_value: 0) () Integer
  [
  !incrementor: () Integer
    [
    initial_value++
    ]
  incrementor  
  ]

// No need to make variable to return
(Integer initial_value: 0) () Integer
  [
  () Integer
    [
    initial_value++
    ]
  ]

// Use the variable as `this`
(Integer initial_value: 0) () Integer
  [
  ^initial_value [this++]
  ]

// Closure that makes closures
!make_incrementor: (Integer initial_value: 0) [^initial_value [this++]]

The compiler can determine that it is a coroutine closure without you specifying the underscore after the caret ^_. These three closures are identical - try pressing Shift+F4 on each line separately:

!closure1: ()[_wait]
!closure2: ^[_wait]
!closure3: ^_[_wait]

You will see that all three will print the same result - and they all have the ^_:

^_ this: 'SkookumDemo'
  ()
    [
    this._wait()
    ]
1 Like

Another epic answer and what a pleasure reading! Thanks Noolarch!

2 posts were split to a new topic: [Resolved] Coroutine closure parse bug