Kotlin Coroutines, decompiled code of a suspend function - kotlin

I'm reading Kotlin Coroutines by Tutorials, Chapter 4 - Suspending functions here by Ray Wenderlich
However, I'm really struggling to understand the author's explanation of the decompiled code. Would someone be able to explain/describe the path of execution in the decompiled code as it pertains to suspend functions/continuations?
suspend fun getUserSuspend(userId: String): User {
delay(1000)
return User(userId, "Filip")
}
#Nullable
public static final Object getUserSuspend(
#NotNull String userId,
#NotNull Continuation var1) {
Object $continuation;
label28: {
if (var1 instanceof < undefinedtype >) {
$continuation = (<undefinedtype>)var1;
if ((((<undefinedtype>)$continuation).label & Integer.MIN_VALUE) != 0) {
((<undefinedtype>)$continuation).label -= Integer.MIN_VALUE;
break label28;
}
}
$continuation = new ContinuationImpl(var1) {
// $FF: synthetic field
Object result;
int label;
Object L $0;
#Nullable
public final Object invokeSuspend (#NotNull Object result) {
this.result = result;
this.label | = Integer.MIN_VALUE;
return MainKt.getUserSuspend((String)null, this);
}
};
}
Object var2 =((<undefinedtype>)$continuation).result;
Object var4 = IntrinsicsKt . getCOROUTINE_SUSPENDED ();
switch(((<undefinedtype>)$continuation).label) {
case 0:
if (var2 instanceof Failure) {
throw ((Failure) var2).exception;
}
((<undefinedtype>)$continuation).L$0 = userId;
((<undefinedtype>)$continuation).label = 1;
if (DelayKt.delay(1000L, (Continuation)$continuation) == var4) {
return var4;
}
break;
case 1:
userId = (String)((<undefinedtype>)$continuation).L$0;
if (var2 instanceof Failure) {
throw ((Failure) var2).exception;
}
break;
default:
throw new IllegalStateException ("call to ’resume’ before ’invoke’ with coroutine");
}
return new User (userId, "Filip");
}

I found this video particularly useful. I've linked the relevant section in the video here: https://youtu.be/YrrUCSi72E8?t=393
at roughly 6:33, where he talks about continuations and labels.
Essentially, when a coroutine is suspended, the continuation is used to save the coroutine state. Once the method is no longer suspended (e.g a result was returned, or the task is done etc.), the continuation's "resume" method recalls the method with the continuation.

Related

RxJava2 Flowable that emits results of multiple network calls without using create?

I have a generic screen that subscribes to an RxJava2 flowable that returns a List. It then displays the content in the list.
I have a use case now though where I need to collect data from multiple endpoints, and emit data once some complete, and then emit data again once the remaining ones complete.
I'm doing this using Flowable.create() but I've seen a lot of posts saying that there's usually a better and safer way to do so than using create? I seem to believe that is the case since I need to subscribe to an observable within the observable which ideally I wouldn't want to do?
Because I subscribe within, I know the emitter can become cancelled within the observable while other network calls are completing so I've added checks to ensure it doesn't throw an error after its disposed which do work (at least in testing...) [I also just remembered I have the code available to dispose of the inner subscription if I kept it like this, when the outer is disposed]
The first 2 calls may be incredibly fast (or instant) which is why i want to emit the first result right away, and then the following 4 network calls which rely on that data may take time to process.
It looks roughly like this right now...
return Flowable.create<List<Object>>({ activeEmitter ->
Single.zip(
single1(),
single2(),
BiFunction { single1Result: Object, single2result: Object ->
if (single1result.something || single2Result.somethingElse) {
activeEmitter.onNext(function(single1result, single2result) //returns list
}
Single.zip(
single3(single1result),
single4(single2result),
single5(single1result),
single6(single2result),
Function4 { single3Result: Object,
single4Result: Object,
single5Result: Object,
single6Result: Object ->
ObjectHolder(single1Result, single2Result, single3Result, single4Result, single5Result, single6Result)
}
)
}
).flatMap { objectHolder ->
objects.flatMap { objectHolder ->
Single.just(parseObjects(objectHolder))
}
}.subscribeBy(
onError = { error ->
if (!activeEmitter.isCancelled) {
activeEmitter.onError(error)
}
},
onSuccess = { results ->
if (!activeEmitter.isCancelled) {
activeEmitter.onNext(results)
activeEmitter.onComplete()
}
}
)
}, BackpressureStrategy.BUFFER)
I can't figure out another way to return a Flowable that emits the results of multiple different network calls without doing it like this?
Is there a different/better way I can't find?
I worked this out given ctranxuan response. Posting so he can tweak/optimize and then I accept his answer
return Single.zip(single1(), single2(),
BiFunction { single1result: Object, single2result: Object ->
Pair(single1result, single2result)
}
).toFlowable()
.flatMap { single1AndSingle2 ->
if (isFirstLoad) {
createItemOrNull(single1AndSingle2.first, single1AndSingle2.second)?.let { result ->
Single.just(listOf(result)).mergeWith(proceedWithFinalNetworkCalls(single1AndSingle2))
}.orElse {
proceedWithFinalNetworkCalls(single1AndSingle2).toFlowable()
}
} else {
proceedWithFinalNetworkCalls(single1AndSingle2).toFlowable()
}
}.doOnComplete {
isFirstLoad = false
}
fun proceedWithFinalNetworkCalls(): Flowable<List> {
return Single.zip(
single3(single1result),
single4(single2result),
single5(single1result),
single6(single2result),
Function4 { single3Result: Object,
single4Result: Object,
single5Result: Object,
single6Result: Object ->
ObjectHolder(single1Result, single2Result, single3Result, single4Result, single5Result, single6Result)
}
)
Sorry, it's in Java but from what I've understood, something like that may be a possible solution?
public static void main(String[] args) {
final Single<String> single1 = single1().cache();
single1.map(List::of)
.mergeWith(single1.zipWith(single2(), Map::entry)
.flatMap(entry -> Single.zip(
single3(entry.getKey()),
single4(entry.getValue()),
single5(entry.getKey()),
single6(entry.getValue()),
(el3, el4, el5, el6) -> objectHolder(entry.getKey(), entry.getValue(), el3, el4, el5, el6))))
.subscribe(System.out::println,
System.err::println);
Flowable.timer(1, MINUTES) // Just to block the main thread for a while
.blockingSubscribe();
}
private static List<String> objectHolder(final String el1,
final String el2,
final String el3,
final String el4,
final String el5,
final String el6) {
return List.of(el1, el2, el3, el4, el5, el6);
}
static Single<String> single1() {
return Single.just("s1");
}
static Single<String> single2() {
return Single.just("s2");
}
static Single<String> single3(String value) {
return single("s3", value);
}
static Single<String> single4(String value) {
return single("s4", value);
}
static Single<String> single5(String value) {
return single("s5", value);
}
static Single<String> single6(String value) {
return single("s6", value);
}
static Single<String> single(String value1, String value2) {
return Single.just(value1).map(l -> l + "_" + value2);
}
This outputs:
[s1]
[s1, s2, s3_s1, s4_s2, s5_s1, s6_s2]

Updating GUI from another class which implements SerialPortEventListener (Java FX, FXML)

I am making an application which uses serial communication. In SerialEvent method of that class, I am awaiting for a input from COM port, and then I want to pass it to the controller class of an .fxml screen.
Input will always be 8 bytes, and it works correctly inside that thread (I read the input and by printing it to the output, I see that the String is correct). However, when I try to pass it "in real time" to the controller class, I have a problem.
If I pass it directly, it does receieve it, but I can't invoke anything later (Not on FX Application Thread exception), I know that I can't do it that way, that I need to use Platform.runLater or similair solution, but if I use it that way, my controller class never receives that input, textField which I am trying to update stays blank.
I will copy part of the code here, and I am hoping that someone tell me what I'm doing wrong.
SERIALEVENT METHOD OF ANOTHER CLASS
#Override
public void serialEvent(SerialPortEvent spe) {
if (spe.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
try {
byte singleData = (byte) input.read();
logText = new String(new byte[]{singleData});
bytes.add(logText);
if(bytes.size() == 8) {
for (int i = 0; i < bytes.size(); i++) {
inputText += bytes.get(i);
}
if(inputText.length() == 8) {
Platform.runLater(new Runnable() {
#Override
public void run() {
controller.getInputString(inputText);
}
});
}
bytes.clear();
inputText = "";
}
} catch (Exception e) {
logText = "Failed to read data. (" + e.toString() + ")";
controller.getInputString(logText);
}
}
}
GETINPUT METHOD OF THE CONTROLLER CLASS
#Override
public void getInputString(String input) {
firstSerialNumberField.setText(input);
}
When using it this way, my firstSerialNumberField never gets that input.
---EDIT---
SETCONTROLLER METHOD OF THE SERIALPORTLISTENER CLASS
public void setController(SerialController controller) {
this.controller = controller;
}
INITIALIZE SCREEN IN SCREEN HANDLER CLASS
serialCommunication = new SerialCommunication(this);
loader = new FXMLLoader();
loader.setLocation(getClass().getResource(path));
pane = loader.load(getClass().getResource(path).openStream());
serialController = (SerialController) loader.getController();
serialController.setScreenHandler(this);
serialController.setSerialCommunication(serialCommunication);
serialCommunication.setController(serialController);
parent = loader.getRoot();
stage = new Stage();
stage.setScene(new Scene(parent));
stage.setTitle(title);
stage.setResizable(false);
stage.sizeToScene();
stage.centerOnScreen();
stage.initModality(Modality.APPLICATION_MODAL);
stage.showAndWait();
You are passing a reference to inputText to the (inappropriately-named) getInputText() method in the controller. inputText is presumably a field in the class implementing the port listener. However, as soon as you pass it, you then set it back to an empty string:
if(inputText.length() == 8) {
Platform.runLater(new Runnable() {
#Override
public void run() {
controller.getInputString(inputText);
}
});
}
bytes.clear();
inputText = "";
Since inputText is being accessed from multiple threads, there is no guarantee as to which order things will happen: whether controller.getInputText(inputText) will execute first, or whether inputText = ""; will execute first. So you may end up setting the text field to an empty string.
What I think you intend to do is:
if(inputText.length() == 8) {
final String numberFieldText = inputText ;
Platform.runLater(new Runnable() {
#Override
public void run() {
controller.getInputString(numberFieldText);
}
});
}
or more succinctly:
if(inputText.length() == 8) {
final String numberFieldText = inputText ;
Platform.runLater(() -> controller.getInputString(numberFieldText));
}

Java 8 Iterator to stream to iterator causes redundant call to hasNext()

I notice a bit of a strange behavior in the following scenario:
Iterator -> Stream -> map() -> iterator() -> iterate
The hasNext() of the original iterator is called an additional time after having already returned false.
Is this normal?
package com.test.iterators;
import java.util.Iterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class TestIterator {
private static int counter = 2;
public static void main(String[] args) {
class AdapterIterator implements Iterator<Integer> {
boolean active = true;
#Override
public boolean hasNext() {
System.out.println("hasNext() called");
if (!active) {
System.out.println("Ignoring duplicate call to hasNext!!!!");
return false;
}
boolean hasNext = counter >= 0;
System.out.println("actually has next:" + active);
if (!hasNext) {
active = false;
}
return hasNext;
}
#Override
public Integer next() {
System.out.println("next() called");
return counter--;
}
}
Stream<Integer> stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(new AdapterIterator(), 0), false);
stream.map(num -> num + 1).iterator().forEachRemaining(num -> {
System.out.println(num);
});
}
}
If I either remove the map() or replace the final itearator() with something like count() or collect() it works without the redundant call.
Output
hasNext() called
actually has next:true
next() called
3
hasNext() called
actually has next:true
next() called
2
hasNext() called
actually has next:true
next() called
1
hasNext() called
actually has next:true
hasNext() called
Ignoring duplicate call to hasNext!!!!
Yes, this is normal. The redundant call happens in StreamSpliterators.AbstractWrappingSpliterator.fillBuffer(), which is called from the hasNext() method of the iterator returned by stream.map(num -> num + 1).iterator(). From the JDK 8 source:
/**
* If the buffer is empty, push elements into the sink chain until
* the source is empty or cancellation is requested.
* #return whether there are elements to consume from the buffer
*/
private boolean fillBuffer() {
while (buffer.count() == 0) {
if (bufferSink.cancellationRequested() || !pusher.getAsBoolean()) {
if (finished)
return false;
else {
bufferSink.end(); // might trigger more elements
finished = true;
}
}
}
return true;
}
The call to pusher.getAsBoolean() calls hasNext() on the original AdapterIterator instance. If true, it adds the next element to bufferSink and returns true, otherwise it returns false. When the original iterator runs out of items and it returns false, this method calls bufferSink.end() and retries filling the buffer, which leads to the redundant hasNext() call.
In this case, bufferSink.end() has no effect and the second attempt to fill the buffer is unnecessary, but as the source comment explains, it "might trigger more elements" in another situation. This is just an implementation detail buried deep in the complex inner workings of Java 8 streams.

ArrayList partial integrating one List in another

I have a function that creates regular Objects of a same type and I cannot avoid that step.
When I use List.addAll(*) I will get many "Duplications" that are not equal in sense of Objectivity.
I have a very bad coded solution and want to ask if there could be a better or more effective one maybe with Java-Util-functions and defining a Comparator for that single intermezzo?
Here is my bad smell:
private void addPartial(List<SeMo_WikiArticle> allnewWiki, List<SeMo_WikiArticle> newWiki) {
if(allnewWiki.isEmpty())
allnewWiki.addAll(newWiki);
else{
for(SeMo_WikiArticle nn : newWiki){
boolean allreadyIn = false;
for(SeMo_WikiArticle oo : allnewWiki){
if(nn.getID()==oo.getID())
allreadyIn= true;
}
if(!allreadyIn)
allnewWiki.add(nn);
}
}
}
Any Ideas?
Add an override function of equals() into class SeMo_WikiArticle :
class SeMo_WikiArticle {
// assuming this class has two properties below
int id;
String name;
SeMo_WikiArticle(int id, String name) {
this.id = id;
this.name = name;
}
#Override
public boolean equals(Object obj) {
// implement your own comparison policy
// here is an example
if (obj instanceof SeMo_WikiArticle) {
SeMo_WikiArticle sw = (SeMo_WikiArticle)obj;
if (this.id == sw.id && (this.name == sw.name || this.name.equals(sw.name))) {
return true;
}
}
return false;
}
}
After that you can use contains() to judge if the list has already contains the specific object of SeMo_WikiArticle.
Here is the code:
private void addPartial(List<SeMo_WikiArticle> allnewWiki, List<SeMo_WikiArticle> newWiki) {
for (SeMo_WikiArticle sw : newWiki) {
if (!allnewWiki.contains(sw)) {
allnewWiki.add(sw);
}
}
}

How to access property of anonymous type?

Considering this IronPython script
def SensorEvent(d):
print d
print d.Message
... how do I access properties of d?
First line of the SensorEvent method successfully prints
{ Message = blah blubb }
however second line throws an exception:
'<>f_anonymousType[str]' object has no attribute 'Message'
Explanation
d is an instance of an anonymous type provided by an invoke from a C# method. I'm invoking it like this:
public static async void ExecutePyFunc(string name, dynamic data)
{
try
{
var f = strategyScope.GetVariable<Action<object>>(name);
if (f != null)
{
await Task.Run(() => f((object)data));
}
}
catch (Exception x)
{
StaticLog("[Callback Exception] Fehler beim Ausführen einer Python Funktion: {0}", x.Message);
}
}
d is a dictionary. Access it like so:
d['Message']
My solution using DynamicObject: I've introduced a class that converts an anonymous type into a known type by copying its properties via reflection (I don't need anything but the properties but it could probably be enhanced for use with fields, methods, functions as well).
Here's what I've come up with:
public class IronPythonKnownType : DynamicObject
{
public IronPythonKnownType(dynamic obj)
{
var properties = obj.GetType().GetProperties();
foreach (PropertyInfo prop in properties)
{
var val = prop.GetValue(obj);
this.Set(prop.Name, val);
}
}
private Dictionary<string, object> _dict = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (_dict.ContainsKey(binder.Name))
{
result = _dict[binder.Name];
return true;
}
return base.TryGetMember(binder, out result);
}
private void Set(string name, object value)
{
_dict[name] = value;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_dict[binder.Name] = value;
return true;
}
}
which effectively converts the anonymous object into something IronPython can handle.
Now I can do that:
def Blubb(a):
print a.Message
without getting the mentioned exception.