B4J Question Classes & objects problems.

LucaMs

Expert
Licensed User
Longtime User
I wanted to run a test: a CallSubDelayed on an object-variable referring to an object that "no longer exists" (?).

So I created a B4J project "on the fly" and I came across some rather strange things (one of which I don't even write... at least for now).

It is not easy to explain in words what the problems are, so
I am attaching the project, which is very simple (B4J).

A class has an object variable which refers to an object instantiated elsewhere.
This object is set to null. If inside the class I use a CallSubDelayed "to the variable", the method is executed as if the object still exists.


Another problem is:
B4X:
'gmapRooms.Get(3).As(clsRoom) = Null' *** --> Compile-time error message ***
clsRoom exists, of course, and the object in "3" too.
 

Attachments

  • CallSubTest.zip
    9.6 KB · Views: 153

Heuristx

Active Member
Licensed User
Longtime User
I wanted to run a test: a CallSubDelayed on an object-variable referring to an object that "no longer exists" (?).

So I created a B4J project "on the fly" and I came across some rather strange things (one of which I don't even write... at least for now).

It is not easy to explain in words what the problems are, so I am attaching the project, which is very simple (B4J).

A class has an object variable which refers to an object instantiated elsewhere.
This object is set to null. If inside the class I use a CallSubDelayed "to the variable", the method is executed as if the object still exists.


Another problem is:
B4X:
'gmapRooms.Get(3).As(clsRoom) = Null' *** --> Compile-time error message ***
clsRoom exists, of course, and the object in "3" too.

That's not how it works.
In B4X you don't have to free objects(memory taken up by them) because they are reference-counted.
If you have a variable that points to your object, in your example, User, then the object still exists in memory.

There is a map item pointing to your object. Then you also point to the same object with the variable called User.
You can delete this object from the map(but not the way you try to do it), your User variable still points to the object, so the system will keep the object alive.

And even if you set all variables referring to your objects to Null, your object may still be in the memory because garbage collection does not happen at once but periodically. It takes some time for the actual object to disappear completely, but if you have nothing to refer to, it does not matter.

This makes no sense:
gmapRooms.Get(3).As(clsRoom) = Null

What exactly are you trying to set to Null? The item in the map? Then you have to Put a Null into the map with the same Key as your User object has.

But simply removing the item from the map does work, so setting the map item to Null is not necessary.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
I know that in B4A in order for the garbage collector, which by the way you cannot invoke directly, to eliminate an object it is necessary to eliminate any reference to that object, but then how to do it in a case like that?
 
Upvote 0

Heuristx

Active Member
Licensed User
Longtime User

Literally eliminate the references. If you remove the item in the Map, that should be enough.
I don't know how you can test when the object is collected by the garbage collector, because you have no reference to it, so how do you test it? But why test it, it will be collected.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
If you remove the item in the Map, that should be enough.
No, because there is a reference inside the clsUser (object user).

But why test it, it will be collected.
The case. The global map contains N room objects. One of this is "passed" (reference) to an object User. While the user is accidentally disconnected from the server (the client loses the connection for a few seconds) the server can decide to delete the room from the map. At that point for the server the room no longer exists, but the user still has a reference to that room and could run CallSubDelayed2(ThatRoom, "Method", ...) which will work - error.
 
Upvote 0

Heuristx

Active Member
Licensed User
Longtime User
The method you call is inside the class User. The Room is also a field in User.
If you only delete the Room from the Map, User.Room is still a reference to Room.
To eliminate that, you have to say User.Room = Null.
 
Upvote 0

Heuristx

Active Member
Licensed User
Longtime User
I guess if you lose connection to a server then on reconnecting you'll have to validate local stuff, how could the local variable know that an instance was deleted from a server?
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
"Fortunately" also rooms have references to users (an array, in this specific case), so when the server deletes a room, before doing so it can call a method of the user class to inform it of this (the user class can set the reference - which is private - to the room to null).
The problem remains that the "physical" client (the app), reconnected, could induce the user object to run callsubdelayed anyway.
[I wrote it before reading your last one.]
 
Upvote 0

Heuristx

Active Member
Licensed User
Longtime User
One question remains: I did not understand why this is not compiled:
B4X:
'gmapRooms.Get(3).As(clsRoom) = Null' *** --> Compile-time error message ***

Map.Get(Key) is a function.
It will return a value that you can assign to a variable:

x = Map.Get(k)
and then you can set x to Null:
x = Null

But directly trying to set a function result to Null does not make sense. What would it do?
You can say Map.Put(k, Null) to actually set the map item to null.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Map.Get(Key) is a function.
It will return a value
Map.Get is a function that returns an object that you should be able to cast to a defined type.

Tested (and it works):
B4X:
Type typSomething(Name As String)
'...
Log(CreatetypSomething("Erel").As(typSomething).Name)

B4X:
Public Sub CreatetypSomething (Name As String) As Object
    Dim t1 As typSomething
    t1.Initialize
    t1.Name = Name
    Return t1
End Sub
 
Upvote 0

Heuristx

Active Member
Licensed User
Longtime User
Map.Get is a function that returns an object that you should be able to cast to a defined type.

Tested (and it works):
B4X:
Type typSomething(Name As String)
'...
Log(CreatetypSomething("Erel").As(typSomething).Name)

B4X:
Public Sub CreatetypSomething (Name As String) As Object
    Dim t1 As typSomething
    t1.Initialize
    t1.Name = Name
    Return t1
End Sub

You can absolutely cast it, but you are also trying to set it to Null.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
1629240554165.png


Why? Just because I'm very curious, of course ?
 
Upvote 0
Top