[comp.sys.mac.programmer] Variable length arrays in Pascal--can it be done?

vrm@blackwater.cerc.wvu.wvnet.edu (Vasile R. Montan) (04/03/91)

I want to have variable length arrays in Pascal.  Pascal, however,
does not want me to have variable length arrays in it.  I think I've
figured out a way to do this.  This solution is probably glaringly
obvious to more experienced programmers, but I want to run it
past you to see if there's any reason why it shouldn't work.

Suppose I define a type in Pascal which is an arbitrarily large
array: say, one with 10000 elements in it, or some number larger than
I will ever need.  Suppose I then define a pointer to point to
this type, and a handle to point to the pointer.  Let's say I want
to start out with seven elements in the array, so I use NewHandle
and allocate just enough memory to hold those seven elements.  I
store this number seven in a variable to keep track of how big
the array is.

Now, as long as I am careful not to refer to any elements beyond the
end of the memory block, I should not have any problems, right?
And if I want to resize the array, I can use SetHandleSize,
making sure to keep track of how many elements are now in the array,
right?  Is there any reason why this shouldn't work?

--Kurisuto
un020070@vaxa.wvnet.edu

russotto@eng.umd.edu (Matthew T. Russotto) (04/03/91)

In article <1521@babcock.cerc.wvu.wvnet.edu> un020070@vaxa.wvnet.edu writes:
>I want to have variable length arrays in Pascal.  Pascal, however,
>does not want me to have variable length arrays in it.  I think I've
>figured out a way to do this.  This solution is probably glaringly
>obvious to more experienced programmers, but I want to run it
>past you to see if there's any reason why it shouldn't work.
>
>Suppose I define a type in Pascal which is an arbitrarily large
>array: say, one with 10000 elements in it, or some number larger than
>I will ever need.  Suppose I then define a pointer to point to
>this type, and a handle to point to the pointer.  Let's say I want
>to start out with seven elements in the array, so I use NewHandle
>and allocate just enough memory to hold those seven elements.  I
>store this number seven in a variable to keep track of how big
>the array is.
>
>Now, as long as I am careful not to refer to any elements beyond the
>end of the memory block, I should not have any problems, right?
>And if I want to resize the array, I can use SetHandleSize,
>making sure to keep track of how many elements are now in the array,
>right?  Is there any reason why this shouldn't work?

I believe this is similiar to the way Apple does it for CTabHandles and other
variable-length arrays.  They declare theirs to be
TYPE
	CSpecArray: Array [0..0] of ColorSpec;
and turn off range checking so the references succeed.  If you want range
checking effective for other arrays, your method should work.
--
Matthew T. Russotto	russotto@eng.umd.edu	russotto@wam.umd.edu
     .sig under construction, like the rest of this campus.

sundinKC@dna.lth.se (Anders Sundin) (04/03/91)

Kurisuto writes:

> I want to have variable length arrays in Pascal.  Pascal, however,
> does not want me to have variable length arrays in it.  I think I've
> figured out a way to do this.  This solution is probably glaringly
> obvious to more experienced programmers, but I want to run it
> past you to see if there's any reason why it shouldn't work.
> 
> Suppose I define a type in Pascal which is an arbitrarily large
> array: say, one with 10000 elements in it, or some number larger than
> I will ever need.  Suppose I then define a pointer to point to
> this type, and a handle to point to the pointer.  Let's say I want
> to start out with seven elements in the array, so I use NewHandle
> and allocate just enough memory to hold those seven elements.  I
> store this number seven in a variable to keep track of how big
> the array is.
> 
> Now, as long as I am careful not to refer to any elements beyond the
> end of the memory block, I should not have any problems, right?
> And if I want to resize the array, I can use SetHandleSize,
> making sure to keep track of how many elements are now in the array,
> right?  Is there any reason why this shouldn't work?

Here is how I do dynamic memory allocation in Pascal. 

  data  =
    record
      x :  Real;
      y :  Real;
      z :  Real;
    end;

  arrHandle  = ^arrPtr;
  arrPtr     = ^arr;
  arr        =  array [1..MaxInt] of data;

  objHandle  = ^objPtr;
  objPtr     = ^obj;
  obj =
    record
      nData   : Integer;
      nAlloc  : Integer;
      dataH   : arrHandle;
      nextObj : objHandle;
    end;

function AllocObject(n: LongInt): objHandle;
var
  theObj  : objHandle;
  
begin
  theObj := objHandle(NewHandle(SizeOf(obj)));
  if theObj <> nil then
  begin
    theObj^^.dataH := arrHandle(NewHandle(n * SizeOf(data)));
    if theObj^^.dataH = nil then
    begin
      DisposHandle( Handle(theObj));
      theObj := nil;
    end
    else
    begin
      theObj^^.nData := 0;
      theObj^^.nAlloc := n;
		theObj^^.nextObj := nil;
    end;
  end;
  AllocObject := theObj;
end;

function ReallocObject(theObj: objHandle; n: LongInt): Boolean;
begin
  SetHandleSize(Handle(theObj^^.dataH), n * SizeOf(data));
  if MemError = noErr then
  begin
    theObj^^.nAlloc := n;
    if theObj^^.nData > n then
      theObj^^.nData := n;
    ReallocObject := true;
  end
  else
    ReallocObject := false;
end;

-- 
 Anders Sundin                       e-mail: sundinKC@dna.lth.se
 Organic Chemistry 2,                        ok2aps@seldc52.bitnet
 P.O. Box 124                        phone:  +46 46 108214
 S-22100 Lund, Sweden                fax:    +46 46 108209

jmatthews@desire.wright.edu (04/05/91)

In article <1521@babcock.cerc.wvu.wvnet.edu>, vrm@blackwater.cerc.wvu.wvnet.edu (Vasile R. Montan) writes:
> I want to have variable length arrays in Pascal.  Pascal, however,
> does not want me to have variable length arrays in it.  I think I've
> figured out a way to do this.
> ...
> Suppose I define a type in Pascal which is an arbitrarily large
> array: say, one with 10000 elements in it, or some number larger than
> I will ever need.  Suppose I then define a pointer to point to
> this type, and a handle to point to the pointer.  Let's say I want
> to start out with seven elements in the array, so I use NewHandle
> and allocate just enough memory to hold those seven elements.  I
> store this number seven in a variable to keep track of how big
> the array is.
> 
> Now, as long as I am careful not to refer to any elements beyond the
> end of the memory block, I should not have any problems, right?
> And if I want to resize the array, I can use SetHandleSize,
> making sure to keep track of how many elements are now in the array,
> right?  Is there any reason why this shouldn't work?
> 
> --Kurisuto
> un020070@vaxa.wvnet.edu

Your technique is sound. I think that's how TextEdit's lineStarts array and
the List Manager's cellArray work. Notice that only the lower array bound
matters: it determines whether the array starts with element 0 or 1. The
upper bound is immaterial since you'll never create an instance variable
of this type, only a pointer to it.

Moreover, you can keep the count with the array
	Type MyArray = record
			count:Integer;
			elements: array[1..1] of MyArrayElemnt
			end;

Finally, I recently "discovered" the ToolBox Utility PtrAndHand. It's great
in this context since it does the GetHandleSize, SetHandleSize and
BlockMove stuff you'ld have to do yourself. You can always get a Ptr to
the source data with the @ operator and the destination handle can be unlocked
(PtrAndHand does the right thing internally, I think:-).

Hope this helps, John

o----------------------------------------------------------------------------o
| John B. Matthews, jmatthews@desire.wright.edu, am103@cleveland.freenet.edu |
| "Say...what's a mountain goat doing way up here in a cloud bank?" - Larson |
o----------------------------------------------------------------------------o

phils@chaos.cs.brandeis.edu (Phil Shapiro) (04/12/91)

In article <1991Apr4.124257.3095@desire.wright.edu> jmatthews@desire.wright.edu writes:
   In article <1521@babcock.cerc.wvu.wvnet.edu>, vrm@blackwater.cerc.wvu.wvnet.edu (Vasile R. Montan) writes:
   > I want to have variable length arrays in Pascal.  Pascal, however,
   > does not want me to have variable length arrays in it.  I think I've
   > figured out a way to do this.
   > ...
   > Suppose I define a type in Pascal which is an arbitrarily large
   > array: say, one with 10000 elements in it, or some number larger than
   > I will ever need.  Suppose I then define a pointer to point to
   > this type, and a handle to point to the pointer.  Let's say I want
   > to start out with seven elements in the array, so I use NewHandle
   > and allocate just enough memory to hold those seven elements.  I
   > store this number seven in a variable to keep track of how big
   > the array is.

   Your technique is sound. I think that's how TextEdit's lineStarts array and
   the List Manager's cellArray work. Notice that only the lower array bound
   matters: it determines whether the array starts with element 0 or 1. The
   upper bound is immaterial since you'll never create an instance variable
   of this type, only a pointer to it.

   Moreover, you can keep the count with the array
       Type MyArray = record
          count:Integer;
          elements: array[1..1] of MyArrayElemnt
       end;

I don't know about MPW Pascal, but THINK Pascal make some assumptions
about how an array is indexed depending on its upper bound (really,
the range over which it is bound).  If you want to use the
SetHandleSize method to expand/shrink an array, make sure that you
dimension your array as the largest possible array that you're
planning to resize it to.

If you don't use this method, your programs will surely crash.

	-phil

mitch@Apple.COM (Mitchell Adler) (04/17/91)

In article <1521@babcock.cerc.wvu.wvnet.edu> un020070@vaxa.wvnet.edu writes:
>I want to have variable length arrays in Pascal.
 [Reason for having variable length arrays deleted]

>Suppose I define a type in Pascal which is an arbitrarily large
>array: say, one with 10000 elements in it, or some number larger than
>I will ever need.  Suppose I then define a pointer to point to
>this type, and a handle to point to the pointer.  Let's say I want
>to start out with seven elements in the array, so I use NewHandle
>and allocate just enough memory to hold those seven elements.  I
>store this number seven in a variable to keep track of how big
>the array is.
>
>Now, as long as I am careful not to refer to any elements beyond the
>end of the memory block, I should not have any problems, right?
>And if I want to resize the array, I can use SetHandleSize,
>making sure to keep track of how many elements are now in the array,
>right?  Is there any reason why this shouldn't work?

Umm..not quite. Pascal is defined to Range Check at RUN time. That is,
if you access outside of the declared range it's a runtime error. So
as long as your dynamic array is smaller than your declared array,
you'd be OK for the range checking (assuming you don't write outside
the actual size of the array, as you said). But if you ever tried to
write to a location beyond the end of your declared size, you'd get a
runtime error.

MPW Pascal (and I believe Think Pascal also), have the ability to turn off
runtime range checking. You'll need to turn it off everywhere you index
into your dynamic array.

In MPW Pascal you use the directive:
  {$R-} to turn runtime range checking for sets, arrays and strings off.
  {$R+} to turn it back on.

>--Kurisuto
>un020070@vaxa.wvnet.edu

Mitch



-- 
Mitch Adler           mitch@apple.com
Development Systems
Apple Computer, Inc.  AppleLink: M.Adler

Claimer: These are MY opinions, not Darin's, not Apple's! MINE!

vrm@babcock.cerc.wvu.wvnet.edu (Vasile R. Montan) (04/21/91)

From article <13102@goofy.Apple.COM>, by mitch@Apple.COM (Mitchell Adler):
[Deleted posting in which I ask whether you can SetHandleSize on
an array as long as you're careful not to read/write past the end
of the block] 
> Umm..not quite. Pascal is defined to Range Check at RUN time. That is,
> if you access outside of the declared range it's a runtime error. So
> as long as your dynamic array is smaller than your declared array,
> you'd be OK for the range checking (assuming you don't write outside
> the actual size of the array, as you said). But if you ever tried to
> write to a location beyond the end of your declared size, you'd get a
> runtime error.
> 
> MPW Pascal (and I believe Think Pascal also), have the ability to turn off
> runtime range checking. You'll need to turn it off everywhere you index
> into your dynamic array.

I've gone ahead and used the technique, but I am running into a problem
of a different kind.  I'd like to be able to define an array as, say,
MyArrayType = array[0..32000] of SomeType, since 32000 is a lot bigger
than I will ever need.  Unfortunately, the Lightspeed Pascal Compiler
(which is what I'm stuck with) gives it a thumbs-down and says "Variables
of this type would be too large."  It seems the biggest range possible
is around [0..125], which may not be big enough for what I need.

Don't some versions of Pascal allow you to declare a range as [0..0]
to solve this problem?  Lightspeed takes this to mean that your array
has only one element, number 0, and gives a range error if you refer,
say, number 1.

So how do I turn off range checking in Lightspeed Pascal?  Any
ideas?

--Kurisuto
un020070@vaxa.wvnet.edu

unierik@uts.uni-c.dk (Erik Bertelsen) (04/22/91)

> In MPW Pascal you use the directive:
>   {$R-} to turn runtime range checking for sets, arrays and strings off.
>   {$R+} to turn it back on.

You can even do this:

   {$push}{$R-}
       { some code that is performed without runtime range checks }
  {$pop}   { resume previous setting }

This will allow you preserve the global setting of range check (and other
options) and have the global setting be one value while debugging and 
another in final builds.

regards
Erik Bertelsen
UNI-C, The Danish Computing Centre for Research and Education.