On 11/26/2010 5:34, Ralph Versteegen wrote:
QB/FB arrays are the worst designed feature in any programming
language I know of (except for *possibly* some of the stuff in MUMPS
http://thedailywtf.com/Articles/A_Case_of_the_MUMPS.aspx)
(A quick rant:
-not 1st class: you can't return them or even place them in types!
-uninitialised dynamic arrays are indistinguishable and will crash
your program. You must initialise them.
-to figure out whether an array is static or dynamic you have to check
the dialect, the OPTION statements in effect, and whether the index in
the DIM statement is a variable or a constant
-unlike the rest of the language, arrays aren't properly statically
typed: the compiler will let you REDIM a static array and crash your
program
-zero-length arrays not supported
-almost zero support for arrays in the standard library: just REDIM,
LBOUND, UBOUND, ERASE. You can't even copy an array, or get a pointer
to the array descriptor.
)
A couple days ago I had finally had enough, and started on a library
of array utility functions written in C, effectively extending libfb
(addressing just the last 2 complaints above). The idea is they act on
1D arrays starting at -1, with the -1 element ignored so we can have
zero-length arrays. Here are a few prototypes (you use a macro to
declare overloaded versions for each type T you want to support):
declare sub array_copy overload (array() as T, source() as T)
'Append an element or an array
declare sub array_append overload (array() as T, value as T)
declare sub array_append overload (array() as T, appendlist() as T)
'Removes index n from array
declare sub array_delete overload (array() as T, byval n as integer)
'Insert a value/array at an index. Negative indices count from end
(-1 appends)
declare sub array_insert overload (array() as T, byval insertbefore
as integer, value as T)
declare sub array_insert overload (array() as T, byval insertbefore
as integer, insertlist() as T)
declare sub array_sort overload (array() as T)
A couple nights into implementing them (expected to be done by now,
but the libfb array code is horribly over-complex, eg. there are about
8 different implementations of REDIM) I suddenly realised: if FB
arrays are so horrible, why am I using them at all? It would be FAR
easier to create a new array structure and write an extensive library
for it in C. The code would be much simple, faster, there'd be no
worry about keeping up with changes to libfb, and I can fix more of
the problems with FB arrays. The disadvantages would be having to
manually allocate and free them, and no bounds checking when compiled
with -exx. However when we finally switch to -lang fb we'll get those
back.
I would implement these arrays like this: array objects would just be
pointers of the desired type, which can be indexed like a normal
pointer. The array descriptor (containing length and other stuff)
would be stored before the 0th element. These pointers can of course
be embedded in UDTs or returned from functions. Because code should be
self documenting, to avoid confusion with normal pointers I'd do this:
#define array ptr
Example code:
FUNCTION generate_test_array() as string array
DIM arr as string array
array_new arr ' allocate zero-length array
array_append arr, "test"
array_append arr, array_of("foo", "bar") ' I think I'll manage this
array_sort arr
RETURN arr
END FUNCTION
DIM arr as string array
arr = generate_test_array ' Can only do this as arr is a NULL pointer
array_set arr, generate_test_array ' Safe way to assign an array
print arr[length(arr) - 1]
array_free arr
So the question to the other developers is: would you rather have a
library for FB arrays, or use these new arrays? I am definitely in
favour of the new arrays, and would start using them and, where
beneficial, converting code I'm working on to use them as soon as
possible (tomorrow?).
I'm curious about one thing. Would these new arrays be dynamic or
statically sized? I assume the former. In which case, you do you handle
the realloc()/Reallocate() semantics?
Specifically, when you use realloc(), you have to use the return value
as the new pointer (if it's not null), since the memory block may have
moved to accommodate the new size.
However, the syntax you're proposing does not allow for the
re-assignment of the variable containing the array. (Unless you intend
for some preprocessor trickery, in which case foo on you.)
The best way to replace FB's arrays would be to create an array object
which overloads the [] operator, and keeps the memory buffer internal.
Ideally, it supports templates for maximum efficiency.
Class Array<T>
length as uinteger
data as T ptr
Public Constructor Array(size as uinteger)
length = size
data = new T[size]
End Constructor
Public Operator[](index as uinteger) as T ref
if index < 0 or index >= length throw new ArgumentException()
return &data[index]
End Operator
public sub Resize(newsize as uinteger)
...
end sub
End Class
However, since I don't think this possible in FB (and, especially not in
-lang deprecated), you would have to settle for a C-style api:
TYPE IntArrayUDT
length as uinteger
data as integer ptr
End Type
TYPE IntArray as IntArrayUDT ptr
Function NewIntArray(size as uinteger) as IntArray
Sub DeleteArray(a as IntArray)
Function ResizeArray(a as IntArray, newsize as IntArray) as integer 'boolean
Function GetArray(a as IntArray, index as uinteger) as integer
Sub SetArray(a as IntArray, index as uinteger, value as integer)
'etc.
Also, I would be very tempted to use some evil preprocessor trickery to
simulate templates, since this is very silly.
Or, the final option would just to use regular pointers as arrays. It's
worked for almost 40 years so far :D
_______________________________________________
Ohrrpgce mailing list
[email protected]
http://lists.motherhamster.org/listinfo.cgi/ohrrpgce-motherhamster.org