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.
Related
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.
In the example below the Default trait is used just for demonstration purposes.
My questions are:
What is the difference between the declarations of f() and g()?
Why g() doesn't compile since it's identical to f()?
How can I return a concrete type out of a impl trait generically typed declaration?
struct Something {
}
impl Default for Something {
fn default() -> Self {
Something{}
}
}
// This compiles.
pub fn f() -> impl Default {
Something{}
}
// This doesn't.
pub fn g<T: Default>() -> T {
Something{}
}
What is the difference between the declarations of f() and g()?
f returns some type which implements Default. The caller of f has no say in what type it will return.
g returns some type which implements Default. The caller of g gets to pick the exact type that must be returned.
You can clearly see this difference in how f and g can be called. For example:
fn main() {
let t = f(); // this is the only way to call f()
let t = g::<i32>(); // I can call g() like this
let t = g::<String>(); // or like this
let t = g::<Vec<Box<u8>>(); // or like this... and so on!
// there's potentially infinitely many ways I can call g()
// and yet there is only 1 way I can call f()
}
Why g() doesn't compile since it's identical to f()?
They're not identical. The implementation for f compiles because it can only be called in 1 way and it will always return the exact same type. The implementation for g fails to compile because it can get called infinitely many ways for all different types but it will always return Something which is broken.
How can I return a concrete type out of a impl trait generically typed declaration?
If I'm understanding your question correctly, you can't. When you use generics you let the caller decide the types your function must use, so your function's implementation itself must be generic. If you want to construct and return a generic type within a generic function the usual way to go about that is to put a Default trait bound on the generic type and use that within your implementation:
// now works!
fn g<T: Default>() -> T {
T::default()
}
If you need to conditionally select the concrete type within the function then the only other solution is to return a trait object:
struct Something;
struct SomethingElse;
trait Trait {}
impl Trait for Something {}
impl Trait for SomethingElse {}
fn g(some_condition: bool) -> Box<dyn Trait> {
if some_condition {
Box::new(Something)
} else {
Box::new(SomethingElse)
}
}
how can I return a concrete type out of a "impl trait" generically typed declaration?
By "impl trait" generically typed declaration I presume you mean "impl trait" rewritten to use named generics. However, that's a false premise - impl Trait in return position was introduced precisely because you can't express it using named generics. To see this, consider first impl Trait in argument position, such as this function:
fn foo(iter: impl Iterator<Item = u32>) -> usize {
iter.count()
}
You can rewrite that function to use named generics as follows:
fn foo<I: Iterator<Item = u32>>(iter: I) -> usize {
iter.count()
}
Barring minor technical differences, the two are equivalent. However, if impl Trait is in return position, such as here:
fn foo() -> impl Iterator<Item = u32> {
vec![1, 2, 3].into_iter()
}
...you cannot rewrite it to use generics without losing generality. For example, this won't compile:
fn foo<T: Iterator<Item = u32>>() -> T {
vec![1, 2, 3].into_iter()
}
...because, as explained by pretzelhammer, the signature promises the caller the ability to choose which type to return (out of those that implement Iterator<Item = u32>), but the implementation only ever returns a concrete type, <Vec<u32> as IntoIterator>::IntoIter.
On the other hand, this does compile:
fn foo() -> <Vec<u32> as IntoIterator>::IntoIter {
vec![1, 2, 3].into_iter()
}
...but now the generality is lost because foo() must be implemented as a combination of Vec and into_iter() - even adding a map() in between the two would break it.
This also compiles:
fn foo() -> Box<dyn Iterator<Item = u32>> {
Box::new(vec![1, 2, 3].into_iter())
}
...but at the cost of allocating the iterator on the heap and disabling some optimizations.
The entry point of the c-like languages is almost identical, so Kotlin's fun main() {}
This is quite understandable for me, however; when using this routine as a single-expression function and (assign?) it any output method it will be compiled and print the parameter's value of the print method not its return type (which is Unit). I guess this snippet will make it clear..
fun main() = print("Do I return something?")
This will be compiled as a basic hello world program!
Why is this acceptably compiled? does the main method returns something else than the 0?
Is the equal operator acts as assignment operator? and if so; what does the print() method returns? is it something other than Unit?
If so, why it returns Unit when assign it to a variable?
fun main() {
val x= println()
print(x)
}
Then also, why it doesn't return Unit in this case:
fun main() = foo()
fun foo(): Unit {}
I'm not understanding everything you ask. = here is not an assignment operator. It's just a shorter way of writing the method:
fun main() = print("Do I return something?")
is equivalent to
fun main(): Unit {
return print("Do I return something?")
}
And since print()'s return type is Unit, it's equivalent to
fun main() {
print("Do I return something?")
}
See the documentation for details.
In the following snippet, however, = is the assignment operator:
fun main() {
val x = println()
print(x)
}
So this code calls println(), and assigns what it returns (Unit) to the variable x. Printing x thus produces the output kotlin.Unit.
I hope that helps:
The entry point to a Kotlin program is fun main(): Unit or fun main(args: Array<String>): Unit, which are functions that return Unit
Unit is something that is returned by default from Kotlin functions when there is nothing interesting to return
println() returns Unit
A Unit return type is often omitted in the code, but it is implied
fun foo(): T = boo() is a short syntax for fun foo(): T { return boo() }
Since fun main(): Unit and fun println(...): Unit have the same return type Unit, it is valid to write fun main() = println()
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()
I am at the early stages of learning Scala and I've noticed different ways to declare methods.
I've established that not using an equals sign makes the method a void method (returning a Unit instead of a value), and using an equals sign returns the actual value so
def product(x: Int, y: Int) {
x*y
}
will return () (Unit), but
def product(x: Int, y: Int) = {
x*y
}
will return the product of the two arguments(x*y)
I've noticed a third way of declaring methods - with a colon. Here is an example
def isEqual(x: Any): Boolean
How does this differ from the = notation? And in what situations will it be best to use this way instead?
When you use colon (and use equal) you explicitly define return type of method.
// method return Boolean value
def m(a : Int) : Boolean = a > 0
When you don't use colon and use equal you allow scala compiler inferring return type itself.
// method has return type of last expression (Boolean)
def m(a : Int) = a > 0
When you use neither colon nor equal your method has return type of Unit class.
// method has Unit return type
def m(a : Int){
a > 0
}
Others have perfectly explained the differences between the different declarations:
def foo: Boolean = true // explicitly declare the return type
and
def foo = true // let the compiler to implicitly infer Boolean
That being said, I have to warn you against
def foo { }
This is called procedure-syntax, and you should never use it, as it's has been already deprecated (since Oct 29, 2013), although you'll get a deprecation warning only under the -Xfuture flag.
Whenever you have to declare a method returning Unit (which you should avoid as much as possible, since it means you're relying on side-effects), use the following syntax
def foo: Unit = { }
Also, as a personal advice, explicitly annotating return types makes your code often more readable and helps you in catching errors early. You know what the function should return, so explicitly annotating the type allows the compiler to check that the implementation returns an appropriate value, right at the declaration position (if you use the function you will catch an error eventually, but perhaps far from where the error really is).
Also, when declaring an abstract member, you'd better also annotate the types
trait {
def foo
}
is legal, but the type of foo is automatically inferred to be Unit, which almost never what you want.
Instead, do
trait {
def foo: Boolean
}
if you don't want the return type then you used
scala> def product(x: Int, y: Int) { //in lack of = it explicit uses Unit
| x*y
| }
product: (x: Int, y: Int)Unit
//equivalent to below
scala> def product(x: Int, y: Int):Unit={
| x*y
| }
product: (x: Int, y: Int)Unit
and when you write
scala> def product(x: Int, y: Int) = { //here it explicit detect return type
| x*y
| }
product: (x: Int, y: Int)Int
//equivalent to below
scala> def product(x: Int, y: Int):Int = {
| return x*y
| }
product: (x: Int, y: Int)Int
def foo(arg) { sideEffects() } is equivalent to def foo(arg) = { sideEffects(); Unit }. It is bad style because it hides your intention. (It's easy to overlook the missing =). I recommend you don't use it.
def foo(arg) = { expression } is a method that implicitly resolves to the type of the expression and is good style.
def foo(arg): Type is an abstract method definition with an explicit type. It is not equivalent to the other two examples, as no implementation is provided.
1) The procedure syntax is deprecated from scala-2.11, avoid it.
def product(x: Int, y: Int) {
x*y
}
// It always returns Unit.
// creates confusion for most beginners. deprecated for good.
2) The type inference syntax, mostly used with small/private methods.
def product(x: Int, y: Int) = {
x*y
}
It is a help from the compiler, but sometimes compiler's inference may be different from what you think.
3) The type annotation syntax.
def product(x: Int, y: Int): Int = {
x*y
}
For public APIs it is good practice to specify return type explicitly.
In some cases it is mandatory to specify return type.
For instance:
when defining recursive methods.
when compiler's inference is more specific but you need generic return type (Map in place of HashMap).
To override compiler's inference. def getId(): Long = 1
If return is used anywhere in the method body.
In Scala a function is defined as
def product(x: Int, y: Int): Int = {
x*y
}
but there there are few "shortcuts" that can be used
Since scala have good type Inference you can omit the type (unless the function is recursion one):
def product(x: Int, y: Int) = {
x*y
}
Everything is an expression. so function must return value. The last line of block of code is the return value. so if you use curved brackets {} the last line will be return. if the function has only one line there is no need for the curved brackets.
def product(x: Int, y: Int) = x*y
Since everything has to return a value "No value" is actually Unit. So if you dont want to return meaningful value (which mean you do some side effects) then use Unit as the return value:
def product(x: Int, y: Int): Unit = x*y
Using functions without the equal sign is just another way to return Unit (this also named "procedure syntax":
def product(x: Int, y: Int) { x*y }
Note that the procedure syntax is Deprecate and should be avoid!