Exit Full View

Feather2 / documentation / FunctionTypes.md

Function Types

Function Types are a feature not seen in Java (AFAIK).

They are similar in spirit to lambdas, but the implementation is much simpler.

Let's take a look at an example :

class Foo {

    // Nothing weird here yet!
    func plus( a : double, b : double ) = a + b
    func minus( a : double, b : double ) = a - b
    
    // This is odd.
    var myFunction = ::plus

    func applyFunction( a : double, b : double ) : double {
        // This looks simple, but `myFunction` is a `var`, not a `func` or `meth`.
        return myFunction( a, b )
    }
}

myFunction is a field, whose type is a Function, which takes two double arguments, and returns a double. We could have explicitly stated the type in the var definition :

var myFunction : (double, double)->double = ::plus

We can call (invoke) a Function just like we would a regular fun :

myFunction( 1, 2 )

The result is obviously 3, when myFunction == ::plus. But myFunction is a var, so we could change it to ::minus, or any other function with the same argument types and return type.

A function can be treated like any other object. It can be passed as an argument to a func or meth, stored in fields/lists/arrays etc.

Curried Functions

Currying a function means we give one or more arguments to the Function, without invoking the Function.

For example, we can curry myFunction like so :

val myCurriedFunction = myFunction.curry( 4 )

myCurriedFunction is also a Function, but as the first parameter is already given, myCurriedFunction now only has a single argument. We could have explicitly stated its type like so :

val myCurriedFunction : (double)->double = myFunction.curry( 4 )

To invoke it :

myCurriedFunction( 2 )

The result is 6 (4+2), assuming myFunction is ::plus.

Note that myCurriedFunction is NOT the same type as myFunction, because they have different arguments.

meth vs func

In the example above the ::plus is a func. We can also use methods (meth). In which case, the first argument to the Function is the instance of the class.

How it works

Function is a regular Java class in the Feather runtime. When a Function is created, it is passed a Java Method (from the java.lang.reflect package)

Invoking the function calls Method.invoke.

Differences with Java/Kotlin Lambdas

  1. Functions are simpler. They only have access to their parameters.
  2. Functions ultimately use plain old func or meth, you cannot (yet) create a Function from an in-line expression or block of code.

Lambdas are much more powerful, because they don't have either of these limitations.

However, there's no simple equivalent of currying with lambdas.

Why?

Why did I implement Functions, when lambdas are more powerful, and easy to use?

Quite frankly, lambdas are really tricky to implement, whereas Functions are dead easy!

I fondly remember using pure functional languages, where functions as first-class-citizens is the norm, and currying is common. So I wanted to see how this could work in Feather.

Back to Contents