High() and Low() for empty dynamic arrays

classic Classic list List threaded Threaded
18 messages Options
Reply | Threaded
Open this post in threaded view
|

High() and Low() for empty dynamic arrays

Jürgen Hestermann
Some time ago there was a discussion about the data type
given back by the "length" function.
Several reasons were given for the type beeing a *signed* integer.

But what about High() and Low()?
Shouldn't they give back signed integers too for the same reasons?

Especially, when I have a dynamic array like

--------------------------------
var MyArray : array of ...
...
for i := Low(MyArray) to High(MyArray) do
    MyArray[i] := ...
--------------------------------

I now have to prepend this with a

--------------------------------
if Length(MyArray)<>0 then..
--------------------------------

because otherwise I would get an error in case the length is 0
because Low() and High() both give back 0.
The result of both functions is the same as if the array had exact one element.

I find this quite illogical and would prefer if High() gives
back a value less than Low() in this case so that the above
for-loop would not be entered at all without the need to prepend
it with an if-condition.
For example, setting High() to -1 while Low() to 0 for empty
dynamic arrays would avoid this special case.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Florian Klämpfl
Am 08.02.2014 16:56, schrieb Jürgen Hestermann:
>
> because otherwise I would get an error in case the length is 0
> because Low() and High() both give back 0.
> The result of both functions is the same as if the array had exact one
> element.

Here:

var MyArray : array of longint;

begin
   writeln(low(MyArray));
   writeln(high(MyArray));
end.

prints

0
-1

Unfortunatly you posted not a complete example which shows the behaviour
but only uncompilable code snippts. Post always complete examples when
discussing strange behaviour.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

leledumbo
Administrator
> Here:
>
> var MyArray : array of longint;
>
> begin
>    writeln(low(MyArray));
>    writeln(high(MyArray));
> end.
>
> prints
>
> 0
> -1

Is this (High() on empty dynamic arrays return -1) documented somewhere?
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Jürgen Hestermann
In reply to this post by Florian Klämpfl
Am 2014-02-08 17:05, schrieb Florian Klaempfl:
 > Here:
 > var MyArray : array of longint;
 > begin
 >   writeln(low(MyArray));
 >   writeln(high(MyArray));
 > end.
 > prints
 > 0
 > -1

Hmm.
I was under the impression that both give back zero.
But you are right.
A closer look showed that the error I got for arrays of zero length
came from the fact that I used a Cardinal type variable for the for-loop:

-------------------------------------------
var i : Cardinal;

for i := Low(MyArray) to High(MyArray) do ...
-------------------------------------------

which raises an exception when the array is empty
but works ok in all other cases.
Thanks for pointing me to my fault.



 > Unfortunatly you posted not a complete example which shows the behaviour but only uncompilable code snippts.
 > Post always complete examples when discussing strange behaviour.

You mean I should post thousands of code lines?



_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Michael Van Canneyt
In reply to this post by leledumbo


On Sat, 8 Feb 2014, leledumbo wrote:

>> Here:
>>
>> var MyArray : array of longint;
>>
>> begin
>>    writeln(low(MyArray));
>>    writeln(high(MyArray));
>> end.
>>
>> prints
>>
>> 0
>> -1
>
> Is this (High() on empty dynamic arrays return -1) documented somewhere?

It is now, in the system unit documentation for the High() function.

Michael.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Florian Klämpfl
In reply to this post by Jürgen Hestermann
Am 08.02.2014 17:35, schrieb Jürgen Hestermann:
>
>  > Unfortunatly you posted not a complete example which shows the
> behaviour but only uncompilable code snippts.
>  > Post always complete examples when discussing strange behaviour.
>
> You mean I should post thousands of code lines?

Of course not, just a small example as I did.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Jürgen Hestermann

Am 2014-02-08 17:40, schrieb Florian Klaempfl:
>
>> You mean I should post thousands of code lines?
>
> Of course not, just a small example as I did.
>

But for what reason?
It just generates work without benefit.

If I had doubts about my assumption regarding High and Low
I would not have asked my question at all
but instead tested it more thoroughly.

But I had no doubts so I only asked why High and Low give back 0.
Why should I write code for my question?
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Sven Barth-2

Am 08.02.2014 18:06 schrieb "Jürgen Hestermann" <[hidden email]>:
>
>
> Am 2014-02-08 17:40, schrieb Florian Klaempfl:
>
>>
>>> You mean I should post thousands of code lines?
>>
>>
>> Of course not, just a small example as I did.
>>
>
> But for what reason?
> It just generates work without benefit.
>
> If I had doubts about my assumption regarding High and Low
> I would not have asked my question at all
> but instead tested it more thoroughly.
>
> But I had no doubts so I only asked why High and Low give back 0.
> Why should I write code for my question?

This way we could try to reproduce your problem easier. Also it often happens that the problem goes away when one simplifies it, because it was an error in ones own code. This would likely have been true here as well.

Regards,
Sven


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Florian Klämpfl
In reply to this post by Jürgen Hestermann
Am 08.02.2014 18:06, schrieb Jürgen Hestermann:

>
> Am 2014-02-08 17:40, schrieb Florian Klaempfl:
>>
>>> You mean I should post thousands of code lines?
>>
>> Of course not, just a small example as I did.
>>
>
> But for what reason?
> It just generates work without benefit.
>
> If I had doubts about my assumption regarding High and Low
> I would not have asked my question at all
> but instead tested it more thoroughly.
>
> But I had no doubts so I only asked why High and Low give back 0.
> Why should I write code for my question?

You didn't have only a question but you made also a proposal for a
language change. And when proposing a change it is very usefull to have
an example which demonstrates the reason for the change.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Jürgen Hestermann
Am 2014-02-08 19:53, schrieb Florian Klämpfl:
 > You didn't have only a question but you made also a proposal for a
 > language change. And when proposing a change it is very usefull to have
 > an example which demonstrates the reason for the change.

What code should I have written?
I was convinced that Low() and High() both give back zero.
I did not ask how High/Low work.
I thought I had understood it.
So what code should I write?


My missinterpretation was based on two facts:

1.) I had switched off range checking
2.) I used a cardinal variable in my for loop

That lead to the circumstance that my for loop was entered
even when the dynamic array was empty.
And then I got an exception when accessing the element with index 0:

-------------------------------------
var i : Cardinal;
for i := low(MyArray) to High(MyArray) do
    MyArray[i] :=    <--- the debugger put me here with an exception
-------------------------------------

So I thought that High and Low both give back zero.
How otherwise could I end up within the for loop when the array is empty?

Actually the error already occured in the line before:
High() gave back -1 but was assigned to a cardinal variable.
With range check on I would have got an error here already.
But with range check off it was simply assigned so that
the high value now was a very high positive value!
Therefore the for loop was entered although it should not do so.

Under this impression, what kind of code should I have written?

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Saunders, Rich
On 2014-02-09 04:11, Jürgen Hestermann wrote:
> Am 2014-02-08 19:53, schrieb Florian Klämpfl:
>> You didn't have only a question but you made also a proposal for a
>> language change. And when proposing a change it is very usefull to
>> have
>> an example which demonstrates the reason for the change.
>
> [snip]
>
> Under this impression, what kind of code should I have written?

Knowing that you should provide a small but complete example that
illustrates the problem that you are proposing a solution to would have
caused you to attempt some code. That attempt would probably have
brought out the details and assumptions that you overlooked in your
original case. And that, in turn, probably would have allowed you to
diagnose your problem without bringing it to the developers.

So, its' not always about the specific example code. Sometimes it is
about the attempt to write it.

--

Cheers!
Rich Saunders
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

fredvs
Hello everybody.

I have a question (maybe stupid) about dynamic arrays...

Usually, before to close the application, to avoid memory leak, i do :

  if length(MyArray) > 0 then
 for x := 0 to high(MyArray) do
 MyArray[x].Free;

But, if i use :

 setlength(MyArray, 0) ;

would it do the same job ?

Thanks.

Fred

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Many thanks ;-)
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Michael Fuchs-5
Am 09.02.2014 13:05, schrieb Fred van Stappen:
> if length(MyArray) > 0 then
>   for x := 0 to high(MyArray) do
>     MyArray[x].Free;
>
> But, if i use :
>
>  setlength(MyArray, 0) ;
>
> would it do the same job ?

No. Your array contains only references to the objects. The references
where deleted, but the objects remain in memory without any destructor call.

g
Michael
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

fredvs

> Date: Sun, 9 Feb 2014 13:08:16 +0100

> From: [hidden email]
> To: [hidden email]
> Subject: Re: [fpc-pascal] High() and Low() for empty dynamic arrays
>
> Am 09.02.2014 13:05, schrieb Fred van Stappen:
> > if length(MyArray) > 0 then
> > for x := 0 to high(MyArray) do
> > MyArray[x].Free;
> >
> > But, if i use :
> >
> > setlength(MyArray, 0) ;
> >
> > would it do the same job ?
>
> No. Your array contains only references to the objects. The references
> where deleted, but the objects remain in memory without any destructor call.
>
> g
> Michael

OK, many thanks Michael.

Hum, i have a dynamic array of threads.

mythread.create has :
FreeOnTerminate := True; 

So, when the thread terminate, it frees the memory too ? (yes/no).
And it explain why i get a crash and error message if i try to do, for dynamic arrays of threads :

 > if length(MyArray) > 0 then
 > for x := 0 to high(MyArray) do
 > MyArray[x].Free;

Because the threads are already freed (yes/no) ?

If so, how can i know if MyArray[x] was already freed ?

When i use:
if assigned(MyArray[x]) then MyArray[x].Free;

It does not work.

Many thanks.

Fred

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Many thanks ;-)
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Jürgen Hestermann
Am 2014-02-09 15:10, schrieb Fred van Stappen:
 >  > if length(MyArray) > 0 then
 >  > for x := 0 to high(MyArray) do
 >  > MyArray[x].Free;

As I have learned just recently ;-) this code could be shortened by

for x := low(MyArray) to high(MyArray) do
    MyArray[x].Free;

if x is a signed integer. So you would save the length check.


 > Because the threads are already freed (yes/no) ?

Yes, that's tricky. *Some* (managed) data structures like ansistrings and dynamic arrays are freed by the compiler. But if you requested memory by yourself (new, getmem) then you need to clean it up yourself too. I am not sure what applies to threads but I would think that they are managed by the compiler so that a setlength(MyArray,0) would automatically free all (automatically) allocated data.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Sven Barth-2
On 09.02.2014 15:46, Jürgen Hestermann wrote:

> Am 2014-02-09 15:10, schrieb Fred van Stappen:
>  >  > if length(MyArray) > 0 then
>  >  > for x := 0 to high(MyArray) do
>  >  > MyArray[x].Free;
>
> As I have learned just recently ;-) this code could be shortened by
>
> for x := low(MyArray) to high(MyArray) do
>     MyArray[x].Free;
>
> if x is a signed integer. So you would save the length check.

Or:

for arrayelem in MyArray do
   arrayelem.Free;

>  > Because the threads are already freed (yes/no) ?
>
> Yes, that's tricky. *Some* (managed) data structures like ansistrings
> and dynamic arrays are freed by the compiler. But if you requested
> memory by yourself (new, getmem) then you need to clean it up yourself
> too. I am not sure what applies to threads but I would think that they
> are managed by the compiler so that a setlength(MyArray,0) would
> automatically free all (automatically) allocated data.

Threads themselves are normal class instances. Normal class instances
need to be freed manually (we don't have ARC for class instances yet).
Threads however implement a "FreeOnTerminate" property that tells the
thread to free itself once it terminates. In this case you must not free
the thread yourself (and at best don't touch the class instance variable
anymore after you used "Start", because the thread might already be
terminated by that point and thus the instance freed).

Regards,
Sven
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

Sven Barth-2
In reply to this post by fredvs
On 09.02.2014 15:10, Fred van Stappen wrote:

>
>  > Date: Sun, 9 Feb 2014 13:08:16 +0100
>  > From: [hidden email]
>  > To: [hidden email]
>  > Subject: Re: [fpc-pascal] High() and Low() for empty dynamic arrays
>  >
>  > Am 09.02.2014 13:05, schrieb Fred van Stappen:
>  > > if length(MyArray) > 0 then
>  > > for x := 0 to high(MyArray) do
>  > > MyArray[x].Free;
>  > >
>  > > But, if i use :
>  > >
>  > > setlength(MyArray, 0) ;
>  > >
>  > > would it do the same job ?
>  >
>  > No. Your array contains only references to the objects. The references
>  > where deleted, but the objects remain in memory without any
> destructor call.
>  >
>  > g
>  > Michael
>
> OK, many thanks Michael.
>
> Hum, i have a dynamic array of threads.
>
> mythread.create has :
> FreeOnTerminate := True;
>
> So, when the thread terminate, it frees the memory too ? (yes/no).

Yes, that frees the complete class instance of the thread.

> And it explain why i get a crash and error message if i try to do, for
> dynamic arrays of threads :
>
>   > if length(MyArray) > 0 then
>   > for x := 0 to high(MyArray) do
>   > MyArray[x].Free;
>
> Because the threads are already freed (yes/no) ?

Exactly.
>
> If so, how can i know if MyArray[x] was already freed ?

You can't. You must not access MyArray[x] anymore after the thread
terminated.

>
> When i use:
> if assigned(MyArray[x]) then MyArray[x].Free;
>
> It does not work.

Yes, because MyArray[x] is not modified when the thread destroys the
class at the end of its life. It doesn't even know that there is a
variable that points to the class (class instance variables are
basically pointers to the real class instance data). Thus the MyArray[x]
still contains the pointer to the class instance data, but the later was
already destroyed, so it's no longer valid memory. So: don't touch it! ;)

Regards,
Sven

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: High() and Low() for empty dynamic arrays

fredvs
> So: don't touch it! ;)
>
> Regards,
> Sven

Yep, many thanks for that clear answer.


;-)

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Many thanks ;-)