How to test Either from Arrow in functional style - junit

I would like to test the obtained result using Either. Let's assume I have a simple example without Either
#Test
fun `test arithmetic`() {
val simpleResult = 2 + 2
Assertions.assertEquals(4, simpleResult)
}
And now i have wrapped result:
#Test
fun `test arithmetic with either`() {
val result : Either<Nothing, Int> = (2 + 2).right()
Assertions.assertTrue(result.isRight())
result.map { Assertions.assertEquals(4, it) }
}
I suppose it looks a little bit ugly, because the last Assertions will not be executed if we got Either.Left instead of Either.Right
How can I test the result properly in functional style?

kotlintest provides a kotest-assertions-arrow module which can be used to test Arrow types.
It basically expose matchers for Either and other data type. Take a look at this.
#Test
fun `test arithmetic with either`() {
val result : Either<Nothing, Int> = (2 + 2).right()
result.shouldBeRight(4)
}

The implementations of Either are data classes on both sides so you can do something like:
check(result == 4.right())
Or can use something similar with any other assertion library that uses equals to assert equality.

You can create extension functions:
fun <L, R> Either<L, R>.assertIsLeft(): L {
return when (this) {
is Either.Left -> value
is Either.Right -> throw AssertionError("Expected Either.Left, but found Either.Right with value $value")
}
}
fun <L, R> Either<L, R>.assertIsRight(): R {
return when (this) {
is Either.Right -> value
is Either.Left -> throw AssertionError("Expected Either.Right, but found Either.Left with value $value")
}
}
fun <T: Any> T.assertEqualsTo(expected: T): Boolean {
return this == expected
}
With them you tests could look like these:
val resultRight : Either<Nothing, Int> = (2 + 2).right()
resultRight
.assertIsRight()
.assertEqualsTo(4)
val resultLeft: Either<RuntimeException, Nothing> = RuntimeException("Some exception cause").left()
resultLeft
.assertIsLeft()

Related

Kotlin send function arguments using a data class

Let's say I have class:
class Foo {
fun doSomething(param1: Int, param2: String, param3: String)
}
and a data class
data class Params(
val param1: Int,
val param2: String,
val param3: String)
Now I want to use the data class arguments to send them to the function, is there a way to do that? Lets say something similar to:
val myParams = Params(1, "2", "3")
val foo = Foo()
foo.doSomething(myparams)
Or by some sort of transformation or method naming. as:
execute(foo, foo::doSomething, myParams)
I doubt this is possible in Kotlin without some tricks. Possible solutions are reflection API and code generation.
Example using reflection:
fun main() {
val myParams = Params(1, "2", "3")
val foo = Foo()
invokeWithParams(foo::doSomething, myParams)
}
fun <T : Any, R> invokeWithParams(func: KFunction<R>, params: T): R {
val paramValues = func.parameters.map { kparam ->
(params::class as KClass<T>)
.memberProperties
.single { it.name == kparam.name }
.get(params)
}.toTypedArray()
return func.call(*paramValues)
}
It should work for static functions, member functions, and extension functions. It may fail with some rarer cases. You should probably add some error handling, e.g. checks if params match.
It won't work on anything else than JVM as reflection is still very limited on other targets.
Also, I'm not entirely sure about this unsafe cast. I think it can't fail, but I'm not 100% sure about it.
Update:
We can make it a little more funny by converting the function to extension operator invoke:
operator fun <T : Any, R> KFunction<R>.invoke(params: T): R
Then we can use it with any function like this:
(foo::doSomething)(myParams)
I'm not sure if this is a good idea though as it is more confusing than an explicit call to the utility function.

extension lambdas accept wrong parameters

I think an extension lambda requires that you pass in the correct argument, but i seems not to do so in the following example.
open class Base {
open fun f() = 1
}
class Derived : Base() {
override fun f() = 99
}
fun Base.g(): Int { return f()}
fun Base.h(xl: Base.() -> Int): Int { return xl()}
fun main() {
val b: Base = Derived() // Upcast
println(b.g())
println(b.h { f()}) // [1]
}
I understand that Base.h takes a function that takes a Base object as its parameter. But line [1] shows that it accepts f(), which is a function that takes no parameter. I was thinking hard about this and I prefixed it with this.f() and it still worked. Not convinced, I modified the code as follows:
open class Base {
open fun f() = 1
}
class Derived : Base() {
override fun f() = 99
}
fun Base.g(): Int { return f()}
fun Base.h(xl: (Base) -> Int): Int { return xl(Base())}
fun test(i:Int) = 1
fun main() {
val b: Base = Derived() // Upcast
println(b.g())
println(b.h { test(1) })
}
This code works. I've run it to verify. And as you can see, b.h() accepts test(), which takes an Int. And this is contrary to the fact that Base.h() takes a Base.
Could you explain this? Thank you for reading.
Note the curly brackets around the functions that are passed in! They change everything.
In the second code, b.h { test(1) } is not passing the function test to b.h. The syntax to pass test to b.h would be b.h(::test), and that does produce an error as you would expect.
b.h { test(1) } passes a function (a lambda expression) that takes a Base as parameter, ignores that parameter, calls test(1) and returns the result. You are basically passing a function that looks like this to b.h:
fun foo(p: Base) = test(1)
You might be wondering how Kotlin knows about Base when you did not write the word Base in the call at all. Well, it can just look at the declaration of b.h, and see that { test(1) } must take a parameter of Base.
The first code snippet is a bit different, because b.h accepts a Base.() -> Int in that case. Base.() -> Int represents a function whose receiver type is Base, that is, a function func that can be called like someBaseObject.func(). Compare this to a function func that takes a Base object as parameter, which can be called like func(someBaseObject).
Again, { f() } is not passing the function f. It is a lambda expression that does nothing but calls f. In this case though, f itself can be passed to b.h (b.h(Base::f)), because it is a function with a receiver type of Base! You can do someBaseObject.f(), can't you? Passing the lambda is similar to passing an extension function that is declared like this (you're just "wrapping" f in another function):
fun Base.foo() = f()
And since the receiver of the function is Base, you are able to access other functions that has Base as the receiver (such as f) in the lambda. You can also specify the receiver (which is this) explicitly.

How to create this advanced Kotlin function?

I am looking to create a custom function like this:
customFunction(arg1, arg2, arg3, etc.){
doSomethingIfConditionIsAccomplished()
}
, where the function accepts vararg as a parameter so you can add as many arguments as you like and the function doSomethingIfConditionIsAccomplished() thats's inside brackets is run only if a certain condition in the function is verified, like:
If (arg1 > arg2 > arg3) -> allow doSomethingIfConditionIsAccomplished() function to run otherwise nothing happens.
The function should look something like:
private fun <T: Any> customFunction(vararg input: T?){
-condition-
}
Since vararg is just an array inside the function, you can do something like this:
private fun <T: Comparable<T>> customFunction(vararg input: T){
val condition = (1 until input.size).none { input[it] < input[it-1] }
if(condition) {
println("calling doSomethingIfConditionIsAccomplished()")
} else {
println("not calling doSomethingIfConditionIsAccomplished()")
}
}
fun main() {
customFunction(1,2,3) // -> calling doSomethingIfConditionIsAccomplished()
customFunction(2,1,3) // -> not calling doSomethingIfConditionIsAccomplished()
}
But this way the condition is hard-coded, and the T must be Comparable<T>. There's no point in writing methods like this, except you want to implement Strategy pattern but that's slightly different.

How to convert function output to Unit with Kotlin

I have troubles with a function in Kotlin that should return Unit, but due to a usage of another function returning a Boolean, there is a type mismatch.
Here is a contrived example:
fun printAndReturnTrue(bar: Int): Boolean {
println(bar)
return true
}
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> printAndReturnTrue(bar)
}
Here, I actually do not care about the fact that printAndReturnTrue returns a boolean. I just want foo to perform side-effect operations. But the compiler warns about a type mismatch: my else should return a Unit value.
Is there a nice way to convert a value to Unit?
The simplest solutions I see are:
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> {
printAndReturnTrue(bar)
Unit
}
}
or:
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> eraseReturnValue(printAndReturnTrue(bar))
}
fun eraseReturnValue(value: Any) = Unit
Or I use the full function form:
fun foo(bar: Int): Unit {
when(bar) {
0 -> println("0")
else -> printAndReturnTrue(bar)
}
}
I am sure there are some idiomatic ways to do that (or is is the last example?), but for now I did not find them.
Unfortunaly, there's no idiomatic way to do this. A similiar problem, passing a lambda of type (T) -> Boolean to a function accepting (T) -> Unit lambdas has come up before, and the auto conversion required there is supposed to come to the language at some future point.
For now, you could use an extension function at the end of the when expression to coerce it back into a Unit value:
fun Any?.toUnit() = Unit
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> printAndReturnTrue(bar)
}.toUnit()
Alternatively, an extension property, if you happen to like that better:
val Any?.unit get() = Unit
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> printAndReturnTrue(bar)
}.unit
Of course you can omit the explicit Unit return type of the function if you use either of these.
I think the last is most idiomatic. Though you don't need explicit : Unit, it's the default for block form if no return type is specified and if you try to return something else you'll get an error.
But note a subtle detail: when when is used as an expression, else is required unless the compiler can prove all cases are handled; in the block form it's "used as a statement" and unhandled cases are ignored.
As another alternative, you could make a higher order function that swallows the output of the function returning a value:
fun consume (fn: () -> Any): Unit {
fn()
}
Giving:
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> consume { printAndReturnTrue(bar) }
}
I just use a semicolon if I write in a line.
someExpression; Unit
I think you should change return type of function to optional, it's more clear, like below:
fun printAndReturnTrue(bar: Int): Boolean {
println(bar)
return true
}
fun foo(bar: Int): Unit? = when(bar) {
0 -> println("0")
else -> printAndReturnTrue(bar) as? Unit
}
You could also do something like
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> printAndReturnTrue(bar).let{ Unit }
}
You can just call .let {} on a non-unit value to discard it (while keeping the side-effect):
// ...
else -> printAndReturnTrue(bar).let {}
// ...
{} is a Unit-returning function that ignores its arguments. let is an extension function that passes its receiver to the given lambda -- in this case, the lambda ignores it, and produces Unit, as needed.

`return` in a scala function literal

I'm trying to do something like this:
var fun : (Int,Int) => Double = (a,b) =>
{
// do something
return 1.0
}
However, my IDE complaints with Return statement outside method definition. So how do I explicitly give a return statement in a function literal in scala?
In Scala a return statement returns from the enclosing method body. If return appears inside of a function literal, it is implemented with exception throwing. return will throw an exception inside of the function which will then be caught be the enclosing method. Scala works this way in order to make the use of custom control constructs that take functions invisible, for example:
def geometricAverage(l: List[Double]): Double = {
val product = l.foldLeft(1.0) { (z, x) =>
if (x == 0) return 0 else z * x
}
Math.pow(product, 1.0 / l.length)
}
The return in this example returns from the geometricAverage method, allowing it to complete instantly if a 0 is found. You don't need to know that foldLeft is a method that takes a function rather than a built-in construct to realize this.
The preference in Scala is to write functions in functional style, taking advantage of Scala's expression-oriented nature to make return unnecessary. For example:
val fun: (Int,Int) => Double = (a,b) => {
if (a == b) {
// side effect here, if desired
0.0
} else {
// side effect here, if desired
1.0
}
}
If you really want to use return in the definition of the function, you can implement the appropriate function interface manually instead of using a function literal:
val fun = new Function2[Int, Int, Double] {
def apply(x: Int, y: Int): Double = {
if (x == y)
return 0.0
1.0
}
}
But this is not idiomatic and strongly discouraged.
Don't use return, it makes Scala cry.
scala> var fun: (Int, Int) => Double = (a, b) => {
| // do something
| 1.0
| }
fun: (Int, Int) => Double = <function2>
scala> fun(1, 2)
res4: Double = 1.0
Or better yet:
scala> def fun: (Int, Int) => Double = (a, b) => {
| // do something
| 1.0
| }
fun: (Int, Int) => Double
scala> fun(1, 2)
res4: Double = 1.0
how do I explicitly give a return statement in a function literal in scala?
You can't. This is answered by the language specification section 6.20, Return Expressions:
A return expression return e must occur inside the body of some enclosing named
method or function.
An apply method which is generated by the compiler as an expansion of an anonymous function does not count as a named function in the source program, and
therefore is never the target of a return expression.
There is no return statement in Scala. In any function the last statement executed is the value returned. If this last statement doesn't comply with expected return type of the function, compiler will raise error.