Official documentation code gives `Type 'KProperty0<Int>' has no method 'getValue(MyClass, KProperty<*>)' and thus it cannot serve as a delegate` - kotlin

Did copy/paste from official documentation:
https://kotlinlang.org/docs/delegated-properties.html#delegating-to-another-property
var topLevelInt: Int = 0
class ClassWithDelegate(val anotherClassInt: Int)
class MyClass(var memberInt: Int, val anotherClassInstance: ClassWithDelegate) {
var delegatedToMember: Int by this::memberInt
var delegatedToTopLevel: Int by ::topLevelInt
val delegatedToAnotherClass: Int by anotherClassInstance::anotherClassInt
}
var MyClass.extDelegated: Int by ::topLevelInt
And there is an error:
I think I need some packages imported, like this answer does, but for Intellij, not Jetpack Compose : https://stackoverflow.com/a/63877349/10777336

The code from the documentation only works for Kotlin version 1.4+. From What's New 1.4:
Better inference for delegated properties
The type of a delegated property wasn’t taken into account while analyzing the delegate expression which follows the by keyword. For instance, the following code didn’t compile before, but now the compiler correctly infers the types of the old and new parameters as String?:
import kotlin.properties.Delegates
fun main() {
var prop: String? by Delegates.observable(null) { p, old, new ->
println("$old → $new")
}
prop = "abc"
prop = "xyz"
}
So you should just update your Kotlin version to 1.4+.

Related

Trying to implement the TornadoFX "Motivational example"

I'm trying to implement the motivational example from this page: https://docs.tornadofx.io/0_subsection/1_why_tornadofx
For this I need a data class Person as defined here:
class Person(id: Int, name: String, birthday: LocalDate) {
val idProperty = SimpleIntegerProperty(id)
var id by idProperty
val nameProperty = SimpleStringProperty(name)
var name by nameProperty
val birthdayProperty = SimpleObjectProperty(birthday)
var birthday by birthdayProperty
val age: Int get() = Period.between(birthday, LocalDate.now()).years
}
To do this it was neccessary to make the following imports:
import javafx.beans.property.SimpleIntegerProperty
import javafx.beans.property.SimpleObjectProperty
import javafx.beans.property.SimpleStringProperty
import java.time.LocalDate
import java.time.Period
However, if I try to run the example I get the following error:
Kotlin: Property delegate must have a 'getValue(Person, KProperty<*>)' method. None of the following functions is suitable:
public open fun getValue(): Int! defined in javafx.beans.property.SimpleIntegerProperty
I can circumvent this by not using delegate types and setting the properties like this:
val idProperty = SimpleIntegerProperty(id)
var id: Int
get() = idProperty.value
set(value) { idProperty.value = value}
But that seems to defeat the point of using delegates in TornadoFX when this is their motivational example for using it.
Here's what I found on delegate types: https://edvin.gitbooks.io/tornadofx-guide/content/part2/Property_Delegates.html
That doesn't help with getting the shorthand of var id by idProperty to work though.
Can somebody point me in the right direction here?
You need to also import the following:
import tornadofx.getValue
import tornadofx.setValue
Those are extension operator functions defined for various types in JavaFX (e.g., properties, observable values, etc.) so that those types can be used as delegates. But those function aren't defined in those types, thus the need for the additional imports.

Mock auto-generated setter in Kotlin with Mockito

Let's say I have the following interface:
internal interface IRegisters {
var i: Short
var pc: Int
var sp: Int
}
Now, when I compile that interface, the public fields are replaced by getters and setters. I suppose that the final result is not exactly this, but let's assume it is for simplicity sake:
internal interface IRegisters {
fun getI(): Short
fun setI(value: Short)
fun getPc(): Int
fun setPc(value: Int)
fun getSp(): Int
fun setSp(value: Int)
}
My problem is: with Mockito, I can mock the getter part the following way:
Mockito.`when`(registersMock.sp).thenReturn(16)
Which I suppose is replaced behind the scenes at some point in the compiling process for something like this:
Mockito.`when`(registersMock.getSp()).thenReturn(16)
I verified that this is in fact correct replacing the .thenReturn part for a .thenAnswer. The invocation.method while calling to the answer method of the answer was, indeed, getSp.
My question is: how do I mock (if it is even possible) the set counterpart?
I have tried this:
Mockito.`when`(registersMock.sp = ArgumentMatchers.anyInt()).then...
But it tells me that assignments are not expressions, and only expressions are allowed in this context. And, because the setSp(value: Int) doesn't exist yet, I can't do the following either:
Mockito.`when`(registersMock.setSp(ArgumentMatchers.anyInt())).then...
...as it gives a unresolved reference error (which is reasonable, as the behavior is consistent if I try the getSp() counterpart).
This is specially infuriating because I can verify the setSp method using the = assignment the following way:
Mockito.verify(
registersMock,
times(1)
).sp = 0x300
Thanks in advance.
took a while, but I found something working. The trick was to swap the whenever and the doAnswer.
For example I can extract the passed-in Int when the setter is called.
working solution:
source code:
interface IRegisters {
var sp: Int
}
mock in tests:
val mockIRegister = mock<IRegister>()
var lastSp: Int? = null
doAnswer { invocation ->
lastSp = invocation.getArgument(0) as? Int
}
.whenever(mockIRegister)
.sp = anyInt()

How to use DeprecationLevel.ERROR

Let's say I am writing a library and have a class that looks something like this (contrived example, but shows self reference:
import java.util.logging.Logger
class MyClass(private val myNum: Int) {
companion object {
private val LOG = Logger.getLogger(MyClass::class.java.canonicalName)
}
constructor() : this(1337)
fun addTo(num: Int): Int {
LOG.fine { "Adding num $num to $myNum" }
return myNum + num
}
fun doubleAdd(num: Int): Int = 2 * addTo(num)
}
Now, I have decided that I want to deprecate this class and have my consumers move on to to better things, so I give them a warning.
#Deprecated("Don't use!", level = DeprecationLevel.WARNING)
class MyClass(private val myNum: Int) {
// ...
}
Now, after some more time I'd like to increase the strictness with my deprecation. I still want the library to be binary compatible, so I do not remove the code I see that there is the DeprecationLevel.ERROR available, so I try to use it.
#Deprecated("Don't use!", level = DeprecationLevel.ERROR)
class MyClass(private val myNum: Int) {
// ...
}
Except now, when I try to compile my own project, I get compiler errors:
e: /path/to/project/src/main/kotlin/MyClass.kt: (7, 44): Using 'MyClass' is an error. Don't use!
e: /path/to/project/src/main/kotlin/MyClass.kt: (10, 23): Using 'MyClass' is an error. Don't use!
This is on both the MyClass reference and the this primary constructor reference.
What is the point of DeprecationLevel.ERROR? If I am using it wrong, what is the intended use, and how do I use it?
NOTE: This whole example was done with Kotlin 1.2.21
It does exactly what is described in the documentation: DeprecationLevel
ERROR means usage of that code generates an error in the compiler. This is when you know using the code is going to cause problems and you'd rather crash the compilation, even if that code compiled fine previously.
There is also the HIDDEN deprecation level which does what you describe. It 'hides' the annotated element from the compiler but leaves it in the binary output. This will still cause a compilation error in your project because it is meant for binary compatibility, not newly compiled code.

Use Javascript libraries in Kotlin

The last time I used Kotlin was Dec 2015 when I used it to solve a couple of Project Euler problems.
This time I want to try its interoperability with Javascript. Now my question is, how do we import/use existing Javascript libraries in Kotlin?
I've seen some people using the native keyword, and I just want a brief explanation of it.
There's no native keyword anymore, there's #native annotation. Currently, it's working solution and you can use it with 1.0.x branch of Kotlin compiler. However, we are going do deprecate this annotation in favour of extern annotations, so be prepared to rewrite your code eventually for 1.1.x branch.
When you put #native annotation on a class or on a top-level function, two things happen:
Its body is not compiled to JavaScript.
Compiler references this class or function directly, without package name and mangling.
I think it's easier to explain by providing example of a JavaScript library:
function A(x) {
this.x = x;
this.y = 0;
}
A.prototype.foo = function(z) {
return this.x + this.y + z;
}
function min(a, b) {
return a < b ? a : b;
}
and a corresponding Kotlin declaration
#native class A(val x: Int) {
var y: Int = noImpl
fun foo(z: Int): Int = noImpl
}
#native fun min(a: Int, b: Int): Int = noImpl
Note that noImpl is a special placeholder that's required because of non-abstract functions required bodies and non-abstract properties require initializers. BTW, when we replace #native with extern, we'll get rid of this noImpl.
Another aspect of interoperation with JS libraries is including libraries via module system. Sorry, we don't have any solution right now (but are going to release it soon). See proposal. You can use the following workaround for node.js/CommonJS:
#native interface ExternalModule {
fun foo(x: Int)
}
#native fun require(name: String): dynamic = noImpl
fun main(args: Array<String>) {
val module: ExternalModule = require("externalModule")
module.foo(123)
}
where external module is declared like this
function foo(x) {
return x + 1;
}
module.exports = { foo : foo };
I added a simple barebone project as an example of how to do Kotlin2Js.
https://bitbucket.org/mantis78/gradle4kotlin2js/src
Here is the gradle file that is the main recipe.
group 'org.boonhighendtech'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.1.2-5'
repositories {
maven { url 'http://dl.bintray.com/kotlin/kotlin-dev/' }
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin2js'
repositories {
maven { url 'http://dl.bintray.com/kotlin/kotlin-dev/' }
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
}
build {
outputs.dir("web/")
}
build.doLast {
copy {
from 'src/main/webapp'
into 'web/'
include '**/*.html'
include '**/*.js'
include '**/*.jpg'
include '**/*.png'
}
configurations.compile.each { File file ->
copy {
includeEmptyDirs = false
from zipTree(file.absolutePath)
into "${projectDir}/web"
include { fileTreeElement ->
def path = fileTreeElement.path
path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
}
}
}
}
clean.doLast {
file(new File(projectDir, "/web")).deleteDir()
}
compileKotlin2Js {
kotlinOptions.outputFile = "${projectDir}/web/output.js"
kotlinOptions.moduleKind = "amd"
kotlinOptions.sourceMap = true
}
Firstly, you can assign a dynamic variable then essentially code it like you code JavaScript, dynamically.
e.g.
val jQuery: dynamic = passedInJQueryRef
jQuery.whateverFunc()
But if your intention is to have it typed, then you need to introduce types to the external library. One way is to make use of the relatively extensive libraries of typedefs by https://github.com/DefinitelyTyped/DefinitelyTyped
Find the ts.d there, then run ts2kt (https://github.com/Kotlin/ts2kt) to get your Kotlin files. That typically gets you there. Occasionally, certain conversions are not well done. You will have to hand fix the conversion. E.g. snapsvg's snapsvg.attr() call takes in "{}" but it got converted to some strange interface.
It was
fun attr(params: `ts$2`): Snap.Element
And I replaced it with
fun attr(params: Json): Snap.Element
and it works like a charm.
Kotlin 1.1 introduces the externalmodifier that can be used to declare functions and classes written directly in JS, see http://kotlinlang.org/docs/reference/js-interop.html

How to write a package-level static initializer in Kotlin?

A previous question shows how to put a static initializer inside a class using its companion object. I'm trying to find a way to add a static initializer at the package level, but it seems packages have no companion object.
// compiler error: Modifier 'companion' is not applicable inside 'file'
companion object { init { println("Loaded!") } }
fun main(args: Array<String>) { println("run!") }
I've tried other variations that might've made sense (init on its own, static), and I know as a workaround I can use a throwaway val as in
val static_init = {
println("ugly workaround")
}()
but is there a clean, official way to achieve the same result?
Edit: As #mfulton26's answer mentions, there is no such thing as a package-level function really in the JVM. Behind the scenes, the kotlin compiler is wrapping any free functions, including main in a class. I'm trying to add a static initializer to that class -- the class being generated by kotlin for the free functions declared in the file.
Currently there is no way to add code to the static constructor generated for Kotlin file classes, only top-level property initializers are getting there. This sounds like a feature request, so now there is an issue to track this: KT-13486 Package-level 'init' blocks
Another workaround is to place initialization in top-level private/internal object and reference that object in those functions that depend on the effect of that initialization. Objects are initialized lazily, when they are referenced first time.
fun dependsOnState(arg: Int) = State.run {
arg + value
}
private object State {
val value: Int
init {
value = 42
println("State was initialized")
}
}
As you mentioned, you need a property with something that would run on initialisation:
val x = run {
println("The package class has loaded")
}
I got around it by using a Backing Property on the top-level, under the Kotlin file. Kotlin Docs: Backing Properties
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
// .... some other initialising code here
}
return _table ?: throw AssertionError("Set to null by another thread")
}