Wiki improvements

Forum for discussion about the documentation project.
fxm
Posts: 8970
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Wiki improvements

Postby fxm » May 26, 2019 13:36

In the array descriptor, I do not see a field to discriminate a fix-len array against a var-len array.
MrSwiss
Posts: 3081
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Wiki improvements

Postby MrSwiss » May 26, 2019 13:38

Just added that comment in my post, because I know by now,
your "modus operandi", which always requires, additionals ... ;-(
(and, it's honestly, a pain in the rear, having to spell things out,
for the umpteenth time)
fxm
Posts: 8970
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Wiki improvements

Postby fxm » May 26, 2019 14:53

My remark was sufficient in itself. It was not necessary (and I was not asking it) to update your post.
MrSwiss
Posts: 3081
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Wiki improvements

Postby MrSwiss » May 26, 2019 14:57

fxm wrote:My remark was sufficient in itself. It was not necessary (and I was not asking it) to update your post.

Your remark was written at about the same time, as my addition
(you just posted Seconds, before I did).

It's IMO, not necessary to mention -exx in every post, that's what irks me, most ...
(and, your (failing) attempt, to always be 100% correct, people are very well able
"to read between the lines", too)
speedfixer
Posts: 327
Joined: Nov 28, 2012 1:27
Location: California

Re: Wiki improvements

Postby speedfixer » May 26, 2019 15:24

fxm does bring in side topics frequently, but he usually has something on his mind when he does this, and then drags it out into multiple posts. Give him time to finish his thought and see where he goes first before you jump too quick.

Personally, what is the problem?

Scope is scope and we don't need any bonus code to escape it or break it.

Declare your array common shared in main (or include to main) with 'any', redim in functions, re-assign the shared pointer, use that common shared pointer for access for a return value.
I use this with UDTs all the time.

Don't break that.

david
Last edited by speedfixer on May 26, 2019 15:54, edited 1 time in total.
fxm
Posts: 8970
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Wiki improvements

Postby fxm » May 26, 2019 15:28

MrSwiss wrote:people are very well able "to read between the lines", too

If you think so, apply that to yourself as well.
speedfixer
Posts: 327
Joined: Nov 28, 2012 1:27
Location: California

Re: Wiki improvements

Postby speedfixer » May 26, 2019 15:39

re: MrSwiss comments

Some people don't like my posts. Not everyone is trying to be a star or gather points by making a comment that does not contribute. Should I stop?

fxm works hard to provide value. Even if I disagree with him (and he with me) he still is trying to contribute, not just make noise. Some people don't like his style. Should he stop? fxm is fxm.

My methods don't always follow someone's convention. But if I did, I wouldn't be me. I'm wrong sometimes. (Are you ever wrong?)

My 'against convention' has been successful enough for me to retire at 55, over ten years ago. I'm still thinking about buying a summer place in Italy or France.

I'll keep my method over yours, thank you.
Oh - 'between the lines' ??? Listen to yourself.

I don't know fxm. I don't know how successful he may be. But I DID learn a long time ago to be patient, and learn from successful people. His code is successful, even if I may not like his style. So, I learn from him.


YOUR method drives people AWAY from FB. THANK YOU.

david
Last edited by speedfixer on May 26, 2019 15:57, edited 2 times in total.
MrSwiss
Posts: 3081
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Wiki improvements

Postby MrSwiss » May 26, 2019 15:44

fxm wrote:If you think so, apply that to yourself as well.

In order to do so, you'd have to write more, than single liners.
fxm
Posts: 8970
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Wiki improvements

Postby fxm » May 26, 2019 15:57

MrSwiss wrote:
fxm wrote:If you think so, apply that to yourself as well.

In order to do so, you'd have to write more, than single liners.

You misunderstood me. I did not talk about me.
I wanted to say:
Do you always try to read between the lines of user posts before answering?
MrSwiss
Posts: 3081
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Wiki improvements

Postby MrSwiss » May 26, 2019 17:01

fxm wrote:Do you always try to read between the lines of user posts before answering?

Yes, but apparently, I'm not very good at it. That's why I'm sometimes asking,
if my stated assumptions are correct, or for further clarifications.
NOTE: trying and succeeding isn't synonymous!
MrSwiss
Posts: 3081
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Wiki improvements

Postby MrSwiss » May 26, 2019 17:17

Back to business, again:
fxm wrote:In the array descriptor, I do not see a field to discriminate a fix-len array against a var-len array.

No, but there is a workaround:
1) check array bounds (save them, for comparison)
2) Erase(array)
3) check bounds again (compare)
4) if still the same bounds: array is static, otherwise,
if UBound(array) < LBound(array) then: the array is dynamic (uninitialized)
(maybe a dynamic temp. array needed, to keep values)

Proof of concept:

Code: Select all

Dim     Array1(1 To 10) As Integer  ' static
ReDim   Array2(1 To 10) As Integer  ' dynamic

Print "Array1("; Str(LBound(Array1)); " To "; Str(UBound(Array1)); ")"
Print "Array2("; Str(LBound(Array2)); " To "; Str(UBound(Array2)); ")"
Print

Print "erasing now ... done"
Erase Array1, Array2

Print
Print "Array1("; Str(LBound(Array1)); " To "; Str(UBound(Array1)); ")"
Print "Array2("; Str(LBound(Array2)); " To "; Str(UBound(Array2)); ")"

Sleep
RESULT wrote:Array1(1 To 10)
Array2(1 To 10)

erasing now ... done

Array1(1 To 10)
Array2(0 To -1)
fxm
Posts: 8970
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Wiki improvements

Postby fxm » May 27, 2019 5:59

Yes, but the question is to determine from inside a procedure whether the array passed as a parameter is a fix-len array or a var-len array.
When the code refers to the array by its own name, there is no problem because the array type is known implicitly.

Inside a procedure, this type of test on the passed array does not work because, for a static array, a temporary descriptor of array is passed and any changes really only work on the array data (changes on the descriptor values ​​appear operate locally):

Code: Select all

Sub erasing (Array() As Integer)
  Print "  From inside the procedure:"
  Print "    Array("; Str(LBound(Array)); " To "; Str(UBound(Array)); ")"
  Print "    Erasing now ... done"
  Erase Array
  Print "    Array("; Str(LBound(Array)); " To "; Str(UBound(Array)); ")"
End Sub

Dim     Array1(1 To 10) As Integer  ' static
ReDim   Array2(1 To 10) As Integer  ' dynamic

Print "Array1()"
erasing(Array1())
Print "  then, from the Array1() scope:"
Print "    Array1("; Str(LBound(Array1)); " To "; Str(UBound(Array1)); ")"
Print
Print "Array2()"
erasing(Array2())
Print "  then, from the Array2() scope:"
Print "    Array2("; Str(LBound(Array2)); " To "; Str(UBound(Array2)); ")"
Print

Sleep

Code: Select all

Array1()
  From inside the procedure:
    Array(1 To 10)
    Erasing now ... done
    Array(0 To -1)
  then, from the Array1() scope:
    Array1(1 To 10)

Array2()
  From inside the procedure:
    Array(1 To 10)
    Erasing now ... done
    Array(0 To -1)
  then, from the Array2() scope:
    Array2(0 To -1)

Note: In addition, 'Erase' from inside a procedure does not reset the elements of a fix-len array passed as parameter.
fxm
Posts: 8970
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Wiki improvements

Postby fxm » May 27, 2019 7:16

coderJeff,

What exactly does 'Erase' do from inside a procedure when it applies to a fixed-len array passed as parameter?
Does it try to deallocate any thing?
'Erase' applied to a fix-len array passed as parameter is not full efficient, but is it safe code?

In any case, we can check that at least from inside a procedure:
- 'Erase' calls the destructor (if exists) of each element of a fix-len array passed as parameter.
- 'Erase' does not reset the elements of a fix-len array passed by parameter (no object elements re-construction or no numeric elements resetting to 0).
- Does it try to deallocate some memory, as for a var-len array?
I do not see how afterwards, in the main code, when the fix-len array goes out of its scope, a second destruction attempt seems to be well skipped (maybe through the state of the array descriptor passed by reference?).


[edit]
WARNING: 'Erase' used on a fix-len array passed by parameter causes a crash in FBC 64-bit (only seen afterwards).
To the following, use only FBC 32-bit to run the different examples.
fxm
Posts: 8970
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Wiki improvements

Postby fxm » May 27, 2019 13:34

After deeper tests (with FBC 32-bit), I can conclude that:
- 'Erase' (from inside a procedure) seems to not attempt to deallocate some memory (maybe because the array data are not on the heap?)
- Otherwise the code seems to be safe (except for global fix-len arrays, see post below).
- But the only difference (for a user) when 'Erase' is called from inside a procedure (on fix-len array passed as parameter) is that the array elements are not reset (not cleared for numeric elements or not re-constructed for object elements like UDTs).
An information is returned from the procedure in order to skip the normal call of destructor at end of scope, through the array descriptor passed by reference, that 'Erase' resets (as if it were the descriptor of a var-len array).

A small code to check the behavior related to the constructor/destructor calls (three cases: 'Erase' called on an array name, 'Erase not called, and 'Erase' called on an array passed as parameter):

Code: Select all

Type UDT
  Dim AS Integer I
  Declare Constructor ()
  Declare Destructor ()
End Type
Constructor UDT
  Print "constructor ", @This
End Constructor
Destructor UDT
  Print "destructor ", @This
End Destructor

Sub erasing (array() As UDT)
  Erase array
  Print "array erased"
End Sub

For K As Integer = 1 To 3
  Scope
    Dim array(1 To 2) As UDT
    array(1).I = 111
    Print
    If K = 1 Then
      Print "call 'Erase'"
      Erase array
      Print "array erased"
    Elseif K = 2 Then
      Print "array not erased"
    Else
      Print "call Sub 'erasing'"
      erasing(array())
    End If
    Print
    Print Ubound(array), array(1).I
    Print "end of scope"
  End Scope
  Print
  Print "--------------------"
  Print
Next K

Sleep

Code: Select all

constructor   1703568
constructor   1703572

call 'Erase'
destructor    1703572
destructor    1703568
constructor   1703568
constructor   1703572
array erased

 2             0
end of scope
destructor    1703572
destructor    1703568

--------------------

constructor   1703568
constructor   1703572

array not erased

 2             111
end of scope
destructor    1703572
destructor    1703568

--------------------

constructor   1703568
constructor   1703572

call Sub 'erasing'
destructor    1703572
destructor    1703568
array erased

 2             111
end of scope

--------------------

Note: If really 'Erase' (from inside a procedure) does not attempt to deallocate some memory (maybe because the array data are not on the heap), we could replace this skipped deallocation (compared to a var-len array) by a re-construction of the object elements or by a clearing of the numeric elements.
In that case, the object elements (of fix-len arrays) should be destructed at scope end (or program end for global arrays) as the normal behavior when 'Erase' is used on an explicit array name (this would also fix the bug of the post below). Therefore, the trick of resetting the passed descriptor of a fix-len array should be no longer used (more logical to not modify the descriptor of a fix-len array).


Annex 1: Code to demonstrate that 'Erase' presently resets the descriptor of a fix-len array (of UDT) passed as parameter, a trick, but illogical:
(a trick in order that the calling code does not destroy a second time the array elements when program goes out of its scope)

Code: Select all

Type arrayDimensionDescriptor
  Dim As Uinteger nbOfElements  ' number of elements: (highBound-lowBound+1)
  Dim As Integer lowBound       ' lbound
  Dim As Integer highBound      ' ubound
End Type

Type arrayDescriptor
  Dim As Any Ptr nullIndexesAddress  ' pointer to the real or virtual element: @array(0, 0,...)
  Dim As Any Ptr minIndexesAddress   ' pointer to the first real element: @array(lbound1, lbound2,...)
  Dim As Uinteger globalSize         ' "global" size in bytes: (ubound1-lbound1+1)*(ubound2-lbound2+1).....*(size of 1 element)
  Dim As Uinteger elementSize        ' size of one element in bytes
  Dim As Uinteger nbOfDimensions     ' number of dimensions
  Dim As arrayDimensionDescriptor arrayDimensions(1 to 8)  ' max number of dimensions = 8
End Type                                                   '   (numbered from 1 to 8)

private Function arrayDescriptorGetPtrFunction (Byval p As Any Ptr) As Any Ptr
  Return p
End function

#macro arrayDescriptorPtr(array, p)
  Scope
    Dim As Function (() As Typeof((array))) As Any Ptr f
    f = Cast(Function (() As Typeof((array))) As Any Ptr, @arrayDescriptorGetPtrFunction)
    p = f(array())
  End Scope
#endmacro

'------------------------------------------------------------------------------------

Sub printArrayDescriptor (Byval p As Any Ptr)
  Dim As arrayDescriptor Ptr pu = p
  Print "[@array descriptor: "; pu; "]"
  Print "  @array(all_null_indexes)   ="; pu->nullIndexesAddress
  Print "  @array(all_min_indexes)    ="; pu->minIndexesAddress
  Print "  array_total_size_in_bytes  ="; pu->globalSize
  Print "  array_element_size_in_bytes="; pu->elementSize
  Print "  number_of_array_dimensions ="; pu->nbOfDimensions
  For i As Integer = 1 to pu->nbOfDimensions
    Print "  [dimension number:"; i; "]"
    Print "    number_of_elements="; pu->arrayDimensions(i).nbOfElements
    Print "    min_index         ="; pu->arrayDimensions(i).lowBound
    Print "    max_index         ="; pu->arrayDimensions(i).highBound
  Next i
End Sub

'------------------------------------------------------------------------------------

Type UDT
  Dim AS Integer I
  Declare Constructor ()
  Declare Destructor ()
End Type
Constructor UDT
  Print "constructor ", @This
End Constructor
Destructor UDT
  Print "destructor ", @This
End Destructor

Sub erasing (array() As UDT)
  Dim As Any Ptr p
  arrayDescriptorPtr(array, p)
  printArrayDescriptor(p)
  Print
  Print "Erasing the fix-len array:"
  Print
  Erase array
  printArrayDescriptor(p)
  Print
End Sub

Scope
  Dim As UDT array(0 To 1)
  erasing(array())
  Print "Going out the array scope:"
  Print
End Scope

Sleep

Code: Select all

constructor   1703572
constructor   1703576
[@array descriptor: 1703540]
  @array(all_null_indexes)   =1703572
  @array(all_min_indexes)    =1703572
  array_total_size_in_bytes  =8
  array_element_size_in_bytes=4
  number_of_array_dimensions =1
  [dimension number: 1]
    number_of_elements=2
    min_index         = 0
    max_index         = 1

Erasing the fix-len array:

destructor    1703576
destructor    1703572
[@array descriptor: 1703540]
  @array(all_null_indexes)   =0
  @array(all_min_indexes)    =0
  array_total_size_in_bytes  =0
  array_element_size_in_bytes=4
  number_of_array_dimensions =1
  [dimension number: 1]
    number_of_elements=0
    min_index         = 0
    max_index         = 0

Going out the array scope:

Annex 2: Code to demonstrate that if 'Erase' did not reset the descriptor of a fix-len array (of UDT) passed as parameter, but re-constructed the array elements, all would be right when program would go out of its scope (the re-constructed array elements properly destroyed when program goes out of its scope):

Code: Select all

Type arrayDimensionDescriptor
  Dim As Uinteger nbOfElements  ' number of elements: (highBound-lowBound+1)
  Dim As Integer lowBound       ' lbound
  Dim As Integer highBound      ' ubound
End Type

Type arrayDescriptor
  Dim As Any Ptr nullIndexesAddress  ' pointer to the real or virtual element: @array(0, 0,...)
  Dim As Any Ptr minIndexesAddress   ' pointer to the first real element: @array(lbound1, lbound2,...)
  Dim As Uinteger globalSize         ' "global" size in bytes: (ubound1-lbound1+1)*(ubound2-lbound2+1).....*(size of 1 element)
  Dim As Uinteger elementSize        ' size of one element in bytes
  Dim As Uinteger nbOfDimensions     ' number of dimensions
  Dim As arrayDimensionDescriptor arrayDimensions(1 to 8)  ' max number of dimensions = 8
End Type                                                   '   (numbered from 1 to 8)

private Function arrayDescriptorGetPtrFunction (Byval p As Any Ptr) As Any Ptr
  Return p
End function

#macro arrayDescriptorPtr(array, p)
  Scope
    Dim As Function (() As Typeof((array))) As Any Ptr f
    f = Cast(Function (() As Typeof((array))) As Any Ptr, @arrayDescriptorGetPtrFunction)
    p = f(array())
  End Scope
#endmacro

'------------------------------------------------------------------------------------

Sub printArrayDescriptor (Byval p As Any Ptr)
  Dim As arrayDescriptor Ptr pu = p
  Print "[@array descriptor: "; pu; "]"
  Print "  @array(all_null_indexes)   ="; pu->nullIndexesAddress
  Print "  @array(all_min_indexes)    ="; pu->minIndexesAddress
  Print "  array_total_size_in_bytes  ="; pu->globalSize
  Print "  array_element_size_in_bytes="; pu->elementSize
  Print "  number_of_array_dimensions ="; pu->nbOfDimensions
  For i As Integer = 1 to pu->nbOfDimensions
    Print "  [dimension number:"; i; "]"
    Print "    number_of_elements="; pu->arrayDimensions(i).nbOfElements
    Print "    min_index         ="; pu->arrayDimensions(i).lowBound
    Print "    max_index         ="; pu->arrayDimensions(i).highBound
  Next i
End Sub

'------------------------------------------------------------------------------------

Type UDT
  Dim AS Uinteger I
  Declare Constructor ()
  Declare Destructor ()
End Type
Constructor UDT
  Print "constructor ", @This
End Constructor
Destructor UDT
  Print "destructor ", @This
End Destructor

Sub erasing (array() As UDT)
  ' get pointer to descriptor
    Dim As Integer Ptr p
    arrayDescriptorPtr(array, p)
  printArrayDescriptor(p)
  Print array(0).I
  Print
  ' save descriptor
    Dim As Integer I(4 + p[4] * 3)
    For K As Integer = Lbound(I) To Ubound(I)
      I(K) = p[K]
    Next K
  Print "Erasing the fix-len array:"
  Print
  ' bugged erase array
    Erase array
  printArrayDescriptor(p)
  Print Cptr(Uinteger Ptr, I(0))[0]
  Print
  Print "Restoring the descriptor and re-constructing the array elements:"
  Print
  ' restore descriptor
    For K As Integer = Lbound(I) To Ubound(I)
      p[K] = I(K)
    Next K
  printArrayDescriptor(p)
  Print array(0).I
  ' re-construct array elements
    Dim As Any Ptr p0 = New(Cast(Any Ptr, p[1])) Typeof((array))[p[2] \ p[3]]
  Print array(0).I
  Print
End Sub

Scope
  Dim As UDT array(0 To 1)
  array(0).I = 111
  erasing(array())
  Print "Going out the array scope:"
  Print
End Scope

Sleep

Code: Select all

constructor   1703572
constructor   1703576
[@array descriptor: 1703540]
  @array(all_null_indexes)   =1703572
  @array(all_min_indexes)    =1703572
  array_total_size_in_bytes  =8
  array_element_size_in_bytes=4
  number_of_array_dimensions =1
  [dimension number: 1]
    number_of_elements=2
    min_index         = 0
    max_index         = 1
111

Erasing the fix-len array:

destructor    1703576
destructor    1703572
[@array descriptor: 1703540]
  @array(all_null_indexes)   =0
  @array(all_min_indexes)    =0
  array_total_size_in_bytes  =0
  array_element_size_in_bytes=4
  number_of_array_dimensions =1
  [dimension number: 1]
    number_of_elements=0
    min_index         = 0
    max_index         = 0
111

Restoring the descriptor and re-constructing the array elements:

[@array descriptor: 1703540]
  @array(all_null_indexes)   =1703572
  @array(all_min_indexes)    =1703572
  array_total_size_in_bytes  =8
  array_element_size_in_bytes=4
  number_of_array_dimensions =1
  [dimension number: 1]
    number_of_elements=2
    min_index         = 0
    max_index         = 1
111
constructor   1703572
constructor   1703576
0

Going out the array scope:

destructor    1703576
destructor    1703572


[edit]
WARNING: 'Erase' used on a fix-len array passed by parameter causes a crash in FBC 64-bit (only seen afterwards).
Use only FBC 32-bit to run the different examples.
fxm
Posts: 8970
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Wiki improvements

Postby fxm » May 27, 2019 15:15

Bug when 'Erase' is used on global fix-len arrays passed as parameters (see with FBC 32-bit)

For static fix-len arrays or shared fix-len arrays passed as parameters, 'Erase' in the procedure call the destructor for each object element, but at program end, the destructor is called a second time on the same object elements (maybe just an oversight compared to the behavior with non-global fix-len arrays where that works).

Example with Shared:

Code: Select all

Type UDT
  Dim AS Integer I
  Declare Constructor ()
  Declare Destructor ()
End Type
Constructor UDT
  Print "constructor ", @This
End Constructor
Destructor UDT
  Print "destructor ", @This
End Destructor

Sub erasing (array() As UDT)
  Erase array
  Print "array erased"
End Sub

Dim Shared array(1 To 2) As UDT
Print
Print "call Sub 'erasing'"
erasing(array())
Print
Output (when executing the above code from a console window, for example):

Code: Select all

constructor   4239392
constructor   4239396

call Sub 'erasing'
destructor    4239396
destructor    4239392
array erased

destructor    4239396
destructor    4239392

As fix proposal, see the note in post above.


[edit]
WARNING: 'Erase' used on a fix-len array passed by parameter causes a crash in FBC 64-bit (only seen afterwards).
Use only FBC 32-bit to run the different examples.

Return to “Documentation”

Who is online

Users browsing this forum: No registered users and 1 guest