Android Question Is my way of creating code wrong?

vecino

Well-Known Member
Licensed User
Longtime User
Hi, I have recently been alerted by some masters of these forums that I am doing something wrong with calls to some "Sub" that return nothing, they do not need to be "ResumableSub".
I am in the habit of always using "ResumableSub" even if it should not return any value. I do this to make sure that each "Sub" is executed before the next "Sub" is executed.
I paste a piece of example code so you can understand what I mean.
Why is it wrong, why shouldn't it be done this way?
B4X:
Sub Activity_Create(FirstTime As Boolean)
  Activity.LoadLayout("ftpv320x480")

  Wait For (CrearDirectorios) complete (oRes As Object)
  Wait For (setEstetica) complete (oRes As Object)  
  Wait For (LimpiarDB) complete (bRes As Boolean)
  if bRes Then
    ' ...  
  End If
   Wait For (ShowTitulo) complete (oRes As Object)
End Sub

Sub CrearDirectorios As ResumableSub
    Dim rp As RuntimePermissions
    globales.cDBruta            = rp.GetSafeDirDefaultExternal("")
    globales.cDirFotos         = rp.GetSafeDirDefaultExternal(globales.cNameDirFotos)
    '
    Return Null
End Sub

Sub setEstetica As ResumableSub
    pnCabecera.Color = globales.iColorNaranja
    pnFondo.Color = globales.iColorCelesteOscuro
    pnBotones.Color    = globales.iColorCelesteOscuro
    pnBotones.Visible=True
    '
    Return Null
End Sub


Sub LimpiarDB As ResumableSub
    Dim cSq1 As String = $"delete from tbNotasLineasCombinados"$
    Dim cSq2 As String = $"delete from tbNotasLineasComponentes"$
    Dim cSq3 As String = $"delete from tbAgrupamientoDatosVenta"$
    Dim acSq() As String = Array As String(cSq1,cSq2,cSq3)
    '  
    For i=0 To acSq.Length -1
        globales.DBconex.AddNonQueryToBatch( acSq(i), Null )
    Next
    Dim SenderFilter As Object = globales.DBconex.ExecNonQueryBatch("SQL")
    Wait For (SenderFilter) SQL_NonQueryComplete (Success As Boolean)
    '
    Return Success  
End Sub

Sub ShowTitulo As ResumableSub
  lbEmpresa.Text = NumberFormat(globales.cCodigoEmpresa,2,0)
  lbVendedor.Text = NumberFormat(globales.cCodigoVendedor,3,0)  
  '
  Return Null
End Sub
 

Daestrum

Expert
Licensed User
Longtime User
If your code produces the results you expect then it isn't wrong.

Maybe they just meant it could be written differently.
 
Upvote 0

XbNnX_507

Active Member
Licensed User
Longtime User
I have done the same sometimes, i don't think is wrong with it as long as you are not utilizing the returned value which in this case is null.
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
In my opinion, Resumable Subs are not necessary in your cases.
Resumable Subs are useful if you have subs which need a certain time to be done to not bloc the main thread.
How did you call subs before Resumable Subs did exist ?
I use rarely Resumable Subs.
 
Upvote 0

vecino

Well-Known Member
Licensed User
Longtime User
In my opinion, Resumable Subs are not necessary in your cases.
Resumable Subs are useful if you have subs which need a certain time to be done to not bloc the main thread.
How did you call subs before Resumable Subs did exist ?
I use rarely Resumable Subs.

Before, for example, a bit of an exaggeration, but just to be clear:

B4X:
sub Sales
  SelectCustomer
end sub

sub SelectCustomer
  CustomerRisk
end sub

sub CustomerRisk
  ChargeCustomer
end sub

sub ChargeCustomer
  CustomerPaymentMethod
end sub

sub CustomerPaymentMethod
  PaymentMethod = AnotherProcedure
end sub

Now:
B4X:
sub Sales
  wait for (SelectCustomer) ...
  wait for (CustomerRisk) ...
  wait for (ChargeCustomer) ...
  wait for (CustomerPaymentMethod) ...
  ...
end sub
Before the "wait for" it was a mess, I was never sure if a sub was completely executed before calling the next one. Discovering "wait for" was a "blessing", it completely changed the programming, now I could be sure that the code I wanted to be executed had been executed.

Although anyway my question is if there is any inconvenience in returning null if it is not used later.
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
anyway my question is if there is any inconvenience in returning null if it is not used later.
I do not know if there is any inconvenience.
It would be interesting to have Erels' opinion on this, and also about the doubt of routines not finishing before another is executed.
 
Upvote 0

udg

Expert
Licensed User
Longtime User
Hi all.
I can't see any problem in returning a Null from a ResumableSub (it's there just for cases where you don't need a return value).
What it could be "dangerous" in code like post #1 is the use of wait-for in Activity_Create (something similar applies to B4xPages projects): when the first wait-for is reached the Activity_Resume sub is executed. This may be not what you expect or want (e.g. in Resume you make use of something deriving fron the wait-for chain).

Another point to keep in mind; if a ResumableSub calls another function this too should be a ResumableSub in order to keep the wait-for chain executing as expected.

As for the "old style" as shown, why do you have doubts about a routine not completing before the start of the next one?
 
Upvote 0

Sandman

Expert
Licensed User
Longtime User
Another point to keep in mind; if a ResumableSub calls another function this too should be a ResumableSub in order to keep the wait-for chain executing as expected.
Yes! I had so much issues with my code until I understood this. There must be turtles all the way down!
 
Upvote 0

vecino

Well-Known Member
Licensed User
Longtime User
As for the "old style" as shown, why do you have doubts about a routine not completing before the start of the next one?
Hi, because it has happened to me many times, and I don't know if it is because the device is too slow, or too fast, or some other reason.
A more real example (can you be sure that Four will run on completion of Three, and that Three will run on completion of Two?)

B4X:
sub One
  Two
  Three
  Four
end sub

sub Two 
  Five
  Six
end sub

sub Three
  DoSomething
  DoSomethingElse
end sub

sub Four
  DoOneMoreThing
  AndYetAnotherOneMore
end sub

sub Five
  ..
end sub

sub Six
  ..
end sub
 
Upvote 0

vecino

Well-Known Member
Licensed User
Longtime User
Now you have made me doubt.
I'm going to look up an old project where I had that problem and try to replicate it with a simple example.
 
Upvote 0

zed

Active Member
Licensed User
A more real example (can you be sure that Four will run on completion of Three, and that Three will run on completion of Two?)
Not so sure for the result
In an app, on installation, I have to unzip files in xui.DefaultFolder and then loop to get the file names in a ComboBox.
A SUB for unzipping and a sub for the loop with ComboBox.
The SUB unzip is called first. The SUB ComboBox second.
The second finished before the first.
My app crashes.
Finally, I put the call of the second at the end of the first
 
Last edited:
Upvote 0

udg

Expert
Licensed User
Longtime User
I didn't test it, but the "old-style" http download (separate sub JobDone) or other long lasting async sub could alter the expected order of execution.
I mean, you call sub First which has both Second and Third one after the other. But Second starts an async long lasting operation (w/out wait-for).
Will this lead to Three to be executed before Second receives its "you're done" message and so completes itself?
 
Last edited:
Upvote 0

agraham

Expert
Licensed User
Longtime User
It's not complicated. I think you are over thinking this. The calling sequence will always be executed in strict order. Starting an async operation (without WaitFor ) will not disrupt the sequence. The async operation is off doing its thing on another thread, when it is finished it will raise an event for the main thread but the Sub for this event will not execute until any current calling sequence on the main therad is unwound and returns to the app message loop.
 
  • Like
Reactions: udg
Upvote 0

udg

Expert
Licensed User
Longtime User
So, in a way, the message loop is "locked" until the asyn sub is finished?
Since ResumableSubs (and B4xPages) I din't use old style anymore.. and this is showing in emerging doubts when considering that kind of problems. Thank you, @agraham
 
Upvote 0

vecino

Well-Known Member
Licensed User
Longtime User
Well I don't get it, I always (until I discovered "wait for") had the problem of something being executed after a sub call that hadn't finished yet.
Of course, what I have put before are very simple examples, the reality are quite more complex calls with controls, calculations, requesting data to the user, etc. Then the code that followed that call would continue executing without the previous one having finished yet.
That's why my life changed when I discovered "wait for", all those spaghetti code problems were over, trying to control events that jumped from one side to another and subs that were executed without finishing the previous ones.
I don't know if I am making myself clear, many of you already know that my English is that of "DeepL Translate".
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
So, in a way, the message loop is "locked" until the asyn sub is finished?
There is no such thing as an 'async Sub' unless you are running it on a thread with my Threading library. Android, like Windows and Linux and iOS and most operating systems is event driven. Each app has a message queue and each apps' code loops reading the message queue until a message, posted by an event, arrives. The Sub allocated to this event is run and may call another Sub which calls another Sub which then returns and then returns and eventually execution returns to the message loop. Until execution returns to the message loop no other event Sub can run.

An async library function called by a Sub returns to that Sub having started the async function on another thread. That thread is decoupled from the apps' flow of execution and runs alongside the apps' main thread until it's complete and posts an event to the app message loop. Once the apps' flow of execution has returned to the message loop that event can be processed and its event Sub run.

Sleep and WaitFor interrupt the usual calling sequence by returning from the Sub invoking them having posted a message to the message loop for further processing when the event they are waiting for occurs. Eventually the normal flow of execution will return to process the message loop and the Sub that invoked the Sleep or WaitFor will be called from the message loop and re-entered after the Sleep or WaitFor to run the remaining code and will then return, as usual, to its caller which in this case was the app message loop.

Everything happens in strict sequence, including Resumable Subs. There is no magic 'dancing around' taking place.
 
Last edited:
Upvote 0

terryn

Member
Licensed User
Longtime User
To satisfy yourself, why not run the code in debug and step through to see the order of execution
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I am in the habit of always using "ResumableSub" even if it should not return any value. I do this to make sure that each "Sub" is executed before the next "Sub" is executed.
I paste a piece of example code so you can understand what I mean.
Why is it wrong, why shouldn't it be done this way?
It is not wrong. This is the correct way to wait for a resumable sub to complete.
[B4X] Resumable subs that return values (ResumableSub)

There are many cases where it is not needed as you don't want the app to run each sub sequentially.
 
Upvote 0
Top