Is sequence referred to internal DSL in Kotlin? - kotlin

In book 'Kotlin in Action', it says Kotlin DSL structure is most commonly created through chained method calls. Also, a typical library consists of many methods and no context is maintained btw one call and the next.
I'm confused of which side sequence is close to. Before I read this, I've thought sequence is just API of library, but it really fits with feature of DSL.

I'm not 100% sure this answers your question, but I would not think of Sequence pipelines as a "DSL" per se, in particular because it is quite general, which is the opposite of "domain-specific" - the heart of the definition of a DSL.
If you build your own builder API based on chained method calls for a specific domain, you could consider that as a DSL, but I would say Kotlin DSLs are mostly made of nested lambdas with declarative property assignments, rather than chained method calls.
This is because lambdas in Kotlin give the illusion of blocks and structure more than actual functions and function calls, which is why nested structures like this look like their own "language" (the L of DSL). Chained method calls don't look like another "language" - they just look like function calls, but of course that's my subjective take.
For example, here is a Gradle build script using the Gradle Kotlin DSL:
plugins {
`java-library`
}
dependencies {
api("junit:junit:4.13")
implementation("junit:junit:4.13")
testImplementation("junit:junit:4.13")
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
It does look like its own language, you don't immediately think of Kotlin when reading such code.

Related

Gradle Extensions: can plain Kotlin types be used instead of Property<T> for properties with simple values?

The Gradle docs for lazy configuration states that in extension/DSL classes, properties like var someProperty = "default value" should actually be val someProperty: Property<String> = objectFactory.property(String::class.java).convention("default value"). This is to avoid unnecessary computation during the configuration phase;
I wonder if there is any downside in using plain types for simple values. The benefits are clear to me in case of computation or I/O, but if anything, for simple values I’d say a plain type would result in slightly less resource use during configuration (one less object created and no method calls).
The main reasons I prefer plain property types for simple values is simplicity and especially that the assignment operator can be used in a build script with Kotlin DSL, e.g. someProperty = "foo". I find this cleaner than someProperty.set("foo") and the latter is also imperative, while Gradle DSLs are otherwise mostly declarative.
It seems to work fine and in the task there would still be a Property<String> counterpart that can be initialized with someProperty.set(extension.someProperty), but since the documentation doesn’t mention it as a possibility for simple values, I’m wondering if there is a good reason for it that I couldn’t think of.
In addition to avoiding unnecessary computation during the configuration phase, using a property allows you to avoid race conditions with afterEvaluate clauses. Extension values set by build scripts are NOT available at configuration time.
Therefore, your example of task.someProperty.set(extension.somePlainField) will not work.
Using task.someProperty.set(extension.someProperty) (the method with signature set(value: Provider<T>)) makes sure that extension.someProperty.get() is not invoked until the task executes and reads its Property.
in order to achieve your goal of a fluent extension api, the recommended approach is to add a method to your extension such as
fun someProperty(value: String) {
someProperty.set(value)
}
then, build scripts can use it like:
myExtension {
someProperty("my value")
}

How to use Web Speech API in Kotlin Multiplatform for web application

Do you know how to use Web Speech API in KMM project for Web application: https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API
I'm using Kotlin to build the web app, and the web app require speech to text feature.
I'm not familiar with this particular WEB API, but here's the general process of wrapping global JS APIs in Kotlin so hopefully you'll be able to correct the odd inconsistencies yourself via trial and error.
Firstly, since the target API is global, there's no need for any meta-information for the compiler about where to source JS code from - it's present in the global context. Therefore, we only need to declare the shape of that global context. Normally that would be a straightforward task as outlined in this article, however there's a caveat here which requires some trickery to make it work on all the browsers:
As mentioned earlier, Chrome currently supports speech recognition with prefixed properties, therefore at the start of our code we include these lines to feed the right objects to Chrome, and any future implementations that might support the features without a prefix:
var SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition;
var SpeechGrammarList = window.SpeechGrammarList || webkitSpeechGrammarList;
var SpeechRecognitionEvent = window.SpeechRecognitionEvent || >webkitSpeechRecognitionEvent;
But let's ignore that for now since the API shape is consistent across the implementation, and name is the only difference that we'll address later. Two main API entities we need to wrap here are SpeechRecognition and SpeechGrammarList, both being classes. However, to make it easier to bridge the inconsistent names for them later on, in Kotlin it's best to describe their shapes as external interfaces. The process for both is the same, so I'll just outline it for SpeechRecognition.
First, the interface declaration. Here we can already make use from EventTarget declaration in Kotlin/JS stdlib. Note that the name of it does not matter here and will not clash with webkitSpeechRecognition when present since we declare it as an interface and as such we only care about the API shape.
external interface SpeechRecognition: EventTarget {
val grammars: SpeechGrammarList // or dynamic if you don't want to declare nested types
var lang: String
// etc...
}
Once we have the API shape declared, we need to bridge naming inconsistencies and provide a unified way to construct its instances from Kotlin. For that, we'll inject some hacky Kotlin code to act as our constructors.
// We match the function name to the type name here so that from Kotlin consumer's perspective it's indistinguishable from an actual constructor.
fun SpeechRecognition(): SpeechRecognition {
// Using some direct JS code to get an appropriate class reference
val cls = js("window.SpeechRecognition || webkitSpeechRecognition")
// Using the class reference to construct an instance of it and then tell the kotlin compiler to assume it's type
return js("new cls()").unsafeCast<SpeechRecognition>()
}
Hopefully this gives you the general idea of how things tie together. Let me know if something's still not quite clear.

kotlin coroutines: possible without standard library?

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.

Multi-platform InputStream Alternative in Kotlin?

I’m looking for a multi-platform alternative to input streams. My concrete task is to fetch an encrypted file from a remote server via https and decrypt it on demand.
In Java land I would an implement InputStream which proxies the reads to the input stream from the https library. How can I do the same in kotlin targeting multiple platforms.
I see ktor returns an ByteReadChannel, but I don’t know which functions.
I’m lost and don’t know where to start. Thanks for your help in advance.
If the framework you are using does not provide you with a full-fledged InputStream implementation, the only chance left is to write your own. Much like what the ktor developers did: ByteReadChannel is just an abstraction of "reading bytes from a channel".
This abstraction lives in the common part and allows to write application and business logic around it.
The key to make this work in the context of a Kotlin Multiplatform project is, the actual implementation needs to be provided in the platform specific parts. The JVM specific code of the ktor project actually has an implementation that uses InputStream: InputStream.toByteReadChannel.
You certainly don't have to do it like your example from the ktor project and model everything down from byte channels up to file representations. If you want to leverage Kotlin framework classes, Sequences might be handy. This could look something like this:
// in common
interface FileFetcher {
fun fetch(): Sequence<Byte>
}
expect fun fileFetcher(source: String): FileFetcher
// in jvm
class JvmFileFetcher(val input: java.io.InputStream): FileFetcher {
override fun fetch(): Sequence<Byte> = input.readBytes().asSequence()
}
actual fun fileFetcher(source: String): FileFetcher {
val input = java.net.URL(source).openStream()
return JvmFileFetcher(input)
}
You would define an interface FileFetcher along with a factory function fileFetcher in the common part. By using the expect keyword on the fileFetcher function you need to provide platform-specific implementations for all target platforms you define. Use the FileFetcher interface in the common part to implement your logic (decrypting file contents etc.). See the documentation for Sequence for how to work with it.
Then implement the factory function for all platforms and use the actual keyword on them. You will then need to write platform-specific implementations of FileFetcher. My example shows how a JVM version of the FileFetcher interface.
The example is of course very basic and you probably would not want to do it exactly like this (at least some buffering would be needed, I guess). Also, within the JVM part you could also leverage your favorite networking/HTTP library easily.

How to write matchers for all the important test libraries?

I'm currently extending Degraph to check for violation of dependency rules.
So far I have created matchers for ScalaTest, since this is my favorite test library for the JVM. But many others prefer or have to use other libraries. So I'd like to provide matchers (or whatever is the appropriate equivalent) for those as well.
On the other hand I'm lazy so I don't want to provide a matcher for every conceivable library.
So the question is:
Is there some kind of matcher library that can be used in all (or the most / many) test libraries? Or maybe a wrapper that converts Hamcrest matchers to matchers for all the other libs?
The libraries I would like to support (in that order of importance):
JUnit
ScalaTest
most popular testing library for Groovy
most popular testing library for Clojure
Specs2
TestNG
Every unit testing framework I've seen will fail a test that throws an exception.
Hamcrest's assertThat(T value, Matcher<T> matcher) will throw an AssertionError if matcher.matches(value) returns false.
Therefore, Hamcrest should work out-of-the-box with most testing frameworks. For other libraries, such as for building mock objects, you'll need to either use Hamcrest's Matcher objects natively or write an integration layer. One way would be to create a method to decorate any matcher, for example*,
ArgumentMatcher<T> decorate(final Matcher<T> matcher) {
return new ArgumentMatcher() {
public boolean <T> accepts(T value) {
return matcher.matches(value);
}
}
}
* This is a contrived example using a theoretical Mocking API.