B4J Question B4J and DBUtils library

Adrian Jansen

Member
Licensed User
Longtime User
Just a query on the DBUtils implementation. There is, amongst other very useful routines, this one:

DBUitils ExecuteList:
Public Sub ExecuteList(SQL As SQL, Query As String, StringArgs() As String, Limit As Int, List1 As List)
    'List1.Clear
    Dim Table As List
    Table = ExecuteMemoryTable(SQL, Query, StringArgs, Limit)
    If Table.Size = 0 Then
        Log("Table empty")
        
        Return
    End If
    Log("Table size " & Table.Size)
    
    Dim Cols() As String
    For i = 0 To Table.Size - 1
        
        Cols = Table.Get(i)
        
'        Log("Getting item " & i & " " & Cols)
        List1.Add(Cols(0))
    Next
End Sub

While this works to fill things like comboboxes, I cant find any way of just filling a list to be used in code. Maybe I'm dense, but the obvious thing of passing a list name as a parameter just returns an empty list. And in thinking about it, I can see why, since objects in B4X ( like Java ) are passed by value, so you cant alter them within the routine and have them retained on the return. I presume it works with a combobox, because you pass an object which contains a list.
However quite often I want a list I can just operate on in code after an SQL query to get a list of data. Yes I know I can do it ( but it takes more work ) to extract the list after doing an ExecuteMap to get the data returned as a Map

I played with changing the ExecuteList routine to this:
ExecuteListA:
Public Sub ExecuteListA(SQL As SQL, Query As String, StringArgs() As String, Limit As Int) As List
    Dim list1 As List
    list1.Initialize
    
    Dim Table As List
    Table = ExecuteMemoryTable(SQL, Query, StringArgs, Limit)
    If Table.Size = 0 Then
        Log("Table empty")
        
        Return
    End If
    Log("Table size " & Table.Size)
    
    Dim Cols() As String
    For i = 0 To Table.Size - 1
        
        Cols = Table.Get(i)
        
'        Log("Getting item " & i & " " & Cols)
        list1.Add(Cols(0))
    Next
    
    Return list1
End Sub

This seems to do just what I want, allowing to fill either a list, or a combobox with the right data by doing it like this:
ExecuteLIstA call:
cmbRating.SetItems(DBUtilsA.ExecuteListA(SQL, "SELECT rating from tblRating ORDER BY rank ", Null, 0 ))

Or to do it to fill just a list:
Fill list:
Dim lstTest As List
    lstTest.Initialize
    lstTest = DBUtilsA.ExecuteListA(SQL, "SELECT rating from tblRating ORDER BY rank ", Null, 0 )

There must have been some good reason to do it the other way, but I cant see one.

Anybody care to comment ?
 

LucaMs

Expert
Licensed User
Longtime User
I can see why, since objects in B4X ( like Java ) are passed by value, so you cant alter them within the routine
That's not true; try this:
Sub xxx:
Sub xxx
    Dim lstMain As List
    lstMain.Initialize
    lstMain.Add(1)
    lstMain.Add(2)
    lstMain.Add(3)
    LogList(lstMain)
    ModifyList(lstMain)
    Log("-------")
    LogList(lstMain)
End Sub

B4X:
Private Sub ModifyList(lst As List)
    lst.Add(4)
End Sub

Private Sub LogList(l As List)
    For Each i As Int In l
        Log(i)
    Next
End Sub
Log:
1
2
3
-------
1
2
3
4


However I've rarely used DBUtils, in the past, so I won't comment further (also because I've only read up to that sentence 😁 I'm not fully awake yet, it's very early)
 
Upvote 0

Adrian Jansen

Member
Licensed User
Longtime User
Thanks for the response. I must admit I ddnt try something that simple, but I dd try passing a list to the DBUrils ExecuteList routine, rather than a combobox, and found that it simply created an empty list. Thats what started me on doing it the other way. I was only just beginning with both B4J and SQLite then, so I may easily have missed something.
 
Upvote 0

Adrian Jansen

Member
Licensed User
Longtime User
Ok, just tried it using the DBUtils ExecuteList routine like this
B4X:
Dim listt As List
    listt.Initialize
    DBUtilsA.ExecuteList(SQL, "SELECT rating FROM tblRating ORDER BY rank ", Null, 0, listt)
    Log ("Listt filled " & listt)
And it works, producing

Listt filled (ArrayList) [WT, WG, Easy, Medium, Hard, Very Hard]

which is what I expected. I will crawl back in my box ....
 
Upvote 0

Adrian Jansen

Member
Licensed User
Longtime User
But just 1 more comment, while I am playing around
If you do this
B4X:
Private Sub btnTest_Click
    
    Dim tvalue = 10 As Int
    modify_value(tvalue)
    Log("Outside after " & tvalue)
    
    
End Sub

Private Sub modify_value(value As Int)
    Log ("Inside before " & value)
    
    value = 45
    Log("Inside after " & value)
End Sub

Then the log shows
Inside before 10
Inside after 45
Outside after 10

This is what I would expect, knowing that values are passed by value, rather than by reference in Java
Obviously lists are different.
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
It works the same for all objects, including lists. I like to think of lists (and maps and arrays) as complex objects where you can access inner structures.
Primitive objects like Int, Float, Double, String and Boolean are simple objects made up of ordered bit sequences (which of course you also access)
Neither type of objects can be destroyed outside their scope (i.e. inside a called sub). It works like this for all objects including instances of classes.

B4X:
Private Sub test   
    Dim a As List
    a.Initialize
    a.Add("A")
    a.Add("B")
    a.Add("C")
    testDestroy(a)
    Log("outside sub " & a.Size)    'outside 3
End Sub

Private Sub testDestroy(a As List)
    Dim b As List
    b.initialize
    a = b          'Now 'a" points to the object b, the original object that 'a' pointed to is still intact
    Log("inside sub " & a.Size)        'inside 0
End Sub
 
Upvote 0

EnriqueGonzalez

Well-Known Member
Licensed User
Longtime User
Your last example I think it's an edge case. If instead of doing a = b you add an element inside that sub or delete its contents then it will reflected overall.

I may even say that you can re initialize and it will clear all the data.

My inderstansing is that a = b is not affecting the variable per se just assigning memory somewhere else, the old value continued to be referenced and that's why you see those results.

Primitive values will be passed by value
Objects will be passed by reference
But a = b doesn't destroy the reference it just points to a new reference and the old reference remains intact
 
Upvote 0

aeric

Expert
Licensed User
Longtime User
You may create a new copy of an object:
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
I defer to the guru @agraham


"In the case of a non-primitive type the value of a variable is a refererence to the object instance. The point of pass by value is that a called function cannot change the value of the original variable. However if the value is a reference it can modify the object whose reference it is."

So in a way, the internal structure of primitives is read-only (immutable) and the internal structure of non-primitives is read and write. They are both passed by value and can't be destroyed outside their scope.

Precision of terms is highly valued in our field, but certainly, we all understand how to do this - whatever our mental model is.
 
Upvote 0
Top