Kotlin’s return

Recently I tried out Kotlin and was a bit surprised about its return expression. If you have a Java background like me this might hit you, too.

Look at the following function which does not work as intended:

fun sum(numbers: List<BigDecimal>): BigDecimal {
    return numbers.fold(BigDecimal.ZERO, { acc, value ->
        return acc + value
    })
}

The fold function accepts an initial start value and feeds this and an element of the list into the lambda. The result of the lambda is the new initial value and fold iterates through the whole list until no more elements are left. This example function clearly wants to sum all elements of the list and return the result.

Now, let’s testdrive it with a couple of calls.

println(sum(listOf()))
println(sum(listOf(BigDecimal(3))))
println(sum(listOf(BigDecimal(3), BigDecimal(7))))
println(sum(listOf(BigDecimal(9), BigDecimal(7))))

The output is:

0
3
3
9

It seems ok at first but the last two calls got wrong results. The outcome hints that the function did not iterate through the whole list. Instead it stopped after the first element.
Have another look at the function and you see there are two different return expressions. The most inner return is inside a lambda and on first call the return ends the enclosing function not just the lambda. From the Kotlin documentation:

– return. By default returns from the nearest enclosing function or anonymous function.

So, the intention of returning the result lead us to use return but this ended the whole function prematurely.
How to repair this? Just remove the inner return as lambdas return the last expression anyway:

fun sum(numbers: List<BigDecimal>): BigDecimal {
    return numbers.fold(BigDecimal.ZERO, { acc, value ->
        acc + value
    })
}

Now it works as intended. There is more than one way to patch it up. Sometimes you really want to jump out on the spot and you can.
Kotlin allows a qualified return. Put a label at the lambda and tell the return about it:

fun sum(numbers: List<BigDecimal>): BigDecimal {
    return numbers.fold(BigDecimal.ZERO , accumulator@ { acc, value ->
        return@accumulator acc + value
    })
}

Most often you even do not need to label it yourself but can use an implicit label:

fun sum(numbers: List<BigDecimal>): BigDecimal {
    return numbers.fold(BigDecimal.ZERO , { acc, value ->
        return@fold acc + value
    })
}

Log4j 2 filtering with multiple filters

Filtering in Log4j 2 is an extra way to control which messages make it to the appender. The documentation states that:

Filters may be configured in one of four locations

Filters at these locations do not behave the same but this is explained right afterwards.

This post is about the fact that the configuration does not really work the same in each of these locations. Most often I started out with a filter in the appender section because this is what the examples show you. Take the MarkerFilter example:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
    <Appenders>
        <RollingFile name="RollingFile" fileName="logs/app.log"
                     filePattern="logs/app-%d{MM-dd-yyyy}.log.gz">
            <MarkerFilter marker="FLOW" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout>
                <pattern>%d %p %c{1.} [%t] %m%n</pattern>
            </PatternLayout>
            <TimeBasedTriggeringPolicy/>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="error">
            <AppenderRef ref="RollingFile"/>
        </Root>
    </Loggers>
</Configuration>

Adding a second MarkerFilter seems a no-brainer. Just duplicate the line and change some attributes:

<RollingFile name="RollingFile" fileName="logs/app.log"
             filePattern="logs/app-%d{MM-dd-yyyy}.log.gz">
    <MarkerFilter marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
    <MarkerFilter marker="FLOW2" onMatch="ACCEPT" onMismatch="DENY"/>
    <PatternLayout>
        <pattern>%d %p %c{1.} [%t] %m%n</pattern>
    </PatternLayout>
    <TimeBasedTriggeringPolicy/>
</RollingFile>

Oddly enough, this corrupts the whole configuration. You get:

ERROR appender RollingFile has no parameter that matches element MarkerFilter

This log message is easily missed as it happened to me. How to fix this? Use a CompositeFilter which is a surrounding element named Filters.

<RollingFile name="RollingFile" fileName="logs/app.log"
             filePattern="logs/app-%d{MM-dd-yyyy}.log.gz">
    <Filters>
        <MarkerFilter marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
        <MarkerFilter marker="FLOW2" onMatch="ACCEPT" onMismatch="DENY"/>
    </Filters>
    <PatternLayout>
        <pattern>%d %p %c{1.} [%t] %m%n</pattern>
    </PatternLayout>
    <TimeBasedTriggeringPolicy/>
</RollingFile>

The logic here is quite simple. Only one filter is allowed. If you want more you have to wrap them in a CompositeFilter. Now, at the beginning I told you that there are four locations where filters are permitted. Another location is context-wide. These are filters which are direct sub-elements of the Configuration element. And there it is totally fine to add more than one filter. You get no error by log4j and it works as expected:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
    <MarkerFilter marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
    <MarkerFilter marker="FLOW2" onMatch="ACCEPT" onMismatch="DENY"/>
    ...
</Configuration>

It is also ok to wrap them in a CompositeFilter:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
    <Filters>
        <MarkerFilter marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
        <MarkerFilter marker="FLOW2" onMatch="ACCEPT" onMismatch="DENY"/>
    </Filters>
    ...
</Configuration>

Best practice I derive from this weird behavior is to always wrap them. Then I can copy and paste between locations without thinking too much.