Types containing dynamic arrays

General discussion for topics related to the FreeBASIC project or its community.
AGS
Posts: 1284
Joined: Sep 25, 2007 0:26
Location: the Netherlands

Types containing dynamic arrays

Post by AGS »

Currently the FB manual contains this passage:
ReDim cannot be used on arrays contained in UDTs (user-defined Types), because currently only fixed-size arrays are supported in UDTs
As a result of the limitation on the use of redim I have to use pointers where I would like to use dynamic arrays instead.

So... is there ever going to be support for dynamic arrays in types? And what is the cause for the limitation on the use of redim?
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Post by jevans4949 »

The size of a UDT is supposed to be fixed.

There is a workaround for non-fixed strings at present, in that what is actually stored in the UDT is the descriptor for the string (12 bytes), whilst the content is stored elsewhere.

To be able to REDIM an array in a UDT you would have to do the same thing, i.e., store an arrray descriptor in the UDT, and the data elsewhere. This would break a lot of existing code.

One way round it would be to introduce a new fundamental data type (ArrayDescriptor?) which would work in the same way as the string descriptor.

This could of course be useful in other situations, e.g., allowiing programmers to fake an array descriptor for variable data within a record, and to pass a pointer to an array descriptor rather than the full descriptor.

PL/1 has a some capability in this area, but only to dynamically define the size of the last variable in a structure (string or array), and you have to have a variable earlier in the structure to contain the dimension. OTOH, a PL/1 structure is not strictly analogous to a BASIC UDT.
MOD
Posts: 555
Joined: Jun 11, 2009 20:15

Post by MOD »

I've managed dynamic arrays in UDTs by using properties. It doesn't need any pointer arithmetic for usage at all.


As you can see here.
creek23
Posts: 261
Joined: Sep 09, 2007 1:57
Location: Philippines
Contact:

Post by creek23 »

Does that mean that each new type with the need of a dynamic element will require a redim function to be added in the code as well?
rolliebollocks
Posts: 2655
Joined: Aug 28, 2008 10:54
Location: new york

Post by rolliebollocks »

MOD wrote:I've managed dynamic arrays in UDTs by using properties. It doesn't need any pointer arithmetic for usage at all.
That can't possibly be true. In fact, I know it's not true. Properties have no capacity to redim the size of an array. I've tried it, I've failed.

Code: Select all

type something
    
    dim as integer array(0 to 20)
    
    Declare Property u_bound () as integer
    declare property l_bound () as integer
    declare Property u_bound ( new_u as integer )
    declare Property l_bound ( new_l as integer )

end type

Property something.u_bound () as integer
    property = ubound(array)
end property

Property something.l_bound () as integer
    property = lbound(array)
end Property

Property something.u_bound ( new_u as integer )
    redim array( l_bound to new_u )
end Property

Property something.l_bound ( new_l as integer )
    redim array ( new_l to u_bound )
end Property

dim as something fudge

? fudge.u_bound
fudge.u_bound = 40
? fudge.u_bound
sleep
If it is true, then you're the only person who knows about it.
MOD
Posts: 555
Joined: Jun 11, 2009 20:15

Post by MOD »

Just look at the linked site and try it. In fact it is not the same, it need lot more declarations and code, but it is almost the same.

In this case, ReDim is a method of the UDT. If you want to use the same ReDim method for all datatypes, try using my Variant.
Last edited by MOD on Jul 02, 2010 17:22, edited 1 time in total.
rolliebollocks
Posts: 2655
Joined: Aug 28, 2008 10:54
Location: new york

Post by rolliebollocks »

@Mod

That method is on the Wiki. That's not what AGS wants. We all know about the pointer index method.
MOD
Posts: 555
Joined: Jun 11, 2009 20:15

Post by MOD »

AGS wants it included in the compiler.

What i tried to say is, that there is a method to use the pointer method (from wiki) [almost] like a normal array by wrapping it in properties. It just simplifies the usage and doesn't discover hidden features in fbc.
rolliebollocks
Posts: 2655
Joined: Aug 28, 2008 10:54
Location: new york

Post by rolliebollocks »

@MOD

The thread safe way to do what your doing is resize the array and then recopy.

http://www.freebasic.net/forum/viewtopic.php?p=138313

(Vince, you rule!)
MOD
Posts: 555
Joined: Jun 11, 2009 20:15

Post by MOD »

AFAIK Allocate, CAllocate, ReAllocate and DeAllocate are not threadsafe! You will need MutexLock and -UnLock in threads.
rolliebollocks
Posts: 2655
Joined: Aug 28, 2008 10:54
Location: new york

Post by rolliebollocks »

I don't use threads, but copying a pointer is thread safe and allocating the data into a new buffer should be a thread safe method, while attempting to reallocate data on the stack... Not safe.

Am I way off base with this? I don't use threads so I don't know. If I am I apologize and bow to your knowledge of threads but for the love of god, if you tell a forum of people you can dynamically use arrays in UDT's via properties, it's going to confuse people into thinking that you've discovered some new method when in fact, it's the same method AGS specified rather not using...

The difference between what you're doing and what the wiki does is cosmetic.

Try duplicating this...

Code: Select all

dim as integer arr(20 to 40)

? lbound(arr)
sleep
MOD
Posts: 555
Joined: Jun 11, 2009 20:15

Post by MOD »

You're right, it is cosmetic but I've never said, that it's perfect.
I can almost duplicate your example:

Code: Select all

Type  testtyp
    Public:
    Declare Constructor
    Declare Constructor(c As Integer)

    Declare Destructor

    Declare Property array(i As Integer) As Integer
    Declare Property array(i As Integer, a As Integer)

    Declare Function LBound() As Integer
    Declare Function UBound() As Integer

    Declare Function Pointr() As UInteger Ptr
    Declare Sub ReDim(x As Integer)
    Declare Sub ReDim(lb As Integer, ub As Integer)

    Private:
    As Integer size
    As Integer Ptr arr
    As Integer lbo, ubo
End Type

Constructor testtyp

End Constructor
Constructor testtyp(c As Integer)
    If c >= 0 Then
        arr = Callocate(c, SizeOf(Integer))
        size = c + 1
    EndIf
End Constructor

Destructor testtyp
    size = 0
    DeAllocate(arr)
End Destructor

Property testtyp.array(i As Integer) As Integer
    If i >= 0 And i < size Then Return arr[i]
End Property
Property testtyp.array(i As Integer, a As Integer)
    If i >= 0 And i < size Then arr[i] = a
End Property

Function testtyp.LBound() As Integer
    If arr <> 0 Then
        Return lbo
    Else
        Return -1
    EndIf
End Function
Function testtyp.UBound() As Integer
    If arr <> 0 Then
        Return ubo
    Else
        Return -1
    EndIf
End Function

Function testtyp.Pointr() As UInteger Ptr
    Return arr
End Function

Sub testtyp.ReDim(x As Integer)
    If x >= 0 Then
        Dim As Integer Ptr temp
        temp = ReAllocate(arr, x * SizeOf(Integer))
        arr = temp
        DeAllocate(temp)
        size = x + 1
        lbo = 0
        ubo = x
    EndIf
End Sub
Sub testtyp.ReDim(lb As Integer, ub As Integer)
    If lb >= 0 And ub > lb Then
        Dim As Integer Ptr temp
        temp = ReAllocate(arr, (ub - lb) * SizeOf(Integer))
        arr = temp
        DeAllocate(temp)
        size = (ub - lb) + 1
        lbo = lb
        ubo = ub
    EndIf
End Sub

'############################################################################################

Dim As testtyp foo

foo.ReDim(20,40)
? foo.LBound, foo.UBound

Sleep
And still not perfect...
AGS
Posts: 1284
Joined: Sep 25, 2007 0:26
Location: the Netherlands

Post by AGS »

jevans4949 wrote:The size of a UDT is supposed to be fixed.

There is a workaround for non-fixed strings at present, in that what is actually stored in the UDT is the descriptor for the string (12 bytes), whilst the content is stored elsewhere.

To be able to REDIM an array in a UDT you would have to do the same thing, i.e., store an array descriptor in the UDT, and the data elsewhere. This would break a lot of existing code.

One way round it would be to introduce a new fundamental data type (ArrayDescriptor?) which would work in the same way as the string descriptor.

This could of course be useful in other situations, e.g., allowiing programmers to fake an array descriptor for variable data within a record, and to pass a pointer to an array descriptor rather than the full descriptor.

PL/1 has a some capability in this area, but only to dynamically define the size of the last variable in a structure (string or array), and you have to have a variable earlier in the structure to contain the dimension. OTOH, a PL/1 structure is not strictly analogous to a BASIC UDT.
Thanks for the thorough explanation, jevans. You are (basically) saying that the chances of having support for dynamic arrays in UDTs built into the compiler are zero to none?

And it's great to read that there are workarounds for the dynamic array 'problem'. It's a bit umständlich but it'll do.
rdc
Posts: 1741
Joined: May 27, 2005 17:22
Location: Texas, USA
Contact:

Post by rdc »

The main purpose of having a Type-Def structure in the original Basic languages (and in Pascal as well) was to provide a record structure for files. Having a fixed length record structure made it possible to know the size of a record in a file so that you can access the file randomly.

That is not to say you can't extend the basic functionality of the type-def, for example, with pointers like we have now (if you are not going to use them for files), but it still needs to maintain the fixed length structure for file work.
segin
Posts: 126
Joined: Dec 27, 2005 5:22
Contact:

Post by segin »

MOD wrote:I've managed dynamic arrays in UDTs by using properties. It doesn't need any pointer arithmetic for usage at all.


As you can see here.
That is not exactly this, and therefore doesn't count:

Code: Select all

Type Foo
    m_array() As Integer
End Type
And have that there do exactly what a dynamic array outside a struct would do. [/code]
Post Reply