Since 1.1, Kotlin has had bound callable references. As I am on 1.1.3, I think I should be able to use the following to access the add method :
val elements = mutableListOf<Int>()
Flux.just(1, 2, 3, 4)
.log()
.subscribe(elements::add)
However, this throws an error:
I'm not sure what that error means in this specific instance. I can use .subscribe({ elements.add(it) }) with no issue, but shouldn't I be able to use the elements::add version?
Kotlin Function Reference Expression is not like as java Method Reference Expression. the return type Any is not compatible with the return type Unit.
the error comes from the return type (Boolean) of the MutableList#add(Int) method is not compatible with the parameter parameter type (Int)->Unit of the subscribe method.
so you can only using lambda expression this way.
you can using list::add in somewhere when both the parameter types and return type are compatible with the function. for example:
val add1:(Int) -> Boolean = list::add; // MutableList.add(Int);
val add2:(Int,Int) -> Unit = list::add; // MutableList.add(Int,Int);
To rephrase and elaborate on the other answer: the problem is that a Consumer is expected, which takes an element and returns nothing in its single method. The corresponding function type for this in Kotlin would be (T) -> Unit.
The add method described in the MutableList interface however has the type (T) -> Boolean: it returns true if the element was successfully added (this is to support implementations of the interface that can't contain duplicates).
A possible solution to this is to add an extension method that adds an element to a MutableList without returning anything:
fun <T> MutableList<T>.addItem(element: T): Unit {
this.add(element)
}
You can then use a bound callable reference to this extension, just like other MutableList methods:
Flux.just(1, 2, 3, 4)
.log()
.subscribe(elements::addItem)
Related
I am still learning kotlin, and I am curious how is it possible that mockk is able to return some object T wrapped in Result<T>. For better understanding let analyse below example:
We have such method definition
fun save(toSave : Entity): Result<Entity>
when we mock such method using returnArguments like it is done below:
every { mocked.save(any()) } returnsArgument 0
Then method returns Result<Entity>, but logic says that Entity should be returned.
Looking into declaration of returnsArgument there is casting to generic type which in our case is Result<Entity>, but when I tried to do it in plain I had casting exception.
I assume some magic happens inside, but what magic is responsible for such thing?
Would it be done with any wrapping object or it is specific only to Result?
Result<T> is a value class and mockk has a value class support.
After many internal steps returnsArgument will wrap the argument n with the specified value class and will return it.
Would it be done with any wrapping object or it is specific only to Result?
All value classes are supported, not just Result<T>.
// supported
#JvmInline
value class ValueWrapper<out T> (val something: Any?)
// not supported
class SomeWrapper<out T> (val something: Any?)
Hope it helps.
I have the following function:
inline fun <reified T> create(preference: Preference<T>, title: String = ""): DebugOption{
val type = when (preference) {
is Preference<String> -> Type.STRING
is Preference<Boolean> -> Type.BOOLEAN
else -> Type.STRING
}
return DebugOption(type, preference, displayTitle = StringModel(title))
}
I was expecting to be able to easily perform this 'is' check, since the generic type is reified, but I am still getting a compiler error:
Cannot check for instance of erased type: Preference<String>
Cannot check for instance of erased type: Preference<Boolean>
So I am confused how am I misusing 'reified' / what am I missing here.
Is there a problem with using reified generic types as the type parameter of another class?
The problem is that is checks the runtime type of preference, and the runtime type of preference isn't available until all the generic type information has been erased. Reified types are not magic, after all.
What you can do instead, is check T instead, since as you said, T is indeed reified.
val type = when (T::class) {
String::class -> Type.STRING
Boolean::class -> Type.BOOLEAN
else -> Type.STRING
}
But note that if Preference is covariant (like List) or contravariant, this might not work as you expect in some cases. For example:
// suppose Preference is covariant
// (i.e. the type parameter is declared <out T>)
val pref: Preference<Any> = Preference<Boolean>()
create(pref, "foo")
In this case, T is inferred to be Any, so type will be assigned Type.STRING. If that is unexpected to you, and you want Type.BOOLEAN instead, you might want to use another way to check a preference's type, rather than reified types, as this cannot be determined at compile time.
I'm exploring the Substitution principal and from what I've understood about the principal is that a sub type of any super type should be passable into a function/class. Using this idea in a new section of code that I'm writing, I wanted to implement a abstract interface for a Filter like so
interface Filter {
fun filter(): Boolean
}
I would then imagine that this creates the contract for all classes that inherit this interface that they must implement the function filter and return a boolean output. Now my interpretation of this is that the input doesn't need to be specified. I would like it that way as I want a filter interface that guarantee the implementation of a filter method with a guarantee of a return type boolean. Does this concept even exists in Kotlin? I would then expect to implement this interface like so
class LocationFilter {
companion object : Filter {
override fun filter(coord1: Coordinate, coord2: Coordinate): Boolean {
TODO("Some business logic here")
}
}
}
But in reality this doesn't work. I could remove remove the filter method from the interface but that just defeats the point of the whole exercise. I have tried using varargs but again that's not resolving the issue as each override must implement varargs which is just not helpful. I know this may seem redundant, but is there a possibility to have the type of abstraction that I'm asking for? Or am I missing a point of an Interface?
Let's think about it a little. The main point of abstraction is that we can use Filter no matter what is the implementation. We don't need to know implementations, we only need to know interfaces. But how could we use Filter if we don't know what data has to be provided to filter? We would need to use LocationFilter directly which also defeats the point of creating an interface.
Your problem isn't really related to Kotlin, but to OOP in general. In most languages it is solved by generics/templates/parameterized types. It means that an interface/class is parameterized by another type. You use it in Kotlin like this:
interface Filter<in T> {
fun filter(value: T): Boolean
}
object LocationFilter : Filter<Coordinate> {
override fun filter(value: Coordinate): Boolean {
TODO()
}
}
fun acquireCoordinateFilter(): Filter<Coordinate> = LocationFilter
fun main() {
val coord: Coordinate = TODO()
val filter: Filter<Coordinate> = acquireCoordinateFilter()
val result = filter.filter(coord)
}
Filter is parameterized, meaning that we can have a filter for filtering strings (type is: Filter<String>), for filtering integers (Filter<Int>) or for filtering coordinates (Filter<Coordinate>). Then we can't use e.g. Filter<String> to filter integers.
Note that the code in main() does not use LocationFilter directly, it only knows how to acquire Filter<Coordinate>, but the specific implementation is abstracted from it.
Also note there is already a very similar interface in Java stdlib. It is called Predicate.
my interpretation of this is that the input doesn't need to be specified.
Where did you get that interpretation from?
You can see that it can't be correct, by looking at how the method would be called. You should be able to write code that works for any instance of Filter — and that can only happen if the number and type of argument(s) is specified in the interface. To use your example:
val f: Filter = someMethodReturningAFilterInstance()
val result = f.filter(coord1, coord2)
could only work if all implementations used two Coordinate parameters. If some used one String param, and others used nothing at all, then how would you call it safely?
There are a few workarounds you could use.
If every implementation takes the same number of parameters, then you could make the interface generic, with type parameter(s), e.g.:
interface Filter<T1, T2> {
fun filter(t1: T1, t2: T2): Boolean
}
Then it's up to the implementation to specify which types are needed. However, the calling code either needs to know the types of the particular implementation, or needs to be generic itself, or the interface needs to provide type bounds with in variance.
Or if you need a variable number of parameters, you could bundle them up into a single object and pass that. However, you'd probably need an interface for that type, in order to handle the different numbers and types of parameters, and/or make that type a type parameter on Filter — all of which smells pretty bad.
Ultimately, I suspect you need to think about how your interface is going to be used, and in particular how its method is going to be called. If you're only ever going to call it when the caller knows the implementation type, then there's probably no point trying to specify that method in the interface (and maybe no point having the interface at all). Or if you'll want to handle Filter instances without knowing their concrete type, then look at how you'll want to make those calls.
The whole this is wrong!
First, OOP is a declarative concept, but in your example the type Filter is just a procedure wrapped in an object. And this is completely wrong.
Why do you need this type Filter? I assume you need to get a collection filtered, so why not create a new object that accepts an existing collection and represents it filtered.
class Filtered<T>(private val origin: Iterable<T>) : Iterable<T> {
override fun iterator(): Iterator<T> {
TODO("Filter the original iterable and return it")
}
}
Then in your code, anywhere you can pass an Iterable and you want it to be filtered, you simply wrap this original iterable (any List, Array or Collection) with the class Filtered like so
acceptCollection(Filtered(listOf(1, 2, 3, 4)))
You can also pass a second argument into the Filtered and call it, for example, predicate, which is a lambda that accepts an element of the iterable and returns Boolean.
class Filtered<T>(private val origin: Iterable<T>, private val predicate: (T) -> Boolean) : Iterable<T> {
override fun iterator(): Iterator<T> {
TODO("Filter the original iterable and return it")
}
}
Then use it like:
val oddOnly = Filtered(
listOf(1, 2, 3, 4),
{ it % 2 == 1 }
)
Look at the following code running in Kotlin REPL:
>>> null.takeIf({1==2})
res4: kotlin.Nothing? = null
Why this don't cause NullPointerException?
You code doesn't cause NullPointerException because takeIf is an extension function.
Extension functions are translated into method receiver, first argument being the object you invoked your function on.
So instead of null.takeIf { false } (simplifying your example), you could wonder why the following function doesn't throw a NullPointerException:
fun <T> takeIf(me: T, predicate: (T) -> Boolean): T? {
...
}
Well, for that we need to look into takeIf() implementation (removing annotations and contract):
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
return if (predicate(this)) this else null
}
So, in case your predicate is false (as in your example, 1==2), it just short-circuits and returns null.
What if it's true, then? Will we finally get a NullPointer?
Nope:
val nothing: Nothing? = null.takeIf {
true
}
Kotlin design approach for types aims to eliminate NPEs on purpose. Conditions that might trigger one are limited to, as seen on the docs:
An explicit call to throw NullPointerException();
Usage of the !! operator that is described below;
Some data inconsistency with regard to initialization, such as when:
An uninitialized this available in a constructor is passed and used somewhere ("leaking this");
A superclass constructor calls an open member whose implementation in the derived class uses uninitialized state;
Java interoperation:
Attempts to access a member on a null reference of a platform type;
Generic types used for Java interoperation with incorrect nullability, e.g. a piece of Java code might add null into a Kotlin MutableList, meaning that MutableList should be used for working with it;
Other issues caused by external Java code.
The third option is for NPE-lovers: the not-null assertion operator
(!!) converts any value to a non-null type and throws an exception if
the value is null. We can write b!!, and this will return a non-null
value of b (e.g., a String in our example) or throw an NPE if b is
null:
val l = b!!.length
Thus, if you want an NPE, you can have it, but you
have to ask for it explicitly, and it does not appear out of the blue.
So your code is behaving as expected. See the link for more info
https://kotlinlang.org/docs/reference/null-safety.html
I have a class for binding a viewholder
class ViewHolderBinder(val onBind: (ViewHolder) -> Unit, val onClick: () -> Unit)
There is a list of these items in presenter
val items: MutableList<ViewHolderBinder> = mutableListOf()
ViewHolderBinder contains 2 non-null functions, but this call causes compile-time error
items.getOrNull(position)?.onClick()
However this call compiles as expected
items.getOrNull(position)?.let { it.onClick() }
Maybe i have missed something, but 2 these constructions are fully equivalent and i prefer to use first one, but it is not compiling.
I am using kotlin 1.3.10
Here's the actual error message you're getting:
Reference has a nullable type '(() -> Unit)?', use explicit '?.invoke()' to make a function-like call instead
Suppose you had this code:
val binder: ViewHolderBinder? = getBinder()
binder?.onClick()
onClick() is not a function you can invoke on the ViewHolderBinder instance. It's a property that holds a callback object. The full syntax to invoke that callback's function is
binder?.onClick?.invoke()
Kotlin also offers a special shorthand syntax that would work on a non-nullable binder:
binder.onClick()
If you apply it to a nullable binder,
binder?.onClick()
it expands to
binder?.onClick.invoke()
The type of the expression binder?.onClick is (() -> Unit)?, just like the error says. You aren't allowed to apply the . operator to a nullable type.