Kotlin - Is it possible to check for operator precedence - kotlin

Let's say I have the following class:
data class Foo(var name: String) {
operator fun plus(foo: Foo): Foo {
name += foo.name
return this
}
}
Which is then used like this:
val foo1 = Foo("1")
val foo2 = Foo("2")
val foo3 = Foo("3")
foo1+foo2+foo3
println(foo1.name) // 123
Now, what if I wanted different behavior depending on whether the operations are chained like this:
foo1+foo2+foo3
Or like this:
(foo1+foo2)+foo3
In both cases foo1's name would be 123, but let's say that in the second case I would want foo1's name to be (12)3.
Is there a way to add a condition to the plus function, which checks whether the foo that it is called on originates from within parentheses/has a higher precedence or not.

No, that is not possible, because that makes no sense tbh. The compiler will just resolve the order of operations, brackets just indicate that 1+2 should resolve first and the result should be added to 3. There is no concept of brackets anymore in that result, you just have the outcome.
What is confusing you is that you are abusing the plus function to do something people wouldn't expect. You should not use the plus function to mutate the object it is called upon, this is not expected behaviour. Users will expect the plus function to return a new object not a mutation of the left or right operand.
In your case:
operator fun plus(foo: Foo): Foo {
return Foo(name += foo.name)
}
Don't do something different lest you want other people to be really confused. Fyi plusAssign is a mutating function, but still wouldn't allow you to do what you want. To achieve that you'd probably need to write your own parser and parse the operands and operators yourself.

Related

Why does `EffectScope.shift` need the type parameter `B`?

The move to the new continuations API in Arrow brought with it a handy new function: shift, in theory letting me get rid of ensure(false) { NewError() } or NewError().left().bind() constructs.
But I'm not sure how to properly use it. The documentation states that it is intended to short-circuit the continuation, and there are no conditionals, so it should always take the parameter, and (in either parlance) "make it a left value", and exit the scope.
So what is the type parameter B intended to be used for? It determines the return type of shift, but shift will not return. Given no more context, B can not be inferred, leading to this kind of code:
val res = either {
val intermediate = mayReturnNull()
if (intermediate == null) {
shift<Nothing>(IntermediateWasNull())
}
process(intermediate)
}
Note the <Nothing> (and ignore the contrived example, the main point is that shifts return type can not be inferred – the actual type parameter does not even matter).
I could wrap shift like this:
suspend fun <L> EffectScope<L>.fail(left: L): Nothing = shift(left)
But I feel like that is missing the point. Any explanations/hints would be greatly appreciated.
That is a great question!
This is more a matter of style, ideally we'd have both but they conflict so we cannot have both APIs available.
So shift always returns Nothing in its implementation, and so the B parameter is completely artificial.
This is something that is true for a lot of other things in Kotlin, such as object EmptyList : List<Nothing>. The Kotlin Std however exposes it as fun <A> emptyList(): List<A> = EmptyList.
For Arrow to stay consistent with APIs found in Kotlin Std, and to remain as Kotlin idiomatic as possible we also require a type argument just like emptyList. This has been up for discussion multiple times, and the Kotlin languages authors have stated that it was decided too explicitly require A for emptyList since that results in the best and most consistent ergonomics in Kotlin.
In the example you shared I would however recommend using ensureNotNull which will also smart-cast intermediate to non-null.
Arrow attempts to build the DSL so that you don't need to rely on shift in most cases, and you should prefer ensure and ensureNotNull when possible.
val res = either {
val intermediate = mayReturnNull()
ensureNotNull(intermediate) { IntermediateWasNull() }
process(intermediate) // <-- smart casted to non-null
}

Mockk match overloaded function with generics

So I have 2 overloaded score functions, one of which takes a performance param of type Performance, and the other which takes a performances param, which is a List<Performance>. The former returns a double, while the latter returns a double array. (Another team owns the Scorer class, so fixing it to not overload like this isn't really doable rn; breaking changes and all).
I want to test 2 branches, one with each implementation, how can I mock these using kotlin's mockk?
The former can be mockked using ofType(Performance::class),
scorer: Scorer = mockk()
every { scorer.score(????) } returns doubleArrayOf(0.9)
What goes there?
ofType(List<Performance>::class) doesn't work because apparently that can't be done with generics.
not(ofType(CandidateFeature::class)) results in a compile-time error Type mismatch: inferred type is DoubleArray but Double was expected
How do I explicitly choose which overriden signature I'm trying to call?
You can use withArg
every { scorer.score(withArg<Performance> {} ) returns mockData
every { scorer.score(withArg<List<Performance>> {} ) returns mockData

Kotlin expression fun vs normal fun - differences

Let's assume that I have two functions which do the same stuff.
First one:
fun doSomething() = someObject.getSomeData()
Second one:
fun doSomething(): SomeData {
return someObject.getSomeData()
}
Are there any technical differences between expression functions and standard function in Kotlin excluding the way how they look?
Is compiled output the same?
Are there any advantages using one instead another?
As #Sơn Phan says, they both compile to exactly the same bytecode.
So the differences are simply about conciseness.  The expression form omits the braces and return; it also lets you omit the return type (using type inference as needed).  As the question illustrates, the expression form can be shorter — and when all else is equal, shorter tends to be easier to read and understand.
So whether the expression form is appropriate is usually a matter of style rather than correctness.  For example, this function could be on one line:
fun String.toPositiveIntegers() = split(",").mapNotNull{ it.toIntOrNull() }.filter{ it >= 0 }
But it's a bit long, and probably better to split it.  You could keep the expression form:
fun String.toPositiveIntegers()
= split(",")
.mapNotNull{ it.toIntOrNull() }
.filter{ it >= 0 }
Or use a traditional function form:
fun String.toPositiveIntegers(): List<Int> {
return split(",")
.mapNotNull{ it.toIntOrNull() }
.filter{ it >= 0 }
}
(I tend to prefer the former, but there are arguments both ways.)
Similarly, I rather like using it when the body is a simple lambda, e.g.:
fun createMyObject() = MyObject.apply {
someConfig(someField)
someOtherConfig()
}
…but I expect some folk wouldn't.
One gotcha when using the expression form is the type inference.  Generally speaking, in Kotlin it's good to let the compiler figure out the type when it can; but for function return values, that's not always such a good idea.  For example:
fun myFun(): String = someProperty.someFunction()
will give a compilation error if the someFunction() is ever changed to return something other than a String — even a nullable String?.  However:
fun myFun() = someProperty.someFunction()
…would NOT give a compilation error; it would silently change the function's return type.  That can mask bugs, or make them harder to find.  (It's not a very common problem, but I've hit it myself.)  So you might consider specifying the return type, even though you don't need to, whenever there's a risk of it changing.
One particular case of this is when calling a Java function which doesn't have an annotation specifying its nullability.  Kotlin will treat the result as a ‘platform type’ (which means it can't tell whether it's nullable); returning such a platform type is rarely a good idea, and IntelliJ has a warning suggesting that you specify the return type explicitly.
1. Compiled output
Yes the compiled output will be completely the same
2. Advantage
You usually use expression function when the body of a function is only one line of expression to make it a oneliner function. Its advantage mainly about making the code more concise. Imagine instead of all the brackets and return, you only need a = to make things done.

Using Kotlin's scope functions in not exhaustive with / when

I'm pretty new with Kotlin and I'm trying to figure out Kotlin's scope functions.
My code looks like this:
with(something) {
when {
equals("test") -> var1 = "test123"
startsWith("test2") -> var2 = "test456"
contains("test3") -> myNullableVar?.let { it.var3 = "test789" }
}
}
So before I entered the third check with the .let function my with function does not need to be exhaustive (I'm not returning something, I'm only doing assignments). In my third check I'm using .let as a null-check ... but only for an assignment of it.var3 (if it is not null). I don't need to return anything while I know that Kotlin's .let function returns the result of the body by standard.
Nevertheless now my with/when needs to be exhaustive otherwise it won't compile anymore.
This got me thinking and trying out different things. I found these ways to solve this issue:
I can add an else to my with/when so it becomes exhaustive but actually I don't need an else and I don't want to use it in this case.
I can add another .let, so it looks like this: myNullableVar?.let { it.var3 = "test789" }.let{} .... but this looks kinda hacky to me. Is it supposed to work like this?
Use If(xy==null){...}else{...} stuff but I thought I can solve this with Kotlin differently
Because I'm new with Kotlin I'm not really sure how to handle this case properly. I would probably just go with my second idea because "it works". Or should I don't use .let for null-checks? Add another empty .let{}? Or did I not get the null-safety concept at all? I feel a little bit lost here. Thanks for any help.
This seems to be an unfortunate combination of features…
A when can be non-exhaustive only when it doesn't return a value.  The problem is that the with() function does return a value.  And since the when is at the bottom, its value is what gets returned, so in this case it must be exhaustive.
So why doesn't it insist on an else branch even if you omit the "test3" branch?  That's because assignments don't yield a value.  (They evaluate to Unit, which is Kotlin's special type for functions that don't return a useful value.)  If every branch gives Unit, then Kotlin seems* to be happy to infer a default branch also giving Unit.
But the "test3" branch returns something else — the type of myNullableVar.  So what type does the when infer?  The nearest common supertype of that type and Unit, which is the top type Any?.  And now it needs an explicit else branch!
So what to do?
You've found a few options, none of which is ideal.  So here are a few more, ditto!
You could return an explicit Unit from that branch:
contains("test3") -> { myNullableVar?.let { it.var3 = "test789" }; Unit }
You could return an explicit Unit from the with():
contains("test3") -> myNullableVar?.let { it.var3 = "test789" }
}
Unit
}
You could give an explicit type for the with(). (It has two type parameters, so you'd need to give both, starting with the type of its parameter):
with<String, Unit>("abc") {
I haven't found a single obvious best answer, I'm afraid…
And to answer your last question: yes, ?.let{ is perfectly idiomatic and common for null checks.  In this particular case, replacing it with an if happens to solve the type problem:
contains("test3") -> { if (myNullableVar != null) myNullableVar.var3 = "test789" }
But as well as being long-winded, if myNullableVar is a property and not a local variable, then it opens up a race condition (what if another thread sets it to null in between the test and the assignment?) so the compiler would complain — which is exactly why people use let instead!
(* I can't find a reference for this behaviour.  Is there an official word on it?)

How to deal with nullable variables that are not null?

Consider this piece of code:
var foo: Foo? = null
if (foo != null) {
foo!!.bar()
}
If I omit the two !! I get this error:
Smart cast to 'Foo' is impossible, because 'foo' is a mutable property that could have been changed by this time
This is about concurrency, right? Well, there is no concurrent code that might change the value of foo.
Of course, it works with the two !!. However, I was wondering if this is the most idiomatice way or if there is a better way, without the two !!.
I know I could just foo?.bar() in this particular case. But the question is about whether I can treat foo as Foo instead of Foo? somehow after I've checked that it's not null.
Well, this piece of code works if foo is a local variable. I guess, your code looks a little bit different and foo is a field of a class. The solution is simple: use let:
foo?.let {
it.bar()
}
let "captures" the values of a variable so that any modifications to the original one have no effect in the passed lambda. And safe call is used here to invoke let only for non-null values.