B4R Question Events: Same Variables - different behavior, Why?

JanG

Member
Licensed User
Longtime User
I have problems with the connection events (ESP8266WIFI) and I try to identify the problems. Now I have isolated one issue that makes trouble in my code:

When comparing objects, the result of the comparison should be the same, independently at which part of the code I do this comparion, as long as I leave the content of the variables alone. But in b4r it's not! The result of the comparision of the same variables is different between code in the main-part and in the event-part (here Timer, but in connection event of ESP8266WIFI still the same).

Here is the result and my code, you see the problem at comparision 4-5:
a) Why is the same comparision different in main and event (4-5)?
b) Why is are two uninitialized fields (0-1) equal and two Null-initialzed fields (2-3) not equal?

B4X:
AppStart 0-1: 1
AppStart 2-3: 0
AppStart 4-5: 1
AppStart 6-7: 1
.
Timer1_Tick 0-1: 1
Timer1_Tick 2-3: 0
Timer1_Tick 4-5: 0
Timer1_Tick 6-7: 1
B4X:
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 300
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public Serial1 As Serial
    Public Timer1 As Timer
   
    Public ObjectArray(8) As Object
    Public IntArray(8) As Int
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
   
    Delay(2000)
   
    ObjectArray(2) = Null
    ObjectArray(3) = Null
    ObjectArray(4) = IntArray(0)
    ObjectArray(5) = IntArray(0)
    ObjectArray(6) = ObjectArray(0)
    ObjectArray(7) = ObjectArray(0)
           
    Log("AppStart 0-1: ", ObjectArray(0) = ObjectArray(1))
    Log("AppStart 2-3: ", ObjectArray(2) = ObjectArray(3))
    Log("AppStart 4-5: ", ObjectArray(4) = ObjectArray(5))
    Log("AppStart 6-7: ", ObjectArray(6) = ObjectArray(7))
   
    Log(".")
   
    Timer1.Initialize("Timer1_Tick", 1000)
    Timer1.Enabled = True
End Sub

private Sub Timer1_Tick
    Log("Timer1_Tick 0-1: ", ObjectArray(0) = ObjectArray(1))
    Log("Timer1_Tick 2-3: ", ObjectArray(2) = ObjectArray(3))
    Log("Timer1_Tick 4-5: ", ObjectArray(4) = ObjectArray(5))
    Log("Timer1_Tick 6-7: ", ObjectArray(6) = ObjectArray(7))
   
    Timer1.Enabled = False
End Sub
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You can only assign numeric types to global variables.

The problem is here:
B4X:
ObjectArray(4) = IntArray(0)
It creates a global reference to a stack based object. This means that sooner or later the reference becomes invalid and points to a random value.

If you want to store global numbers then use a numeric type. For arrays of bytes or strings you should use GlobalStore: https://www.b4x.com/android/forum/threads/73863/#content
 
Upvote 0

JanG

Member
Licensed User
Longtime User
Okay, thank you! But I have to store objects, more precisely AsyncStreams/Sockets. How can I do that? If I do it only in the main path everything is fine. The problem only occurs if I do it in an event function.

And why is IntArry(0) a stack based object? IntArray is defined in Process_Globals. I can access IntArray in the event function, too, without any problem. But if I use the global object array that has a reference to this IntArray, the problem occurs.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
But I have to store objects, more precisely AsyncStreams/Sockets. How can I do that?
Please post the code or pseudo code that you are trying to run.

AsyncStreams and sockets should be global variables. Don't use the Object type to hold them. Use the explicit type.

And why is IntArry(0) a stack based object?
IntArray is not stack based. The problem is that ObjectArray is an array of objects. If you change it to a numeric array then it will work properly.
The object created to wrap the int is created on the stack.
 
Upvote 0

JanG

Member
Licensed User
Longtime User
Please post the code or pseudo code that you are trying to run.
Okay, I will do it, but I have to make it more readable ;). In the meantime here a new code example. The result is strange.
I compared the results in:
a) main thread
b) CallSubPlus
c) Event (Timer)
And all 3 results look different (see 4-5)...
a) okay, as expected
b) The content of the vars is 33 (as expected), but the comparision says they are not the same (I know it's references, but to the same object).
c) Now the contents have gone.
B4X:
0: 0-1: 1
0: 2-3: 0
0: 4-5: 1
0: 6-7: 1
0: MyTypeVar1: 33
0: MyTypeVar2: 33
1: 0-1: 1
1: 2-3: 0
1: 4-5: 0
1: 6-7: 1
1: MyTypeVar1: 33
1: MyTypeVar2: 33
2: 0-1: 1
2: 2-3: 0
2: 4-5: 0
2: 6-7: 1
2: MyTypeVar1: 0
2: MyTypeVar2: 0
The source:
B4X:
Public Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Type MyType (ByteVar As Byte)
   
    Public Serial1 As Serial
    Public Timer1 As Timer
   
    Public ObjectArray(8) As Object
    Public IntArray(8) As Int
    Public MyTypeVar As MyType
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
   
    Delay(1000)
       
    MyTypeVar.ByteVar = 33
   
    ObjectArray(2) = Null
    ObjectArray(3) = Null
    ObjectArray(4) = MyTypeVar
    ObjectArray(5) = MyTypeVar
    ObjectArray(6) = ObjectArray(0)
    ObjectArray(7) = ObjectArray(0)
           
    LogFunction(0)
   
    CallSubPlus("LogFunction", 1000, 1)

    Timer1.Initialize("Timer1_Tick", 2000)
    Timer1.Enabled = True
End Sub

private Sub Timer1_Tick
    CallSubPlus("LogFunction", 0, 2)
    Timer1.Enabled = False
End Sub

Private Sub LogFunction(Tag As Byte)
    Dim TempMyTypeVar1 As MyType
    Dim TempMyTypeVar2 As MyType
   
   
    TempMyTypeVar1 = ObjectArray(4)
    TempMyTypeVar2 = ObjectArray(5)
   
    Log(Tag, ": 0-1: ", ObjectArray(0) = ObjectArray(1))
    Log(Tag, ": 2-3: ", ObjectArray(2) = ObjectArray(3))
    Log(Tag, ": 4-5: ", ObjectArray(4) = ObjectArray(5))
    Log(Tag, ": 6-7: ", ObjectArray(6) = ObjectArray(7))
   
    Log(Tag, ": MyTypeVar1: ", TempMyTypeVar1.ByteVar)
    Log(Tag, ": MyTypeVar2: ", TempMyTypeVar2.ByteVar)
   
    Log(" ")
End Sub
 
Upvote 0

JanG

Member
Licensed User
Longtime User
This the same problem as before. You cannot assign a global object variable.

Sorry, but that can't be the problem. I did another test. Please see my code example. I created a "static object map" (module). This module stores every kind of object. It works like a charme! I do assign global objects by using a wrapper type. It works perfectly, even more or less in the events. But in the event (Timer) the key object is not in the right state, i think. That leads to a crash. But, once again, if I don't use events, the code works properly!
Here the output:
B4X:
AppStart
Map Content Size: 3
Content (Key/Value): 101/201
Content (Key/Value): 102/202
Content (Key/Value): 103/203
Map Content Size: 2
Content (Key/Value): 101/201
Content (Key/Value): 103/203
Map Content Size: 2
Content (Key/Value): 101/201
Content (Key/Value): 103/203
Map Content Size: 3
Content (Key/Value): 101/201
Content (Key/Value): 103/203
Content (Key/Value): 102/203
Map Content Size: 3
Content (Key/Value): 0/201
Content (Key/Value): 0/203
Exception (28):
epc1=0x40202551 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000002 depc=0x00000000
ctx: cont
sp: 3ffef5a0 end: 3ffef7f0 offset: 01a0
>>>stack>>>
3ffef740:  00000000 3ffee414 00000002 4020253d
[...]
Here the code snippet:
B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Type MyType (ByteVar As Byte)

    Private Serial1 As Serial
    Private Timer1 As Timer

    Public KeyMyType1 As MyType
    Public KeyMyType2 As MyType
    Public KeyMyType3 As MyType

    Public ValueMyType1 As MyType
    Public ValueMyType2 As MyType
    Public ValueMyType3 As MyType
End Sub

private Sub LogMapContent
    Dim i As Int
   
    Dim TempKeyMyType As MyType
    Dim TempValueMyType As MyType
   
    Dim TempKeyObjectWrapper As ObjectWrapper
    Dim TempValueObjectWrapper As ObjectWrapper
   
   
    Log("Map Content Size: ", StaticObjectMap.Count)
   
    For i = 0 To (StaticObjectMap.GetNextPos - 1)
        If StaticObjectMap.GetAtPos(i, TempKeyObjectWrapper, TempValueObjectWrapper) Then
            TempKeyMyType = TempKeyObjectWrapper.EnclosedObject
            TempValueMyType = TempValueObjectWrapper.EnclosedObject
            Log("Content (Key/Value): ", TempKeyMyType.ByteVar, "/", TempValueMyType.ByteVar)
        End If
    Next
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Delay(1000)
    Log("AppStart")


    ' Mark the Objects to make them identifiable
    KeyMyType1.ByteVar = 101
    KeyMyType2.ByteVar = 102
    KeyMyType3.ByteVar = 103

    ValueMyType1.ByteVar = 201
    ValueMyType2.ByteVar = 202
    ValueMyType3.ByteVar = 203

    ' Initialize the map   
    StaticObjectMap.Init

    ' Add 3 element pairs (key/value), the map contains 3
    StaticObjectMap.Put(KeyMyType1, ValueMyType1)
    StaticObjectMap.Put(KeyMyType2, ValueMyType2)
    StaticObjectMap.Put(KeyMyType3, ValueMyType3)
    LogMapContent
   
    ' Remove the 'middle' element, the map contains 2
    StaticObjectMap.Remove(KeyMyType2)
    LogMapContent

    ' Add an already existing element, no change, the map contains 2
    StaticObjectMap.Put(KeyMyType3, ValueMyType3)
    LogMapContent

    ' Add the deletes element again (on the top, with another value), the map contains 3
    StaticObjectMap.Put(KeyMyType2, ValueMyType3)
    LogMapContent
   
    Timer1.Initialize("Timer1_Tick", 3000)
    Timer1.Enabled = True
End Sub

Sub Timer1_Tick
    LogMapContent
   
    Timer1.Enabled = False
End Sub
 

Attachments

  • TestStreamStore.zip
    2.4 KB · Views: 351
Upvote 0

JanG

Member
Licensed User
Longtime User
I did another test. You are right!!! When using a well known type, that means NOT the object type, in my module, it works! But that means, my universal object map is now dependent on the given type.

But, i'm sorry, I don't understand why (with universal objects) it works only in the main and not in the events.

Thank you for your brilliant support!
 
Upvote 0
Top