Wish Allow accessing a ResumableSub return value without using Wait For

Russ J

Member
Wish: I believe currently the only way to get a return value from a ResumableSub is to use Wait For. However, I would like to asynchronously call several ResumableSubs that all have return values. If there was a Result function on the ResumableSub object, I believe this would allow for cleaner code.

Note: I have already implemented a workaround that achieves the desired result; the workaround code just isn't as straightforward.

Result from ResumableSub object:
Public Sub LoadTable1() As ResumableSub
  Dim somemap1 as Map
  '...Call and wait on some REST function over the Internet which might take a while
  return somemap1
End Sub

Public Sub LoadTable2() As ResumableSub
  Dim somemap2 as Map
  '...Call and wait on some REST function over the Internet which might take a while
  return somemap2
End Sub

Public Sub LoadTable3() As ResumableSub
  Dim somemap3 as Map
  '...Call and wait on some REST function over the Internet which might take a while
  return somemap3
End Sub

Public Sub LoadTablesAndDoSomething
  Dim rs1 As ResumableSub = CallSub(Starter, "LoadTable1")
  Dim rs2 As ResumableSub = CallSub(Starter, "LoadTable2")
  Dim rs3 As ResumableSub = CallSub(Starter, "LoadTable3")
  If Not(rs1.Completed) Then
    Wait For(rs1) Complete
  End If
  If Not(rs2.Completed) Then
    Wait For(rs2) Complete
  End If
  If Not(rs3.Completed) Then
    Wait For(rs3) Complete
  End If
  Dim Table1Map as Map = rs1.Result '<<< Example of wished-for function "Result"
  Dim Table2Map as Map = rs2.Result '<<< Example of wished-for function "Result"
  Dim Table3Map as Map = rs3.Result '<<< Example of wished-for function "Result"
  '...Do something else
End Sub
 

Sagenut

Expert
Licensed User
Longtime User
You need to call various ResumableSubs and collect a Result from every Sub.
Every Result should be collected independently from the other and do something without waiting for the other Subs to finish?
 

Russ J

Member
All the subs are waiting on responses from independent http calls and are unpredictable on how long each one will take each to get a response. Because of this, I don't want to do the calls one at a time as Android/B4A are both quite capable of issuing all the calls prior to receiving any responses.

As stated, I do have this working, but the code isn't a pretty as it could be with the wished-for Result function. Essentially, right now I am storing the results off in process_globals as a workaround. Here is the workaround:

B4X:
        Dim rs1 As ResumableSub
        Dim rs2 As ResumableSub
        Dim rs3 As ResumableSub
        
        Table1Map = Starter.Table1Map 
        If Not(Table1Map.IsInitialized) Then
            rs1  = CallSub(Starter, "LoadTable1Map")
        End If

        Table2Map = Starter.Table2Map
        If Not(Table2Map.IsInitialized) Then
            rs2 = CallSub(Starter, "LoadTable2Map")
        End If
        
        Table3Map = Starter.Table3Map 
        If Not(Table3Map.IsInitialized) Then
            rs3 = CallSub(Starter, "LoadTable3Map")
        End If
        
        If rs1.IsInitialized Then
            If Not(rs1.Completed) Then
                Wait For(rs1) Complete
            End If
            Table1Map = Starter.Table1Map 
        End If
        
        If rs2.IsInitialized Then
            If Not(rs2.Completed) Then
                Wait For(rs2) Complete
            End If
            Table2Map = Starter.Table2Map 
        End If
        
        If rs3.IsInitialized Then
            If Not(rs3.Completed) Then
                Wait For(rs3) Complete
            End If
            Table3Map = Starter.Table3Map 
        End If
 

Sagenut

Expert
Licensed User
Longtime User
Check if this is what you are thinking of
B4X:
Sub Button1_Click
    Table1    'Call 3 ResumableSubs in sequence
    Table2
    Table3
End Sub

Sub Table1 As ResumableSub
    Sleep(5000)    '5 seconds of pause to simulate a Job
    CallSubDelayed2(Me, "ResultTable1", "I am the Result of Table1")    'Give the Result to Sub ResultTable1
End Sub

Sub Table2 As ResumableSub
    Sleep(3000)    '3 seconds of pause to simulate a Job
    CallSubDelayed2(Me, "ResultTable2", "I am the Result of Table2")    'Give the Result to Sub ResultTable2
End Sub

Sub Table3 As ResumableSub
    Sleep(1000)    '1 seconds of pause to simulate a Job
    CallSubDelayed2(Me, "ResultTable3", "I am the Result of Table3")    'Give the Result to Sub ResultTable3
End Sub

Sub ResultTable1 (result As String)
    Log(result)
    'Do something...
End Sub

Sub ResultTable2 (result As String)
    Log(result)
    'Do something...
End Sub

Sub ResultTable3 (result As String)
    Log(result)
    'Do something...
End Sub
*** EDIT ***
Changed CallSub2 into CallSubDelayed2
 
Last edited:

Russ J

Member
Similar workaround, except I need to know when all 3 are done and the order of completion cannot be predicted. I realize it can be done with various booleans and callbacks, but I believe my wish would allow for a simpler solution.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
There are all kinds of problems to implement it, including the fact that Wait For can handle events with multiple parameters.

Code that waits for multiple resumable subs:
B4X:
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
    Dim res As Map = CreateMap()
    Dim rss() As ResumableSub = Array As ResumableSub(S1(res), S2(res), S3(res))
    Wait For (WaitForSubs(rss)) Complete (unused As Boolean)
    Dim r1 As Int = res.Get("S1")
    Log(r1)
End Sub

Sub WaitForSubs (rss() As ResumableSub) As ResumableSub
    Dim completed As Boolean = False
    Do While completed = False
        completed = True
        For Each rs As ResumableSub In rss
            If rs.Completed = False Then completed = False
        Next
        Sleep(50)
    Loop
    Return True
End Sub

Sub S1 (Result As Map) As ResumableSub
    Sleep(Rnd(10, 5000))
    Result.Put("S1", 1) '1 is the result
    Return True
End Sub

Sub S2 (Result As Map) As ResumableSub
    Sleep(Rnd(10, 5000))
    Result.Put("S2", 2)
    Return True
End Sub

Sub S3 (Result As Map) As ResumableSub
    Sleep(Rnd(10, 5000))
    Result.Put("S3", 3)
    Return True
End Sub
 
Top