Peter N Lewis wrote:
Peter N Lewis wrote:
Does New as a function return nil or does it still give a runtime error?
If I want to allocate memory, but handle it gracefully if it fails, what are the recommended approaches?
You could also trap runtime errors, using `AtExit', or use the `Trap' unit (which does this internally). This comes somewhat closer to exception, though it's not quite the same. Indeed, this may be the best solution available. It's a bit code to write, but it uses `New' and has no disadvantages in this regard.
Ok, it's an interesting approach, but I'd have to write that code for each type, which is still pretty ugly.
I just checked, and if New returns nil (using the UndocumentedReturnNil for example), the compiler will blindly try to Initialize the returned data, and bus error.
I'm not sure if this counts as a bug, since presumably UndocumentedReturnNil is only suppose to be for BP compatibility, and with BP compatibility there would be no Schema and thus no initialization. Unless perhaps BP has objects, in which case, New(obj) which returned UndocumentedReturnNil would probably have the same bus error issue.
It's a shame, as this would be the best solution (documenting UndocumentedReturnNil and allowing GetMem to return it).
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.
Yes, trapping each single allocation is quite some work. The same would hold for exceptions, BTW. If you'd add an exception handler for each single allocation, this will get a bit ugly. Often, AFAIK, exception handlers are used around somewhat larger blocks. You can do the same, of course, with Trap. (That's what I do in one of my programs, to basically handle all runtime errors globally.)
With a nil-return approach you'd really have to check each allocation, of course ...
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.
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 ...
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 ... ;-)
Frank