# 5.2. Functions¶

This chapter describes types of functions, and construction of functions.

## 5.2.1. Types of functions¶

### 5.2.1.1. Methods¶

A method is a function stored in a value.

method

A function which is stored in a variable of a value, and used to do an operation for the value as the receiver.

The value which has a method.

Assume you make a single-element immutable container type `just`, which has one method: `get`. This type can be defined and used as follows.

```:new_just <- {(:Val)
new_val(
... Just_trait
'Val' Val
)
}

:Just_trait <- [

# [1]
'get' {[:J]()
J.Val
}
]

:Just <- new_just(42)

# [2]
:V <- Just.get
stdout.print_line(V.repr)  # => 42
```

`get` method is called at [2]. The receiver `Just` is passed to `J` in the implementation of `get` at [1].

### 5.2.1.2. Constructors¶

A value is usually created by a function called constructor.

constructor

A function which creates a new value.

Usually, a constructor is named `new`. For example, suppose a module named `example/RAT` provides functionality of rational numbers. In `example/RAT` mod, a constructor of a rational number can be defined as follows:

```# example/RAT.kn

:new <- {(:Numer :Denom)
new_val(
'numer' {[:R]() R.Numer }
'denom' {[:R]() R.Denom }
'repr' {[:R]()
'(rat numer={} denom={})'.format(R.numer.repr R.denom.repr)
}

'Numer' Numer
'Denom' Denom
)
}
```

This constructor can be called from a client of the mod as follows:

```:RAT.require_from('example/')

stdout.print_line(RAT.new(2 5).repr) # => (rat numer=2 denom=5)
stdout.print_line(RAT.new(3 7).repr) # => (rat numer=3 denom=7)
```

Apparently, `numer`, `denom`, and `repr` methods can be shared among rational number values. Thus, usually, methods and the syms are stored in a vec called a trait, then they are spreaded as arguments of `new_val`.

trait

A vec which stores methods and the syms, which are spreaded as arguments of `new_val`.

For example, `example/RAT` mod can be rewritten as follows, using a trait `Rat_trait`.

```# example/RAT.kn

:new <- {(:Numer :Denom)
new_val(
... Rat_trait
'Numer' Numer
'Denom' Denom
)
}

:Rat_trait <- [
'numer' {[:R]() R.Numer }
'denom' {[:R]() R.Denom }
'repr' {[:R]()
'(rat numer={} denom={})'.format(R.numer.repr R.denom.repr)
}
]
```

### 5.2.1.3. Thunks¶

thunk

A function which does not take an argument.

This is a thunk:

```{() stdout.print_line('hello') }
```

This is also a thunk:

```{ stdout.print_line('hello') }
```

A thunk is used to delay evaluation until its result or side-effect is needed. In the example below, only one of two thunks `negative_cont` and `non_negative_cont` is called based on the sign of `Num`.

```:branch_on_sign <- {(:Num :negative_cont :non_negative_cont)
if(Num < 0
{ negative_cont }
{ non_negative_cont }
)
}

# => negative
branch_on_sign(
-1
{ stdout.print_line('negative') }
{ stdout.print_line('non negative') }
)

# => non negative
branch_on_sign(
1
{ stdout.print_line('negative') }
{ stdout.print_line('non negative') }
)
```

### 5.2.1.4. Constants¶

constant

A thunk which returns the same value every time.

A constant can be made like this:

```:Result_of_heavy_calculation <- 42

# constant which returns 42

```

See LOCALE.root of kink/LOCALE mod and TRACE.snip of kink/TRACE mod for examples in the builtin API.

The reason of providing constants as functions is to maintain a principle that only functions can be public, while data variables cannot. See Accessibility.

### 5.2.2.1. Optional and variadic parameters¶

If you want to take optional arguments after mandatory ones, you can use `Varref.opt` as follows.

```:posix_locale_tag <- {(:Lang :Opt_territory.opt :Opt_charset.opt)
:Territory = Opt_territory.just_or{ 'US' }
:Charset = Opt_charset.just_or{ 'UTF-8' }
stdout.print_line('{}-{}.{}'.format(Lang Territory Charset))
}

posix_locale_tag('en' 'GB' 'ASCII') # => en-GB.ASCII
posix_locale_tag('en' 'GB') # => en-GB.UTF-8
posix_locale_tag('en')      # => en-US.UTF-8
```

As shown above, if an argument is given to the optional parameter, a single element vec containing the argument is passed to the variable. If no argument is given to the optional parameter, an empty vec is passed to the variable.

See kink/param/OPT_PARAM for details.

If you want to take variadic arguments at the end of the arguments list, you can use `Varref.rest` as follows.

```:commandline <- {(:Command :Args.rest)
stdout.prine_line('command: {}'.format(Command))
Args.size.times{(:I)
stdout.prine_line('arg #{}: {}'.format(I Args.get(I)))
}
}

commandline('ls' '-ltr' '/etc')
# Output:
#   command: ls
#   arg #0: -ltr
#   arg #1: /etc
```

See kink/param/REST_PARAM for details.

You can take both optional and variadic arguments.

```:take_opt_variadic <- {(:Mandatory :Opt.opt :Rest.rest)
stdout.prine_line('Mandatory {}'.format(Mandatory.repr))
stdout.prine_line('Opt {}'.format(Opt.repr))
stdout.prine_line('Rest {}'.format(Rest.repr))
}

# Output:
#   Mandatory "foo"
#   Opt ["bar"]
#   Rest ["baz" "qux"]
```

### 5.2.2.2. Config functions¶

When positional optional parameters are not flexible enough, a config function can be used.

For example, PROGRAM.compile (see kink/PROGRAM) can take a binding, a locale, a program name, and other optional values, and each can be omitted independently. For that case, optional parameters are not appropriate. Assuming that the parameter list is `(Text, opt Binding, opt Locale, opt Program_name)`, you cannot omit only `Binding`, while specifying `Locale` and `Program_name`.

So, PROGRAM.compile takes an optional config function at the end of the parameter list. The client of PROGRAM.compile can specify a binding, a locale, and a program name, by calling methods of a config val, which is passed to the config function.

```:PROGRAM.require_from('kink/')
:LOCALE.require_from('kink/')
:BINDING.require_from('kink/')

:print_num <- PROGRAM.compile('stdout.print_line(Num.repr)'){(:C)
:Binding = BINDING.new
Binding:Num <- 42
C.binding(Binding)
}
print_num # => 42

:zero_division <- PROGRAM.compile('10 // 0'){(:C)
C.name('calc.kn')
C.locale(LOCALE.for('en'))
}
zero_division
# Output:
#   -- main exception
#   [(root)]
#   ,,,
#   {calc.kn L1 C4 op_intdiv} 10 -->// 0
#   Num.op_intdiv(Divisor): zero division: 10 is divided by 0
```

Here, the last parameter of PROGRAM.compile is a config function. The parameter `C` of the config function is a config value.

If you provide a function which takes a config function, and the config value is simple enough, you can use kink/CONFIG_FUN_RUNNER.

Config functions can be seen as an alternative aproach to named parameters of other languages. The most notable advantage of config functions is that they don't need a dedicated syntax. A config function is just the last argument passed to the configured function.

## 5.2.3. Function result¶

### 5.2.3.1. Return value¶

In most cases, a function returns a value, which is the value of the last expression of the sequence of the function body.

Example:

```:NUM.require_from('kink/')

:fraction_part <- {(:Num)
NUM.is?(Num) || raise('Num must be a num, but was {}'.format(Num.repr))
Num % 1
}

stdout.print_line(fraction_part(3.1415).repr)  # => 0.1415
```

In the example above, `fraction_part` function returns the result value of `Num % 1` as its result.

### 5.2.3.2. Continuation¶

Sometimes a function call results in calling another function at the tail. Such a function called at the tail is called a continuation.

continuation

A function which is called at the tail of a function call. Don't confuse with delimited continuation.

continuation passing style

Composition of a function where the continuation is passed from the caller.

For example, `with_just_or(\$cont_just \$cont_empty)` method of a vector is written in continuation passing style. It calls `cont_just` at the tail when the size is 1, or calls `cont_empty` at the tail when the size is 0. Thus, `cont_just` or `cont_empty` is the continuation of `with_just_or`. Example:

```:display_opt <- {(:Opt_vec)
Opt_vec.with_just_or(
{(:Just) 'just {}'.format(Just.repr) }
{ 'empty' }
)
}

stdout.print_line(display_opt([]))  # => empty
stdout.print_line(display_opt([42]))  # => just 42
```

The main loop of an application is often times constructed on continuation passing style. Thus, it is essentially important to make the continuation called as a tail call, so that the main loop does not result in stack overflow.

### 5.2.3.3. Exception¶

A function call can terminate raising an exception, when there is no other way.

For example below, `fraction_part` requires a number as the argument. If that expectation is not met, `fraction_part` raises an exception because the precondition is broken.

```:NUM.require_from('kink/')

:fraction_part <- {(:Num)
NUM.is?(Num) || raise('Num must be a num, but was {}'.format(Num.repr))
Num % 1
}

fraction_part('str')
# Output:
#   -- main exception
#   [(root)]
#   {(call by host)}
#   {(call by host)}
#   {startup}
#   {builtin:kink-mods/kink/_startup/STARTUP.kn L238 C3 _startup_aux} -->_startup_aux(Args Dep)
#   {builtin:kink-mods/kink/_startup/STARTUP.kn L221 C11 try} CONTROL.-->try(
#   [builtin:kink-mods/kink/CONTROL.kn L93 C33 reset] :switch = KONT_TAG.escape_tag.-->reset{
#   {(call by host)}
#   [(kont tag)]
#   [builtin:kink-mods/kink/CONTROL.kn L94 C10 body] :R = -->body
#   {builtin:kink-mods/kink/_startup/STARTUP.kn L223 C7 _start} -->_start(Non_opts Dep)
#   {builtin:kink-mods/kink/_startup/STARTUP.kn L120 C3 if} -->if(Non_opts.empty?
#   {(call by host)}
#   {builtin:kink-mods/kink/_startup/STARTUP.kn L131 C20 call} { :Source_spec -->= Non_opts.front
#   {builtin:kink-mods/kink/_startup/STARTUP.kn L132 C20 call} :Script_args -->= Non_opts.drop_front(1)
#   {builtin:kink-mods/kink/_startup/STARTUP.kn L133 C7 branch} -->branch(
#   {(call by host)}
#   {builtin:kink-mods/kink/_startup/STARTUP.kn L158 C34 call} [:Source_desc :Script] -->= _scan_from(Source_spec Dep)
#   {builtin:kink-mods/kink/_startup/STARTUP.kn L160 C20 call} :Binding -->= BINDING.new
#   {builtin:kink-mods/kink/_startup/STARTUP.kn L162 C11 _run_script} -->_run_script(Binding \$script_fun Script_args)
#   [builtin:kink-mods/kink/_startup/STARTUP.kn L111 C3 script_fun] -->script_fun
#   {(stdin) L8 C1 fraction_part} -->fraction_part('str')  # => Num must be a num, but was "str"
#   [(stdin) L4 C16 op_logor] NUM.is?(Num) -->|| raise('Num must be a num, but was {}'.format(Num.repr))
#   {(call by host)}
#   {(stdin) L4 C19 raise} NUM.is?(Num) || -->raise('Num must be a num, but was {}'.format(Num.repr))
#   Num must be a num, but was "str"
```

See Error handling for details.

### 5.2.3.4. Side effects¶

Function might also cause side effects, such as changing the target value of a member variable, or I/O to the file system or the network.

In the next example, `fill_zero` sets 0 to all the elements of a vector. It is considered as a side effect of `fill_zero`.

```:fill_zero <- {(:Vec)
Vec.size.times.each{(:I)
Vec.set(I 0)
}
}

:Vec <- [1 2 3 4 5]
fill_zero(Vec)
stdout.print_line(Vec.repr) # => [0 0 0 0 0]
```

It is better to avoid side effects as much as possible, unless side effects themselves are the purpose of the function.

Here is a caveat. In mainstream languages, modification of a value not exposed from the function is not considered as a side effect. However, in Kink, that can sometimes be an observable side effect because of delimited continuation.

In the following example, you might think `Mapped` is not exposed from `map` function, so calling `push_back` method does not cause side effects.

```:map <- {(:Vec :transform)
:Mapped = []
:loop <- {(:I)
if(I < Vec.size){
Mapped.push_back(transform(Vec.get(I)))
loop(I + 1)
}
}
loop(0)
Mapped.dup
}

:Double <- map(
[0 1 2 3]
{(:I) I * 2 }
)
stdout.print_line(Double.repr) # => [0 2 4 6]
```

However, it is possible that a function call of `map` is resumed from the middle. The following example shows that modification of `Mapped` can actually be observed from outside.

```:KONT_TAG.require_from('kink/')

:double_caller <- {(:Vec)
:Tag = KONT_TAG.new
Tag.reset{
map(Vec){(:Num)
if(Num == 0
{ Tag.shift{(:resume)
}
0
}
{ Num * 2 }
)
}
}
}

:call_double <- double_caller([0 1 2 3])

:D1 <- call_double
stdout.print_line(D1.repr)  # => [0 2 4 6]

:D2 <- call_double
stdout.print_line(D2.repr)  # => [0 2 4 6 0 2 4 6]
```

To avoid this kind of side effect, you can define `map` like the following.

```:map <- {(:Vec :transform)
:loop <- {(:I :Mapped)
if(I < Vec.size
{ :New_mapped = Mapped + [transform(Vec.get(I))]
loop(I + 1 New_mapped)
}
{ Mapped }
)
}
loop(0 [])
}
```

Also note that implementation with side effects can sometimes be justified from the point of view of efficiency. Possibly it can be faster, or it can allocate less space. For example, the builtin implementation of `map` method a vector can cause side effects when it is resumed by delimited continuation in the middle.