Let's examplify the REDIM exclusion cases

Forum for discussion about the documentation project.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Let's examplify the REDIM exclusion cases

Post by Tourist Trap »

Hello,

could we illustrate a little this note that is found at the REDIM doc page? The page is well documented but the note (below) still holds intrinsic difficulty.
For instance, can I deduce that if I make a multidimension array and just resize the last dimension then I can safely use PRESERVE? (redim preserve array(a)(b)(c) with modifying c only)
(redim documentation page)
NOTES:

ReDim Preserve may not work as expected in all cases:

Preserve's current behavior is to keep the original data contiguous in memory, and only expand or truncate the size of the memory.
Its behavior (with a single dimension) is well-defined only when the upper bound is changed. If the lower bound is changed, the current result is that the data is in effect shifted to start at the new lower bound.
With multiple dimensions, only the upper bound of only the first dimension may be safely increased. If the first dimension is reduced, the existing mappable data may be lost. If lower-order dimensions are resized at all, the effects can be hard to predict.

ReDim cannot be used on fixed-size arrays - i.e. arrays with constant bounds made with Dim. This includes the fixed-size arrays contained in UDTs (user-defined Types). This also includes fixed-length arrays passed as parameters in a function. FreeBASIC cannot prevent you trying this at compile-time, but the results at run-time will be undefined.

Using ReDim within a member procedure with an array that contains an instance of the object class is undefined
, and will [hopefully] result in horrible crashes.

For use of ReDim (resizing) with a complex expression, (especially if the array expression itself contains parentheses), the array expression must be enclosed in parentheses in order to solve the parsing ambiguity.
Not an urgent task anyway. Thanks.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Let's examplify the REDIM exclusion cases

Post by Tourist Trap »

Other question around REDIM that one may face one day or an other.
Let's consider this example:

Code: Select all

redim as const integer      arrayOfInteger(0)


sub Test( IntArray() as const integer )
    ? uBound(IntArray) - lBound(IntArray)
end sub


Test(arrayOfInteger())
? arrayOfInteger(0)
redim arrayOfInteger(1)


getKey()

Code: Select all

'OUTPUT
(1) error 236: Expected initializer in 'dim as const integer      arrayOfInteger(0)'
(11) error 274: Dynamic arrays can't be const in 'redim arrayOfInteger(1)'
The question is why can not we write "dim as const integer arrayOfInteger(0)" without an initializer (I guess = {123}), while the subroutine doesn't require any initializer for the same purpose.
And we can certainly not write:

Code: Select all

dim shared as integer      arrayOfInteger(0)

sub Test( IntArray() as const integer = arrayOfInteger)
    ? uBound(IntArray) - lBound(IntArray)
end sub
For comparison, the standard behaviour seems to be this one:

Code: Select all

dim as const integer      arrayOfInteger(0) = {0}

sub Test( IntArray() as const integer)
    ? uBound(IntArray) - lBound(IntArray)
end sub


Test( arrayOfInteger() )

getKey()
But the small variation below is rejected:

Code: Select all

dim as const integer      arrayOfInteger(0) = {0}

sub Test( IntArray() as const integer={1} )
    ? uBound(IntArray) - lBound(IntArray)
end sub


Test( arrayOfInteger() )

getKey()
This also is illegal at the present day:

Code: Select all

dim as const integer      arrayOfInteger(0) = {0}

sub Test( IntArray() as const integer=arrayOfInteger )
    ? uBound(IntArray) - lBound(IntArray)
end sub

Test( arrayOfInteger() )

getKey()
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Let's examplify the REDIM exclusion cases

Post by Tourist Trap »

I take profit of this topic to throw one other of my concern. Why can we not do:

Code: Select all

type UDTEXAMPLE
    as integer      _array2dim(any)(any)
end type
'error 3: Expected End-of-Line, found '(' in 'as integer      _array2dim(any)(any)'
While we perfectly can write:

Code: Select all

type UDTEXAMPLE
    as integer      _array1dim(any)
end type
'OK
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Let's examplify the REDIM exclusion cases

Post by fxm »

Tourist Trap wrote:For instance, can I deduce that if I make a multidimension array and just resize the last dimension then I can safely use PRESERVE? (redim preserve array(a)(b)(c) with modifying c only)
- The good syntax is : redim preserve array(a, b, c)

- Multidimensional arrays are stored in this definite order: values differing only in the last index are contiguous (row-major order).
So when using Redim Preserve, only the upper bound of only the first dimension may be safely increased ('a' in the above example).
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Let's examplify the REDIM exclusion cases

Post by fxm »

Any declaration of constant variable must have an initializer, including array.
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Let's examplify the REDIM exclusion cases

Post by fxm »

Code: Select all

type UDTEXAMPLE
    as integer      _array2dim(any, any)
end type
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Let's examplify the REDIM exclusion cases

Post by Tourist Trap »

fxm wrote:So when using Redim Preserve, only the upper bound of only the first dimension may be safely increased ('a' in the above example).
Thanks, for me a was the lower bound! Thanks also for the correction about the syntax (a,b,c) and not (a)(b)(c).
fxm wrote: Any declaration of constant variable must have an initializer, including array.
Why then there is not initializer required at the procedure parameter definition place?

Code: Select all

sub Test( Array() as const integer )
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Let's examplify the REDIM exclusion cases

Post by fxm »

Excuse me:
Any declaration definition of constant variable must have an initializer, including array.

In a parameter declaration for a procedure (that is not a definition which allocates memory), the "=" symbol is not an initializer but only allows to define a parameter value per default when the caller does not provide corresponding argument.
For a parameter declared as constant, this per default value usage would obviously be a contradiction.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Let's examplify the REDIM exclusion cases

Post by Tourist Trap »

fxm wrote:Excuse me:
Any declaration definition of constant variable must have an initializer, including array.

In a parameter declaration for a procedure (that is not a definition which allocates memory), the "=" symbol is not an initializer but only allows to define a parameter value per default when the caller does not provide corresponding argument.
Ok thank you for the addition, so for instance in the case of a UDT there is no constructor call? Just the LET operator?
fxm wrote: For a parameter declared as constant, this per default value usage would obviously be a contradiction.
Yes, this would probably be have a very restrictive usage.

Just to come back to the note of the documentation, have you an example in mind for this?
Using ReDim within a member procedure with an array that contains an instance of the object class is undefined, and will [hopefully] result in horrible crashes.
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Let's examplify the REDIM exclusion cases

Post by fxm »

Tourist Trap wrote:Just to come back to the note of the documentation, have you an example in mind for this?
Using ReDim within a member procedure with an array that contains an instance of the object class is undefined, and will [hopefully] result in horrible crashes.
If after the REDIM, the array data are shifted in memory, the instance address is changed, but the THIS reference to the instance (implicitly passed at procedure call) always refers to the old address in memory (now deallocated or reallocated for other things).
So the THIS reference may become incoherent, similarly to a dangling pointer.

Example:

Code: Select all

Type UDT
  Dim As Integer I = 123
  Declare Sub test ()
End Type

Redim Shared As UDT array (0)

Sub UDT.test ()
  Print "@array(0).I= ", @array(0).I, "array(0).I=", array(0).I
  Print "@This.I= ", @This.I, "This.I=", This.I
  Print
  Redim array(1023)
  Print "@array(0).I= ", @array(0).I, "array(0).I=", array(0).I
  Print "@This.I= ", @This.I, "This.I=", This.I
End Sub

array(0).test()

Sleep

Code: Select all

@array(0).I=  5183592       array(0).I=    123
@This.I=      5183592       This.I=        123

@array(0).I=  5189464       array(0).I=    123
@This.I=      5183592       This.I=        5193568
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Let's examplify the REDIM exclusion cases

Post by fxm »

Documentation updated:
KeyPgRedim → fxm [Rewording of note#3]
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Let's examplify the REDIM exclusion cases

Post by fxm »

Tourist Trap wrote:
fxm wrote:Excuse me:
Any declaration definition of constant variable must have an initializer, including array.

In a parameter declaration for a procedure (that is not a definition which allocates memory), the "=" symbol is not an initializer but only allows to define a parameter value per default when the caller does not provide corresponding argument.
Ok thank you for the addition, so for instance in the case of a UDT there is no constructor call? Just the LET operator?
Could you precise your question?
(does the "for instance" term in your question corresponds to "for example" or "for object instance")
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Let's examplify the REDIM exclusion cases

Post by Tourist Trap »

fxm wrote:Documentation updated:
KeyPgRedim → fxm [Rewording of note#3]
Thank you. Is there a remark about the difference of syntax for pointers P[a][c] and arrays A(a,b,c). At least do you know if there is a reason for this difference? Maybe it's an arbitrary choice anyway.
fxm wrote:
Tourist Trap wrote:
fxm wrote:Excuse me:
Any declaration definition of constant variable must have an initializer, including array.

In a parameter declaration for a procedure (that is not a definition which allocates memory), the "=" symbol is not an initializer but only allows to define a parameter value per default when the caller does not provide corresponding argument.

Ok thank you for the addition, so for instance in the case of a UDT there is no constructor call? Just the LET operator?

Could you precise your question?
(does the "for instance" term in your question corresponds to "for example" or "for object instance")

It's "for example", because it's not about arrays, but with UDT it's easier to understand when DIM is called (construction) or LET (assignement operator).
By the way an array has no possible overload for its assignement operator. Maybe it could be useful, at least until array will have some featured assignement.
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Let's examplify the REDIM exclusion cases

Post by fxm »

It is preferable to differentiate the operators:
- Operator () (Array Index)
- Operator [] (Pointer index)

Already, the Operator [] (String Index) might deserve a specific symbol.
Do not add another confusion!
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Let's examplify the REDIM exclusion cases

Post by Tourist Trap »

There seems to be 4 types of brackets in FB:
  • pointer index brackets [][]...[],
  • string index brackets [],
  • array index brackets (,,..,),
  • procedure argument brackets(,,..),
  • arithmetic_expression_prioritizer brackets (...)
  • array content brackets {,,..}
    and maybe also
  • string content brackets "..."
  • comment brackets /*...*/
Maybe even more?

Temporary types have also their brackets: <, , .., >
Post Reply