Is there a good way to handle exceptioins in the declarative region of a function

While working on day 6 of AoC, I found myself breaking a larger calculation into parts and saving them as constants in the declarative region of the function. This was super clean for reading and let me document all my steps nicely. I also knew that if any of the steps failed, then my result should be 0. So I figured I would put an exception handler in the function and return 0 (Note that the case where exceptions happen would be pretty rare based on some really edge case inputs that weren’t practical to the problem):

The problem I ran into is if the early steps raised an exception, then the exception handler wouldn’t catch them as they were in the declarative region. See mock up below:

function Calculate(Inputs : Input_Type) return Integer is
   Step_1 : constant Integer := Some_Function(Stuff);
   Step_2 : constant Integer := Some_Other_Function(Stuff);
begin
   return Final_Function(Step_1, Step_2);
exception
   when others => return 0;  -- doesn't catch Step_1 or Step_2 exceptions!!!
end Calculate;

Any suggestions on a clean way to catch those declarative exceptions? I don’t like putting them in a declare block in the function body because that just indents everything needlessly. Currently I renamed my original function to old_name_unhandled and call it a new wrapper function named the original name, but that does feel kinda silly.

I was hoping there is an aspect or pragma maybe?

The decision for Ada was that exception handlers could reference the declarations associated with the block. When an exception occurs during the elaboration of those declarations, some of them may not exist, so such exceptions cannot be handled in the block’s exception handlers under this rule. They can only be handled outside the block, by a surrounding block’s handlers or the caller of a subprogram. If you need to handle them in the block’s handlers, then you have to arrange for them to be raised after the begin of the block. A block statement is one way to do that.

It is possible to design a language so that an exception handler can’t access the declarations, or can tell which declarations have successfully elaborated, in which case it could handle exceptions from the declarations. It’s not clear to me how useful such handlers would be.

I assume block statement means using declare?

Edit: Yes

…but not always. You could have just begin ... end; or begin ... exception ... end;

Right, because the ARM says that the declarative part is optional. Ofc, in the context of this thread that hardly applies!

I used “block statement” to refer to the statement defined in the ARM. But I used “block” alone to refer to anything with the structure

<header> is
   <declarative part>
begin
   <statements>
exception
   <handlers>
end [Name];

of which there are many.