IntelliJ gives error about reference in Kotlin - intellij-idea

I'm trying to go though the Kotlin tutorial from Freecode camp, but have this issue with references.
IntelliJ complained that
Unresolved reference: greeting in sayHello() in main()
Unexpected
tokens (use ';' to separate expressions on the same line), after
"Hi"
fun sayHello(greeting:String, vararg itemsToGreet: String) {
itemsToGreet.forEach { itemToGreet ->
println("$greeting $itemToGreet")
}
}
fun main() {
val interestingThings = listOf("Kotlin", "Programming", "Comic Books")
sayHello(greeting:"Hi", itemsToGreet:"Kotlin", "Programming", "Comic Books")
}
It seems that assigning values to params can be done only by "=", not ":"

"greeting:" is a parameter name hint. Code should look like this:
sayHello("Hi", "Kotlin", "Programming", "Comic Books")
See how hints will be shown automatically.

Related

How to handle simple error in Kotlin function Android

I'm having trouble handling error in the following function. I'm basically new to Kotlin. Here's my RevenueCat Login Code and I want to handle ::error in this code:
Purchases.sharedInstance.logInWith(
myUserID,
::error // <- How to handle this? I want to retrieve error Code and Error Message.
)
{ customerInfo, created ->
// Handle Successful login here
}
Here's the code behind the function (within RevenueCat SDK)
#Suppress("unused")
fun Purchases.logInWith(
appUserID: String,
onError: (error: PurchasesError) -> Unit = ON_ERROR_STUB,
onSuccess: (customerInfo: CustomerInfo, created: Boolean) -> Unit
) {
logIn(appUserID, logInSuccessListener(onSuccess, onError))
}
The double colon in ::error is a function reference. It is basically a reference to the function error().
And from your logInWith() function, we have onError: (error: PurchasesError) -> Unit = ON_ERROR_STUB, meaning that the function should take PurchasesError as input parameter and does not need to return.
So we can derive a function as the following:
fun error(error: PurchasesError) {
// And you can do something with the error here
}
I solved it like this:
Purchases.sharedInstance.logInWith(
myUserID,
onError = { error ->
// Handle error here
}

Safaricaom Daraja API Android initialization failure (DarajaListener<AccessToken!>! was expected)

This is the way to initialize the Daraja API in Kotlin. Problem is, I get a type mismatch on the forth parameter of Dajara.with(1st, 2nd, 3rd, 4th) function. The error is at the object : DarajaListener parameter.
daraja = Daraja.with("CONSUME_KEY", "CONSUMER_SECRET_KEY", Env.SANDBOX,
**object : DarajaListener<AccessToken>** {
override fun onResult(result: AccessToken) {
Toast.makeText(applicationContext, result.access_token, Toast.LENGTH_SHORT).show()
}
override fun onError(error: String?) {
Toast.makeText(applicationContext, error.toString(), Toast.LENGTH_SHORT).show()
}
})
The build error is as follows:
Type mismatch: inferred type is but DarajaListener<AccessToken!>! was expected
Hovering the cursor around the error flashes this message:
Type mismatch.
Required:DarajaListener<AccessToken!>!Found:
Any help initializing it the right way?
It was a simple matter of imports. I had imported the wrong AccessToken. Instead of the one from the Daraja api, I imported the one provided by Facebook. Can't believe this costed me a week!

Kotlin supplyAsync with executor

I want to create a CompletableFuture with a return value that runs on a specific executor in Kotlin.
The following code works just fine.
return CompletableFuture.supplyAsync {
val commandHandler = registry.get<TCommand, TResponse>(command::class.java)
commandHandler.handle(command)
}
However when I attempt to pass the executor it won't compile.
return CompletableFuture.supplyAsync({
val commandHandler = registry.get<TCommand, TResponse>(command::class.java)
commandHandler.handle(command)
}, exec)
I tried to get clever and wrote the Java version and had Intellij covert it to Kotlin, but that one had the same error as well. What am I doing wrong here?
EDIT:
I can make it work by doing the following but it seems unnecessary. Can someone explain why this works but other methods do not. Are there other ways to write this code?
return CompletableFuture.supplyAsync(Supplier {
commandHandler.handle(command)
}, exec)
I do not exactly know, why it is not working. But the following does work:
return CompletableFuture.supplyAsync({
val commandHandler = registry.get<TCommand, TResponse>(command::class.java)
commandHandler.handle(command)
}, exec::execute)
As you can see, I changed the second parameter to a method reference.
Now the signature of the method is:
supplyAsync(supplier: () -> U, executor: (Runnable)-> Unit)
If you pass the Executor directly, Kotlin chooses the signature:
supplyAsync(supplier: Supplier<U>, executor: Executor)
It looks like you can not mix interface and lambda style.

Kotlin Lambda not calling code inside

I encountered the strangest thing.
Lets say I have a text file called "lines.txt". This file contains lines in key value pairs.
test:100
test1:200
test2:300
test3:400
If I read this file in Kotlin the list is not empty however the loop inside the output stream does not get called.
object App {
#JvmStatic
fun main(args: Array<String>) {
// file containing lines of text
val lines = Files.readAllLines(Paths.get("./hashes.txt"))
// not empty
println(lines.size)
// write back a modified version
PrintWriter(FileWriter(File("./lines2.txt"))).use { out -> {
// this doesn't get called
println(lines.size)
lines.forEach {
out.println(it.split(":")[0])
}
}
}
}
}
I don't understand why this is so if anyone can enlighten me that would be awesome.
The list is not empty. A single println(lines.size) will shown you that, because that println is never called.
You simply have one pair of curly braces too much.
change your code to
...
PrintWriter(FileWriter(File("./lines2.txt"))).use { out ->
// list is empty??
println(lines.size)
lines.forEach {
out.println(it.split(":")[0])
}
}
...
The reason is, that a lambda doesn't need its block in curly braces.
So don't write
out -> { ... }
just write
out -> ...
guenther already told you what is wrong with your code, but I think an explanation of what happened is missing.
Consider the following:
val x = { println("y") }
Will it print out y? No, the lamda is never invoked. You have to call x().
Let's take a look at what you did:
val x = { { println("y") } }
x()
Will it print out y? No, because you don't invoke the lambda that prints y.
To make things more clear, let's specify the types explicitely.
val x:() -> (() -> Unit) = { { println("y") } }
Now we can see that the first lambda invoked by x() returns a lambda as well so you would have to call x()() in order to invoke the returned lambda as well.
So using a second pair a curly braces is not just not optional but gives the code a whole new meaning.
But this means that there would be also another solution to your problem.
PrintWriter(FileWriter(File("./lines2.txt"))).use { out -> {
println(lines.size)
lines.forEach {
out.println(it.split(":")[0])
}
}() // <-- add braces here to invoke the lambda
}
So, you can either remove two brackets are add two more. Choice is yours.
Disclaimer: Removing two braces is the way to go. The other option is just to prove a point.

Scope of variable defined in for loop header

I noticed that the following Kotlin code compiles and executes successfully:
for (i in 1..2) {
val i = "a"
print(i)
}
This prints aa. However, I failed to find rationale behind the decision to allow this kind of variable shadowing. I would say that this is not a good practice, and is prohibited even in Java.
I think that Kotlin designers did a great work of improving Java syntax and accommodating it to the everyday practical use, so I must be missing something here?
Kotlin does not restrict variable shadowing in any way. The rationale is simple: "consistency."
Since you could shadow variables in most other places why would you exclude only some loop variables from the allowed options? Why would they be so special? It is an arbitrary difference.
Any scope can shadow a variable used in another scope. It is NOT good practice and does produce a compiler warning -- but it is allowed.
If you want to engage in a dialog with the contributors of the project, try the discussion forum or slack channel, both are linked from the Kotlin Community page. Otherwise if you feel it is a bug please add an Issue report to Kotlin YouTrack and the answer you receive there will be definitive as well.
In the meantime, you are free to write nonsensical code such as:
val i = 1
class Foo() {
val i = "monkey"
init { println(i) }
#Test fun boo() {
println(i)
val i = i.length
println(i)
if (i == 6) {
val i = Date(System.currentTimeMillis() + i) // Shadow warning
println(i)
}
for (i in 0..i) { // Shadow warning
val i = "chimp $i" // Shadow warning
println(i)
}
InnerFoo()
}
class InnerFoo() {
val i: Long = 100L
init { println(i) }
}
}
Which in Kotlin 1.0.3 produces 3 warnings.
Warning:(15, 21) Kotlin: Name shadowed: i
Warning:(18, 18) Kotlin: Name shadowed: i
Warning:(19, 21) Kotlin: Name shadowed: i
And outputs:
monkeymonkey6Sun Jul 17 11:31:23 UYT 2016chimp 0chimp 1chimp 2chimp 3chimp 4chimp 5chimp 6100