New as function
Peter N Lewis
peter at stairways.com.au
Sun Jul 24 09:31:35 CEST 2005
At 5:05 +0200 24/7/05, Frank Heckenbach wrote:
>Peter N Lewis wrote:
> > I'd love to start using New and Schema and such, but the best
>> solution seems to be the Trap technique and that's some ugly code to
> > have any place you want to use New and not crash out.
>With a nil-return approach you'd really have to check each
>allocation, of course ...
True, although I'm pretty used to that, and if you are going to have
anything other than "program dies on allocation failure" memory
handling, then you have to have *some* code. The question is what is
reasonable and simple and clear.
>I think checking for nil before initialization would not be that
>hard to do in the compiler. The main drawback I see would be that it
>would add some code to all programs because the compiler can't know
>whether the allocator that's active at runtime may return nil. (And
>no, I don't want to add a compiler option. This would create quite
>an ugly mess of compile-time settings and runtime behaviour
>interdependence and just invite hard to find bugs.) OTOH, the check
>would, of course, only be necessary if the type needs initialization
>at all (which the compiler knows), so most allocations are not
>affected -- only files, schemata and objects ATM. So perhaps it's
>not that bad. Such things are not allocated and initializalized in
>tight inner loops usually, anyway.
It sounds reasonable to me. I'd even be happy with this applying
only to the New as function case if that would help, ie:
New(s,57) gives a runtime error on failure, and so the compiler knows
that it need not bother checking.
s := New(String,57) potentially returns nil, so the compiler checks.
I'm not sure if that is reasonable. It makes a certain kind of sense
in some respects - New as a procedure has no return value and thus
nothing to report, New as a function returns a pointer (even for
reference objects anyway) and therefore can return a success/failure
>And then there's a problem with allocation in the RTS. I don't think
>there are so many places, so I could probably take care of all of
>them and check for nil-returns. The question is, of course, what to
>do then. Unless there's a reasonable default behaviour that can be
>done without allocating memory (rarely, I'd suppose), I think the
>best and safest thing to do is raise a runtime error. And there we
>are again ...
If there is no way to return an error as an alternative to runtime
failure, then runtime failure is the only option.
I checked and there are about 20 in units and about 15 in rts. Most
look like they have not much choice but to runtime error, while some,
like LocaleConv for example, look like they could easily pass the
failure on up the line.
I guess by having the two forms of New (function and pointer) behave
as described above, it might work quite well in that you can easily
make the decision in the rts or in user code - if you don't want to
(or cannot) deal with the error, then call New as a procedure; if you
are willing to deal with the possible memory allocation failure, then
call New a a function and honour the possibly nil result.
> > I did think of another hack, which was to pre-allocate a chunk of
>> memory larger than the largest New command, and then have GetMem
>> return that for failure, then rather than testing for nil, I could
>> test of that safe return value. It's ugly, but probably the simplest
>> solution that provides clean New code.
>It's a kludge. I think it would work, but I wouldn't like to keep it
>permanently ... ;-)
True, but actually, way back in the days of the first Mac, when we
had 128K memory, the heap manager had a concept of a "grow zone"
which basically did just this. At the start, you allocated a spare
chunk of memory, enough so that no critical systems would fail (eg
putting up a dialog to tell the user that all hope was lost), and
then if the heap manager was going to fail a memory request, if
released this block of memory and retried the request, and then later
in your main loop, you detected that the memory had been released and
warned the user/saved files/gracefully quit/whatever. You still had
to be careful for any big allocations (eg reading in a file), but you
didn't have to be paranoid about every possible rts allocation.
So it is not an idea completely without precedent.
More information about the Gpc