Extremely Serious

Category: Gosu

Functional Programming with Gosu

First Class Citizen

An entity that can be passed around as an argument, returned from a function, modified and assigned to a variable.

First Class Function

A function that is treated as first class citizen.

Higher-Order Functions (HOF)

A function which takes function as an argument and/or that return a function.

Closure

A function that remembers its lexical scope even when the function is executed outside that lexical scope.

function greeterFn() : block() {
  var name="World" //name is a local variable created by init
  var greet = \-> print("Hello ${name}") //greet is an inner function 
                                         //that uses the variable declared 
                                         //in parent function.
  return greet
}

var greeter = greeterFn()
greeter()

Currying

The process of converting a function that takes multiple arguments into a function that takes them one at a time.

var sum = \ a : int, b : int -> a + b
print(sum(1,2))

var curriedSum = \ a : int -> \ b : int -> a + b
print(curriedSum(1)(2))

Function Composition

The act of putting two functions together to form a third function where the output of one function is the input of the other.

uses java.lang.Integer
uses java.lang.Double
uses java.lang.Math

var compose = \ output : block(out : Integer) : String, func : block(param: Double) : Integer -> \ arg : Double -> func(output(arg)) //Definition

var floorToString = compose(\ out -> out.toString(), \ param -> Math.floor(param)) //Usage

print(floorToString(121.212121))

Continuation

The part of the code that's yet to be executed.

uses java.lang.Double

var printAsString = \ num : Double -> print("Given ${num}")

var addOneAndContinue = \ num: Double, cc : block(___num : Double) -> {
  var result = num + 1
  cc(result)
}

addOneAndContinue(2, printAsString)

Purity

A function is pure if the return value is only determined by its input values, and does not produce side effects.

var greet = \ name: String -> print("Hello ${name}")
greet("World")

The following is not pure since it modifies state outside of the function:

var greeting : String
var greet = \ name: String -> {greeting ="Hello ${name}"}
greet("World")
print(greeting)

Side Effects

A function or expression is said to have a side if apart from returning a value, it interacts with (reads from or writes to) external mutable state.

var currentDate = java.util.Date.CurrentDate //Retrieves the date from the system.
print(currentDate)

gw.api.util.Logger.forCategory("side-effect").info('IO is a side effect!')

Idempotent

A function is idempotent if reapplying it to its result does not produce a different result.

print(java.lang.Math.abs(java.lang.Math.abs(10)))

Point-Free Style (Tacit Programming)

Write functions where the definition does not explicitly identify the arguments used. This style usually requires currying or other higher order functions.

uses java.lang.Integer

// Given
var map = \ fn : block(item : int) : int -> \ list : List<Integer> -> list.map<Integer>(\ item -> fn(item))
var add = \ a : int -> \ b : int -> a + b
var nums : List<Integer> = (0..5).toList()

// Not points-free - 'numbers' is an explicit argument
var incrementAll = \ numbers : List<Integer> -> map(add(1))(numbers)

print(incrementAll(nums))

// Points-free - The list is an implicit argument
var incrementAll2 = map(add(1))

print(incrementAll2(nums))

Predicate

A function that returns true or false for a given value.

var predicate = \ a : int -> a > 2

print((1..4).where(\ a -> predicate(a)))

Lambda

An anonymous function that can be treated like a value.

(\ a : int -> a + 1)(1)

Lambda can be assigned to a variable

var add1 = \ a : int -> a + 1
print(add1(1))

Reference

https://github.com/hemanth/functional-programming-jargon
https://en.wiktionary.org/wiki/second-class_object#English
https://en.wiktionary.org/wiki/third-class_object#English

Gosu Collection Enhancements Functions

flatMap

Maps each element of the Collection to a Collection of values and then flattens them into a single List.

Syntax

flatMap<R>(mapper(item : Collection<?>) : Collection<R>) : List<R>

Example

var items = {{1},{2,2},{3,3,3},{4,4,4,4}}
print(items.flatMap(\ ___item -> ___item))
Output
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

fold

Accumulates the values of an Collection into a single T.

Syntax

fold(aggregator(aggregate : T, item : T) : T) : T

Example

var items = {{1},{2,2},{3,3,3},{4,4,4,4}}
var flatItems = items.flatMap(\ ___item -> ___item)
print(flatItems.fold(\ ___aggr, ___item -> ___aggr + ___item))
Output
30

intersect

Returns a Set that is the intersection of the two Collection objects.

Syntax

intersect(that: Collection<T>) : Set<T>

Example

var items1 = {1,2,3,4,5,6}
var items2 = {4,5,6,7,8,9}
print(items1.intersect(items2))
Output
[4, 5, 6]

map

Returns a List of each element of the Collection mapped to a new value.

Syntax

map<Q>(mapper(item : <INPUT>) : <Q>) : List<Q>

Example

var numbers = {1,2,3}
var words = {"one","two","three"}
print(numbers.map(\ ___number -> words[___number-1]))
Output
[one, two, three]

partition

Partitions this Collection into a Map of keys to a list of elements in this Collection.

Syntax

partition<Q>(partitioner(item : R) : Q) : Map<Q, List<R>>

Example

var numbers = {1,2,3,4,5,6,8}
print(numbers.partition<String>(\ ___number -> ___number % 2 == 0 ? "even" : "odd"))
Output
{even=[2, 4, 6, 8], odd=[1, 3, 5]}

reduce

Accumulates the values of a Collection into a single V given an initial seed value

Syntax

reduce<T>(init : T, aggregrator(aggregate: T, item : ?) : T) : T

Example

var numbers = {1,2,3,4,5,6,8}
var sumOfNumbers = numbers.reduce(0, \ ___aggr, ___number -> ___aggr + ___number)
print(sumOfNumbers)
Output
29

union

Returns a new Set that is the union of the two Collections

Syntax

union(that : Collection<T>) : Set<T>

Example

var items1 = {1,2,3,4,5,6}
var items2 = {4,5,6,7,8,9}
print(items1.union(items2))
Output
[1, 2, 3, 4, 5, 6, 7, 8, 9]

disjunction

Returns a new Set that is the set disjunction of this collection and the other collection

Syntax

disjunction(that : Collection<T>) : Set<T>

Example

var items1 = {1,2,3,4,5,6}
var items2 = {4,5,6,7,8,9}
print(items1.disjunction(items2))
Output
[1, 2, 3, 7, 8, 9]

join

Joins all elements together as a string with a delimiter

Syntax

join(delim : String) : String

Example

var words = {"Hello", "World"}
print(words.join(" "))
Output
Hello World

Writing and Reading Into and From a Text File in Gosu

Writing into a Text File in Gosu

To write into a text file in gosu we can use the FileWriter as follows:

using(var writer = new BufferedWriter(new FileWriter("<FILENAME>"))) {
  writer.write("<TEXT>")  // Writes a text to into a file.
  writer.flush() // Must be at the last.
}
Token Description
FILENAME The target filename to write into.
TEXT The text to write into the filename. You can write as many text as you like. Just don't forget the flush method at the end.

Reading from a Text File in Gosu

To read from a text file in gosu we can use the FileReader with Scanner as follows:

using (var scanner = new Scanner(new BufferedReader(new FileReader("<FILENAME>")))) {
  while(scanner.hasNext()) {
    print(scanner.nextLine()) //---Reads a line from the file.
  }
}
Token Description
FILENAME The target filename to read from.

Using Reduce Method to do AND and OR Testing

If the if conditions are becoming longer and complicated. It is possible to separate all the conditions to a list like the following:

var conditions : List<block() : Boolean>= {
  \-> {
    print("1")
    return true
  }, 
  \-> {
    print("2")
    return false
  }
}

The above example is just a simple illustration and not good for actual coding.

The following code snippet is for hunting at least one truth condition using reduce method to do OR logic testing.

if (conditions?.reduce(false, \ ___aggr, ___cond -> ___aggr || ___cond())) {
  print("I'm in")
}

Once a truth condition was identified it stops checking the rest and the if condition is evaluated to true.

The following code snippet is for checking all the conditions are true using the reduce method to do AND logic testing.

if (conditions?.reduce(true, \ ___aggr, ___cond -> ___aggr && ___cond())) {
  print("I'm in")
}

Once a false condition was identified it stops checking the rest and the if condition is evaluated to false.

Using Map to Code Conditionally without using the If statement

Preface

The following is an example of conditional programming using the key of the map as the condition and the value is the logic to be executed when a particular key was satisfied.

uses java.util.LinkedHashMap

var mainLogicIfRegistry : LinkedHashMap<block(___param : int) : boolean, block()>
 = {
  \ ___param : int -> 1 == ___param -> \ -> {print("one-0")},
  \ ___param : int -> 1 == ___param -> \ -> {print("one-1")},
  \ ___param : int -> 2 == ___param -> \ -> {print("two")},
  \ ___param : int -> 3 == ___param -> \ -> {print("three")}
}

(1..4).each(\ ___idx -> 
  mainLogicIfRegistry.Keys.where(\ ___cond -> ___cond(___idx))
    .each(\ ___key -> mainLogicIfRegistry.get(___key)())
)

We are using a LinkedHashMap in the example to make the execution based on the order of entries the logic were added in the map. If we are not that concern about the order of logic we can just use a regular map (i.e. HashMap).

Inspecting the First Entry in the Map

Let's see how the following first logic was registered in the map.

\ ___param : int -> 1 == ___param -> \ -> {print("one-0")}

The key part of the entry here is the following:

\ ___param : int -> 1 == ___param

The value part of the entry here is the following:

\ -> {print("one-0")}

As we can see both the key and value are lambda expressions and we can repeat the same lambda expression (i.e. but must be different instances) as the key (i.e. as long as you instantiate them separately) since those two are different instances of a block. Knowing this, we can filter the map based on the key (i.e. condition logic) and if it returns true use that key instance to retrieve the value (i.e. logic to execute) from the map.

Note: The lambda expression on the keys must have the same argument signatures. Because the key of the map must be of a consistent type.

Lets interpret the key part, all the lambda expressions of the key requires a parameter (i.e. for consistency of the block instance generated from the lambda expression). So it has one, and is being used to compare to 1. Actually both the first and second entries has the same lambda implementation but with different instances of block. Thus, when we pass in 1, both the first and the second entries will be executed.

Now for the value part, it is just printing the string one-0. To distinguish this from the second entry (i.e. since both the first and second entries has the same lambda expression), the second entry prints the string one-1.

Executing the Entries in the Map

Execute a particular entries using the following statement:

mainLogicIfRegistry.Keys.where(\ ___cond -> ___cond(___idx)).each(\ ___key -> mainLogicIfRegistry.get(___key)())

Lets dissect the statement above. We filter the key by executing the logic in the key like the following (i.e. ___idx is a argument of the lambda expression):

mainLogicIfRegistry.Keys.where(\ ___cond -> ___cond(___idx))

Once all the targeted keys were found execute each one like the following:

.each(\ ___key -> mainLogicIfRegistry.get(___key)())

If we execute the code from the preface it will be like this:

one-0
one-1
two
three

As we can see, both the 1 were executed (i.e. one-0 and one-1) followed by the 2 and 3. And since there's no entry for the 4 nothing was executed for it.

Unit Test with Expando Object

Introduction

Expando object can make dynamic object, properties and methods if you like. This can be used for stubbing an object to be used for testing.

For example if have the following:

Code 1 - processor function that requires the SSampleStructure structure

//Structure works with objects with similar features but no common inheritance and interface declarations
structure SSampleStructure {
  function someAction() : int
}

function processor(sample : SSampleStructure) : int {
  return sample.someAction() + 10
}

The SSampleStructure structure will be compliant to all the classes that has someAction function that returns an int. And the actual compliant implementation of the structure is the following:

Code 2 - Actual implementation that is compatible with SSampleStructure

class SampleCodeWithStaticMethods {

  private construct() {}

  function someAction() : int {
    return (Math.round(Math.random()*100) as int) + 100
  }
}

We can notice that in Code 2, we cannot have a consistent output for someAction method since it is return arbitrary values. And what the processor function does is just add 10 on it.

What we can do here is to create an Expando object that will also comply with SSampleStructure structure like the following:

Code 3 - Using Expando class

uses gw.lang.reflect.Expando
  
    // By declaring the Dynamic type for the variable or function argument, you can
// programmatically access any property or method without requiring compile-time confirmation of its existence.
var testObj : Dynamic =

// An expando object is an object whose properties, and potentially methods, are created dynamically on assignment.
    new Expando()

// We can attached function using the block syntax as below.  
testObj.someAction = \ -> 25

Since the testObj of Code 3, also has someAction function that returns an int. This is compliant with SSampleStructure structure. So we can safely run the following test of logic without any problem:

Code 4 - Actual test

function testProcessor() {
  print("Is35: " + (processor(testObj)==35))
}

testProcessor()

As we can see from Code 4, we are using testObj to test the processor method.

Singleton with Variable State

Looking at the following SingletonUtil class we know we can call generateXML method safely.

Code 1: SingletonUtil class for Studio Terminal

static class SingletonUtil {
  var _sbString : StringBuilder
  
  private static var _SELF : SingletonUtil as Instance = new SingletonUtil()

  private construct() {
    _sbString = new StringBuilder()
  }
  
  function generateXML(text : String) : String {
    _sbString.append("")
    _sbString.append(text?:"")
    _sbString.append("")
    var output = _sbString.toString()
    using(_sbString as IMonitorLock) {
      _sbString.delete(0, _sbString.length())
    }
    return output
  }
}

If we generate the XML like the following:

Code 2: GenerateXML via single thread.

print(SingletonUtil.Instance.generateXML("test"))
print(SingletonUtil.Instance.generateXML("test"))
print(SingletonUtil.Instance.generateXML("test"))

The output will be as expected and we can say it is safe:

Output 1

<text>test</text>
<text>test</text>
<text>test</text>

We are complacent that everything is working good since we can run it and can generate the expected Output 1. But don’t forget we are running it in a single thread. Thus we can say that this code is safe for single thread.

Lets try the same but this time with 10 threads and we are expecting the output to be like this:

Output 2

<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>

Run the following code in terminal:

Code 3: GenerateXML via multithread.

for (var idx in (1..10)) {
  var thread = new Thread(new Runnable() {
    override function run() {
      print(SingletonUtil.Instance.generateXML("test"))
    }
  })
  thread.start()
}

We will have a hard time generating our expected output this time. And we can say that this not thread-safe. There are three things we can do about this.

1.) If we don't have the source code, we can use locking on the client code. Let's use IMonitorLock for the simplicity and run it in studio terminal. The updated client code can be like the following and can generate Output 2:

Code 4: GenerateXML via multithread with locking.

for (var idx in (1..10)) {
  var thread = new Thread(new Runnable() {
    override function run() {
      var inst = SingletonUtil.Instance
      using(inst as IMonitorLock) {
        print(inst.generateXML("test"))
      }
    }
  })
  thread.start()
}

2.) If we have the source code and can update it, we can make the whole generate XML method to be synchronized like the following and use Code 3 to generate Output 2:

Code 5: SingletonUtil class for Studio Terminal with the whole generateXML is locking.

static class SingletonUtil {
  var _sbString : StringBuilder
  
  private static var _SELF : SingletonUtil as Instance = new SingletonUtil()

  private construct() {
    _sbString = new StringBuilder()
  }
  
  function generateXML(text : String) : String {
    using(_sbString as IMonitorLock) {
      _sbString.append("")
      _sbString.append(text?:"")
      _sbString.append("")
      var output = _sbString.toString()
      _sbString.delete(0, _sbString.length())
      return output
    }
  }
}

3.) If we have the source code and can update it, try to remove the variable state like the following and use Code 3 to generate Output 2:

Code 6: SingletonUtil class for Studio Terminal without shared state.

static class SingletonUtil {
  private static var _SELF : SingletonUtil as Instance = new SingletonUtil()

  private construct() {
  }
  
  function generateXML(text : String) : String {
    var _sbString = new StringBuilder() 
    _sbString.append("")
    _sbString.append(text?:"")
    _sbString.append("")
    var output = _sbString.toString()
    return output
  }
}

Refactoring difficult class to test to testable in Gosu

Use case

Normally if we like to create a utility class we normally implement it with static methods.

Problem

This is good if we can write unit tests on it. But most of the time this is not the case since it is difficult to write a unit on it. Specially, if the utility class that have a lots of static methods inside that depends on each other. For example, the following piece of code (i.e. Code 1) even though small authoring a test could be difficult.

Code 1. Small class that cannot be tested easily.

package example

uses java.lang.Math

class SampleCodeWithStaticMethods {

private construct() {}

static function myMethod() {
 var value = someAction() + 10
 print(value)
 }

static function someAction() : int {
 return (Math.round(Math.random()*100) as int) + 100
 }

}

Imagine write a unit test for myMethod. It is almost impossible because the method depends on someAction which is also a static method that returns random integer.

We need to refactor this to make it testable. The first thing we can do is identify if there are other static methods being called that are not a member of the class and make a separate non-static method for them. From code 1, those static method calls are:

- Print
- Math.round
- Math.random

Call those new member instance methods in place of the static method call. Making them contained in a separate method allows us to bypass them by overriding on a child class (i.e. basic OOP principle).

The next thing is remove all the static modifiers to convert all of them to member instance methods.

The refactored code would be like the following code.

Code 2. Refactored to use non-static methods

package example
uses java.lang.Math

class SampleCodeWithoutStaticMethods {

//Contains the call the to static print method.
 function output(value : int) {
 print(value)
 }

//Contains the call the Math.round and Math.random.
 function random() : int {
 return (Math.round(Math.random()*100) as int)
 }

function myMethod() {
 var value = someAction() + 10
 //Calls the member method that contains the static print method.
 output(value)
 }

function someAction() : int {
 return random() //Calls the member method that contains the static Math.round and Math.random method.
 + 100
 }

}

Now testing myMethod becomes so trivial (i.e. Code 3) using the very old behaviour of OOP (i.e. being polymorphic). The key is the inner class SampleCodeWithoutStaticMethodsMyMethod where we overrode someAction and output instance methods.

The someAction method now just return 25 which makes it more consistent than its original random behaviour.

The output method is just collecting what's being passed to it to result field instead of printing it.

Code 3. Unit test for myMethod

package example

uses gw.api.system.server.Runlevel
 uses gw.testharness.RunLevel

@gw.testharness.ServerTest
 @RunLevel(Runlevel.NONE)
 class SampleCodeWithoutStaticMethodsTest extends gw.testharness.TestBase {

class SampleCodeWithoutStaticMethodsMyMethod extends SampleCodeWithoutStaticMethods {
 var result : int

override function someAction() : int {
 return 25
 }

override function output(value : int) {
 result = value
 }
 }

function testMyMethod() {
 var testObj = new SampleCodeWithoutStaticMethodsMyMethod()
 testObj.myMethod()
 assertEquals(35, testObj.result)
 }

}