I have an interface which contains a generic and have its extensions working properly, however I'm not able to receive a list of this subclasses as parameter.
The code below works perfectly:
interface Runnable
class FirstRunnable : Runnable
class SecondRunnable : Runnable
interface Runner<in T> where T : Runnable {
fun run(runnable: T)
}
class FirstRunner : Runner<FirstRunnable> {
override fun run(runnable: FirstRunnable) = println("first runner")
}
class SecondRunner : Runner<SecondRunnable> {
override fun run(runnable: SecondRunnable) = println("second runner")
}
The problem comes in the block below:
class ListRunner(private val runners: List<Runner<Runnable>>)
val runner = ListRunner(listOf(FirstRunner(), SecondRunner()))
ListRunner does not accept FirstRunner() and SecondRunner() as parameters and complains with:
Type mismatch.
Required:
List<Runner<Runnable>
Found:
List<Runner<{FirstRunnable & SecondRunnable}>>
I want to inject the list into the ListRunner to be able to run in the entire list at once, within the runner I have a rule to run only accepted Runnable
Solution
Both answers helped me to find out the solution,
As pointed by Nishant Jalan, I had first to add out variance to the ListRunner
class ListRunner(private val runners: List<Runner<out Runnable>>)
And as Sweeper says:
It is not safe to put anything there. The Kotlin type system is smart
enough that it tells you this by saying that run there takes the type
Nothing.
So the solution was adding #UnsafeVariance annotation to the Runner interface:
interface Runner<in T> where T : Runnable {
fun run(runnable: #UnsafeVariance T)
}
Still it is unsafe and the annotation only prevents the compiler to complain about it, however I have a previous verification which guarantee the runnable is run in the correct runner.
You can use a star-projection to say you want a list of any kind of Runner:
class ListRunner(private val runners: List<Runner<*>>)
This will cause the following to compile:
val runner = ListRunner(listOf(FirstRunner(), SecondRunner()))
However, this will also prevent you from running any of the runners in ListRunner. For example, you cannot do this in ListRunner:
fun runAll() {
for (runner in runners) {
runner.run(...)
}
}
Because what actually is the ... part? It is not safe to put anything there. The Kotlin type system is smart enough that it tells you this by saying that run there takes the type Nothing.
You can't pass a FirstRunnable, because runner could be a SecondRunner, which takes a SecondRunnable. You can apply a similar reasoning for why you can't pass a SecondRunnable, or any other Runnable. ListRunner don't know what kind of Runners are in the list, so it can't run it, because different Runners needs different Runnables to run.
Of course, you can check the types of the runner first, then give them the correct kind of runnable:
for (runner in runners) {
when (runner) {
is FirstRunner -> runner.run(FirstRunnable())
is SecondRunner -> runner.run(SecondRunnable())
else -> println("I didn't expect this type of runner!")
}
}
Note that you need an else branch, in case someone passed in a Runner that isn't any of the types you are checking. Anyone can implement your interface, after all!
If you want to eliminate the else branch, you can make Runner sealed:
sealed interface Runner<in T> where T : Runnable {
There are a few things you can tweak in your code to perform the operation that you are looking for.
interface Runner<in T> where T : Runnable can simply be reduced to interface Runner<T : Runnable>. They both do the same thing.
While declaring the ListRunner class, you need to pass a List of Runner of a type that is a Runnable. Hence, you need to replace your type with List<Runner<out Runnable>>
The final code is written below.
interface Runnable
class FirstRunnable : Runnable
class SecondRunnable : Runnable
interface Runner<T : Runnable> {
fun run(runnable: T)
}
class FirstRunner : Runner<FirstRunnable> {
override fun run(runnable: FirstRunnable) = println("first runner")
}
class SecondRunner : Runner<SecondRunnable> {
override fun run(runnable: SecondRunnable) = println("second runner")
}
class ListRunner(private val runners: List<Runner<out Runnable>>)
Related
I started playing with the new context receivers feature. I intend to use that as a "localized dependency injection" to pass client context around. Currently, I have this (ClientProvider is a fun interface):
fun <T> withClient(client: Client, block: ClientProvider.() -> T) =
ClientProvider { client }.block()
This works pretty well in the production code, e.g. I can do
class MyService {
context(ClientProvider)
fun methodUsingClient() {}
}
However, an issue arises when I want to mockk this code in tests. Currently, I have
val myService: MyService = mockk { every { methodUsingClient() } just runs }
This obviously doesn't work because the ClientProvider context is missing. I would like to fix that by composing mockk and withClient. I imagine it could look like this
inline fun <reified T : Any> mockkWithClient(noinline block: context(T) ClientProvider.() -> Unit) =
mockk<T> { withClient(mockk(), block) }
This indeed works at the call site, i.e., the compiler seems to be happy with
val myService: MyService = mockkWithClient { every { methodUsingClient() } just runs }
but the function itself doesn't compile - the compiler complains about the block parameter:
Type mismatch.
Required:
ClientProvider.() → TypeVariable(T)
Found:
context(T) ClientProvider.() → Unit
Intuitively, I would expect that the extra T context wouldn't harm the block usage inside withClient but apparently, it does.
Is there any way how I can define mockkWithClient so it can be used as outlined above?
I got a useful answer to my other, more generally formulated question, and based on that I was able to solve this problem as well (the key point I was missing is that I have to manually pass the receivers to the block):
inline fun <reified T : Any> mockkWithClient(noinline block: context(ClientProvider) T.() -> Unit) =
withMockClient<T> { mockk { block(this#withMockClient, this#mockk) } }
fun <T> withMockClient(block: ClientProvider.() -> T) =
ClientProvider { mockk() }.block()
The intended usage is then as expected:
mockkWithClient { every { methodUsingClient() }
Note, however, the very specific type of block: it's context(ClientProvider) T.() -> Unit. If I read the documentation correctly I should be also able to write context(ClientProvider, T) () -> Unit but that doesn't compile with the message Subtyping relation between context receivers is prohibited. The root cause of this is still unknown to me but my original problem is solved, nevertheless.
Goal
I would like to globally disable inlining of #JvmInline value class classes via a compiler flag or something similar. I would want to do this when running unit tests but not in production.
Motivation
I would like to use mockk with value classes.
I want to write a unit test that looks like this:
#JvmInline
value class Example(private val inner: Int)
class ExampleProvider {
fun getExample(): Example = TODO()
}
#Test
fun testMethod() {
val mockExample = mockk<Example>()
val mockProvider = mockk<ExampleProvider> {
every { getExample() } returns mockExample
}
Assert.assertEquals(mockExample, mockProvider.getExample())
}
This code fails with the following exception:
no answer found for: Example(#4).unbox-impl()
I think that if I were able to disable class inlining that this would no longer be an issue.
I am relatively new Kotlin and Generics kind of give me a headache. I have the following architecture made out of:
A few data classes
A generic interface to process data
Implementations of that processing interface for each data type
A generic processing job class containing the data to be processed and it's appropriate processor
A global (singleton) processor which implements the processing interface, takes processing jobs and just delegates the processing to the job processor. It doesn't care about the data itself at all.
The simplified code looks like this
class DataOne
class DataTwo
interface DataProcessor<in T> {
fun process(o: T)
}
class DataOneProcessor: DataProcessor<DataOne> {
override fun process(o: DataOne) = println("Processing DataOne")
}
class DataTwoProcessor: DataProcessor<DataTwo> {
override fun process(o: DataTwo) = println("Processing DataTwo")
}
class ProcessingJob<T>(val data: T, val processor: DataProcessor<T>)
object GlobalProcessor: DataProcessor<ProcessingJob<Any>> {
override fun process(job: ProcessingJob<Any>) = job.processor.process(job.data)
}
fun main() {
GlobalProcessor.process(ProcessingJob(DataOne(), DataOneProcessor()))
}
In the main function I get a compiler error
Type mismatch.
Required: ProcessingJob<Any>
Found: ProcessingJob<DataOne>
I understand why this happens: A DataProcessor of DataOne, viewed as a DataProcessor of Any could be asked to process DataTwos and for type safety this is not allowed.
Can you give me any suggestions on how/what to change to make it compile and achieve the required result? Thanks for your time!
There are two problems here.
First, Any isn't actually the top-level type. Any implies not null, but T is unconstrained, which means it can be a nullable type. In this case you can use *, or you could also specify the type as Any?.
Change the signature of the GlobalProcessor to this:
object GlobalProcessor: DataProcessor<ProcessingJob<*>> {
override fun process(job: ProcessingJob<*>): ...
The second problem is that the implementation of process can't take advantage of the generic information from the job in order to know that the job.processor and the job.data are compatible. It just sees two objects of unknown type. To let it know they share a compatible type, you need to capture that type as a type variable. We can't add a generic type parameter to the existing method, because it has to match the signature of the interface method, but we can add a new private method that introduces the generic parameter.
Here's the GlobalProcessor with both the required changes.
object GlobalProcessor: DataProcessor<ProcessingJob<*>> {
override fun process(job: ProcessingJob<*>) = processGeneric(job)
private fun <T> processGeneric(job: ProcessingJob<T>) = job.processor.process(job.data)
}
In Kotlin, I want to add a "namespace" to a class that has a set of related functions. Clients of my class will use that namespace to help classify what type of operation they want to do. (I know you're thinking the functions should be in different classes, problem solved. But for other reasons, it's convenient to house all the functions in a single class).
So, I might have a class Uber that contains fooInsert fooOpen fooDispose along with barInsert barTerminate and barHop. As you can see there's no common interface. Just a bunch of functions that for some reason belong in the same class. Some have an affinity with others (i.e. the fooXXX functions "belong" together, as do the "barYYY" functions).
What I've come up with is:
class Uber {
inner class FooNamespace {
fun insert(): Unit {}
fun open(): Unit {}
fun dispose(): Unit {}
}
val foo = FooNamespace()
inner class BarNamespace {
fun insert(): Unit {}
fun terminate(): Unit {}
fun hop(): Unit {}
}
val bar = BarNamespace()
}
Users of the class can do something like this:
val uber = Uber()
uber.foo.insert()
uber.bar.hop()
What I'd like is something that combines the inner class ... and val xxx = XxxNamespace() into one expression. Something like:
// This doesn't actually compile
val foo = object: inner class {
fun insert(): Unit {}
fun open(): Unit {}
fun dispose(): Unit {}
}
The problem here is that you need a properly defined type if you to want to access these members publicly.
For private properties, the syntax val foo = object { ... } is sufficient, but for publicly exposed properties these are inferred as Any and it makes them unusable.
One option is obviously to define an interface for these types, but it's even more boilerplate than what you came up with already, so I am pretty sure this won't suit your needs:
interface FooNamespace {
fun insert()
fun open()
fun dispose()
}
class Uber {
val foo = object : FooNamespace {
override fun insert(): Unit {}
override fun open(): Unit {}
override fun dispose(): Unit {}
}
}
I know you're thinking the functions should be in different classes, problem solved. But for other reasons, it's convenient to house all of the functions in a single class
I'm indeed really thinking that, and would love to hear more about what makes it so convenient to put everything in the same class :) Since the classes are inner classes, I'm assuming this has to do with accessing private state from Uber, but that could also be done by wrapping this private state into another class that's passed to foo and bar.
I believe this is not possible, at least for now.
The main technical problem here is that uber.foo.insert() is really interpreted as chaining uber.foo and then .insert(). So for this to work, uber.foo needs to have an explicitly defined type. It can't be anonymous class/object, because then there is no way to describe what is the type of uber.foo.
That being said, I've always wondered why Kotlin does not support this syntax:
val foo = object Foo {}
This is consistent with the object declaration where the name of the singleton is at the same time the name of the class. And the compiler even understands this above syntax, because it throws the error: "An object expression cannot bind a name". So Kotlin authors seem to intentionally disallow such use.
I found an issue in the YouTrack, so we can at least upvote it: https://youtrack.jetbrains.com/issue/KT-21329
I'm trying to keep this minimal, but let me know if I'm being too minimal.
Suppose you have a class hierarchy like this, designed for generating HTML (inspired by the Kotlin tutorial; semi-pseudocode follows):
class Tag {
protected val children = arrayListOf<Tag>()
operator fun String.unaryPlus() = children.add(Text(this))
}
class TagWithChildren : Tag() {
fun head(init: Head.() -> Unit) = initializeTag(Head(), init)
fun script(init: Script.() -> Unit) = initializeTag(Script(), init)
fun <T : Tag> initializeTag(tag: T, init: T.() -> Unit): T {
tag.init()
children.add(tag)
return tag
}
}
class Head : TagWithChildren()
class Script : Tag()
class Text(val str: Text) : Tag()
Notice that Head has head and script methods while Script doesn't.
Now you can construct a template that looks like this:
head {
script {
+"alert('hi');"
}
}
Which works great! However, if the block passed to script tries to call methods that aren't available on Script, it can call the method on Head instead. For example,
head {
script {
script {
+"alert('hi');"
}
}
}
not only isn't a compile error, it's actually equivalent to
head {
script {
}
script {
+"alert('hi');"
}
}
which is super confusing, from a template author's perspective.
Is there any way to prevent method lookups from traveling up the scope like that? I only want it to look at the innermost scope.
UPDATE 11/24/2016:
Kotlin 1.1-M03 has introduced scope control, which I believe solves exactly this problem. https://blog.jetbrains.com/kotlin/2016/11/kotlin-1-1-m03-is-here/
The current behavior is intentional. Code in a lambda has access to receivers of all enclosing scopes. It is possible that a future version of Kotlin will add a modifier that will restrict a lambda with receiver to calling methods on that receiver only and not the enclosing scopes, but in the current version there's no way to change that behavior.
As a workaround, I can have it fail at runtime if I change the classes to look like this:
open class Tag {
operator fun String.unaryPlus()
// pulled up from TagWithChildren, call protected method
fun head(init: Head.() -> Unit) = addChild(Head())
fun script(init: Script.() -> Unit) = addChild(Head())
// throws in Tag
open protected fun addChild(t: Tag) = throw IllegalArgumentException()
}
class TagWithChildren : Tag() {
// overridden to not throw in subclass
protected override fun addChild(t: Tag) = children.add(t)
}
This way, every Tag has the builder methods (solving the scoping problem), but actually calling them may result in a runtime failure.