fun main(args: Array<String>) {
HelloWorldApp().launch()
}
fun App.launch() {
JFXPanel()
Platform.runLater({
start(Stage())
})
}
This is what I do right now. Is there a better? more succinct way?
Is it safe to run multiple different TornadoFX apps from within the same kotlin program this way? I read something somewhere about a global variable so I'm wondering if only 1 is allowed/recommended.
The JVM already knows how to start JavaFX applications, and since your App class extends tornadofx.App which again extends javafx.application.Application, you can simply point your JVM to that main class and it will run just fine. If you want to explicitly launch your TornadoFX application, JavaFX provides a static launch method you should use.
A typical main function that starts a JavaFX or TornadoFX application would be:
fun main(args: Array<String>) {
Application.launch(HelloWorldApp::class.java, *args)
}
JavaFX only allows the Application.launch function to be called one time in the life of a JVM, so you can't really start more than one anyways. However, TornadoFX provides special OSGi support allowing you to actually stop and relaunch other TornadoFX apps in the same JVM by utilizing an application proxy instance.
TornadoFX also supports JPro by using Scopes, which allows multiple application instance, though without actually calling Application.launch several times.
You can start it like this:
fun main(args: Array<String>) {
launch<HelloWorldApp>(args)
}
The launch function is defined in tornadofx package as a top-level function, HelloWorldApp is a random Application class.
Related
Let's assume I'm writing a library that returns a string which is a complex and long running task.
I can chose between offering this
interface StringGenerator {
suspend fun generateString(): String
}
or
interface StringGenerator {
fun generateString(): Deferred<String>
}
Are there any (dis-)advantages of either of the options and which are they? Which should I choose?
Kotlin coroutines are designed along the "sequential by default" guideline. That means that your API should always expose suspend funs and the user, if and when they really need it, can easily wrap them in async.
The advantage of that is analogous to the advantages of cold flows with respect to hot flows: a suspendable function is active only while control is inside it. When it returns, it has not left behind a task running in the background.
Whenever you return a Deferred, the user must start worrying what happens if they don't manage to await on the result. Some code paths may ignore it, the calling code may get an exception, and then their application has a leak.
My question is rather theoretical.
I am quite new to kotlin (only passed the tutorial, didn't write any real code).
Reading through the language reference I find myself confused about the fact that "suspend" is a keyword, yet I can't find anything like "launch" in the list of keywords. That makes me think that there is some asymmetry - the "suspend" is a compiler feature, yet "launch" is a library function. Is my understanding correct? If so - wouldn't it have been better to implement both as library features or both as compiler features?
I always thought that you can always write your own standard library using the available language features, but I still can't see if this really applies to this case.
TL;DR: Can I start a coroutine using pure kotlin, without importing any libraries whatsoever (however ugly that would be)?
The suspend marker adds a hidden continuation parameter to the function signature and completely changes the implementation bytecode. Suspension points don't boil down to helper function calls, they turn your linear program code into a state machine, the state being kept in the continuation object. The resulting bytecode isn't even representable as Java program code.
As opposed to that, launch is just regular library code that builds upon the suspend/resume primitive.
#Alexey Soshin's isn't quite correct.
You can use coroutines w/o the library, and it's pretty easy. Here is a about the simplest suspending coroutine example that has 0 dependency on the coroutine library.
import kotlin.coroutines.*
fun main() {
lateinit var context: Continuation<Unit>
suspend {
val extra="extra"
println("before suspend $extra")
suspendCoroutine<Unit> { context = it }
println("after suspend $extra")
}.startCoroutine(
object : Continuation<Unit> {
override val context: CoroutineContext = EmptyCoroutineContext
// called when a coroutine ends. do nothing.
override fun resumeWith(result: Result<Unit>) {
result.onFailure { ex : Throwable -> throw ex }
}
}
)
println("kick it")
context.resume(Unit)
}
This runs fine on the play.kotlinlang.org site.
As you can see from this code, any lambda decorated with suspend has the startCourtine() on it.
In fact, I think the SequenceBuilder() from the standard collection classes uses a simple coroutine like this to generate the sequence, with no dependency on the coroutine library.
The compiler is doing the heavy lifting on the coroutines, splitting the code into different "methods" at each possible suspending point. Look at the java code for this, and you'll see it's "split" into a switch statement. one case before the suspend, and another after.
The library does a ton of nice stuff for you..... and it's likely you'll almost always use it (cuz why not?) but you don't actually need it.
Can I start a coroutine using pure kotlin, without importing any libraries whatsoever (however ugly that would be)?
No. All coroutine generators are inside kotlinx.coroutines library, so you'll need at least that. Now, very theoretically, you could reimplement this functionality yourself. But probably you shouldn't.
How this can be done is a bit too long for a StackOverflow answer, but try invoking method of this Kotlin class from Java:
class AsyncWorks {
suspend fun print() {
println("Hello")
}
}
You'll see that although Kotlin method has no arguments, in Java it requires Continuation<? super Unit>. This is what suspend keyword does. It adds Continuation<T> as the last argument of our function.
wouldn't it have been better to implement both as library features or
both as compiler features?
Ideally, you'd want everything to be a "library feature", since it's easier to evolve. Removing a keyword from a language is very hard. In theory, having suspend as a keyword could be avoided. Quasar, being a framework, uses annotations instead. Go programming language, on the other hand, assumes all functions are suspendable. All those approaches have their advantages and disadvantages.
Kotlin decided to be pragmatic, and add suspend keyword, leaving the decision on the developers. If you're interested in the topic, I highly recommend this talk by Roman Elizarov, author of Kotlin coroutines, that explains their decissions: https://www.youtube.com/watch?v=Mj5P47F6nJg
Answering my own question here.
After a year of Kotlin I tend to think that this IS indeed possible.
The suspend language feature creates an extra class and instantiates it every time your suspend function is called. This class extends ContinuationImpl and stores the progress of your coroutine - to which point it was able to execute so far.
Therefore one will need to write a custom dispatcher that would be able to manage the queue of the continuation objects to decide which one has to run now and a launch function that would take the newly created continuation object and pass it over to the dispatcher.
Now, this is still an asymmetry - the ContinuationImpl lives in kotlin.coroutines.jvm.internal so the compiler assumes this package exists. If one really wants to drop the standard library altogether - he'll need to implement that package to be able use the suspend keyword.
I'm not a kotlin expert though, so I might be wrong.
Because coroutines are valid for use cases that don't support launch. Because suspend requires some specific support from the compiler and launch doesn't if you already have suspend. Because structured concurrency is a library framework on top of the language feature, and launch is a part of that specific framework, that makes specific choices on top of what the language requires.
Starting a coroutine without any libraries can be done with startCoroutine. kotlin.coroutines is part of Kotlin, not a library.
I have defined main(args: Array) in two Kotlin files in the same package. The compiler does not complain. Why not?
I am using IntelliJ IDEA with Gradle
#file1.kt
package test
fun main(args: Array<String>) {}
#file2.kt
package test
fun main(args: Array<String>) {}
Would the compiler complain if it was Java? No.
Since main method is an entry point to your application, the problem can arise only when there is ambiguity in the application that you are trying to compose. In your question, you haven't provided any specifics about your application. Those 2 files can be completely unaware of each other for what it's worth.
It can be a problem at startup, but even that would rarely happen these days. Modern frameworks, like Spring Boot, have their own way to identify where to start your application, that is where the entry point is.
They make use of their specific MANIFEST files and context/class loaders and project structures.
I would like to specifically know how the common module is used by the individual client modules. Which are the truly common parts that is shared by all the clients and the server.
Thank you.
This is easy. I suspect you're talking about Kotlin multiplatform modules.
Consider print and println.
In the common module we can expect a print function:
expect fun print(a: String)
But we don't know how was it implemented, because the common module doesn't know anything about Java's System.out, as well as JavaScript's console.
But the common module can expect such function that prints a String on screen, without providing an implementation.
Since we have print, we can implement println:
fun println(a: String) = print("$a\n")
All codes above are inside the common module.
And all you have to do is to to implement print for JVM/JS spererately.
For JVM:
actual fun print(a: String) = System.out.println(a)
For JS:
actual fun print(a: String) = console.log(a)
(Maybe) For Native:
actual fun print(a: String) = printf(a)
The three code blocks above are inside client modules.
Consider you've designed a data format, you have encoding and decoding code. Those codes are used in your Android device (JVM), your backend server (JVM), your frontend webpage (JS), your native app (Native).
You use Kotlin in all those sub projects but you want to write the encoder/decoder only once. Kotlin multiplatform module solves this probelm.
About the spinner app
It's not using the standard kotlin approach for creating multiplatform project. It's a trick on gradle.
There's a readResources (and randomInit as well, for osx/linux) function that implements differently on platforms but of the same signature, and gradle will decide which Kommon.kt should be compiled with the client projects.
readResources and randomInit should be marked as actual, and there should be a "common module" that has "expect"ed those two functions.
They didn't do this probably because Kotlin 1.2 (which brings stable multiplatform support) isn't out when KotlinConf holds.
I have a Kotlin interface with a default implementation, for instance:
interface Foo {
fun bar(): String {
return "baz"
}
}
This would be okay until I try to implement this interface from Java. When I do, it says the class need to be marked as abstract or implement the method bar(). Also when I try to implement the method, I am unable to call super.bar().
Generating true default methods callable from Java is an experimental feature of Kotlin 1.2.40.
You need to annotate the methods with the #JvmDefault annotation:
interface Foo {
#JvmDefault
fun bar(): String {
return "baz"
}
}
This feature is still disabled by default, you need to pass the -Xjvm-default=enable flag to the compiler for it to work. (If you need to do this in Gradle, see here).
It really is experimental, however. The blog post warns that both design and implementation may change in the future, and at least in my IDE, Java classes are still marked with errors for not implementing these methods, despite compiling and working fine.
Please see the related issue.
There is a recommendation in the comments:
Write your interface in Java (with default methods) and both the Java and Kotlin classes correctly use those defaults
If you know you won't be overriding the function in any implementations of your interface, you can use extension functions as a nice workaround for this issue. Just put an extension function in the same file as the interface (and at the top level so other files can use it).
For example, what you're doing could be done this way:
interface Foo {
// presumably other stuff
}
fun Foo.bar(): String {
return "baz"
}
See the docs on extension functions for more information about them.
One "gotcha" worth noting:
We would like to emphasize that extension functions are dispatched statically, i.e. they are not virtual by receiver type. This means that the extension function being called is determined by the type of the expression on which the function is invoked, not by the type of the result of evaluating that expression at runtime.
Put simply, extension functions don't do what you might expect from regular polymorphism. What this means for this workaround is that the default function cannot be overridden like a regular function. If you try to override it, you'll get some weird behavior, because the "overridden" version will be called whenever you're dealing explicitly with the subclass, but the extension version will be called when you're dealing with the interface generically. For example:
interface MyInterface {
fun a()
}
fun MyInterface.b() {
println("MyInterface.b() default implementation")
}
class MyInterfaceImpl : MyInterface {
override fun a() {
println("MyInterfaceImpl.a()")
}
fun b() {
println("MyInterfaceImpl.b() \"overridden\" implementation")
}
}
fun main(args: Array<String>) {
val inst1: MyInterface = MyInterfaceImpl()
inst1.a()
inst1.b() // calls the "default" implementation
val inst2: MyInterfaceImpl = MyInterfaceImpl() // could also just do "val inst2 = MyInterfaceImpl()" (the type is inferred)
inst2.a()
inst2.b() // calls the "overridden" implementation
}
Since Kotlin 1.4.0, you can use one of the following compiler flags:
-Xjvm-default=all
-Xjvm-default=all-compatibility (for binary compatibility with old Kotlin code)
This will enable JVM default method compilation for all interfaces.
If you want to read up on how to set these flags in your IDE or Maven/Gradle project, check out the documentation on compiler options.
Progress on this is being tracked in issue KT-4779, which also includes a helpful summary of the current state. The #JvmDefault annotation and the older -Xjvm-default=enable and -Xjvm-default=compatibility compiler flags should no longer be used.
Unlike earlier version of Java8, Kotlin can have default implementation in interface.
When you implement Foo interface into a Java class. Kotlin hides those implementation of interface method. As stated here.
Arrays are used with primitive datatypes on the Java platform to avoid the cost of boxing/unboxing operations. As Kotlin hides those implementation details, a workaround is required to interface with Java code
This is specific for Arrays in above link but it also applies to all the classes (May be to give support for earlier version of Java8).
EDIT
Above explanation is opinion based.
One thing i came across and that is the main reason.
Kotlin binaries were compiled with java bytecode version 1.8 without default methods in interfaces. And they are facing critical issue solving it.