بنقرة واحدة
mapl-error-handling
MAPL error handling macros and best practices
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
MAPL error handling macros and best practices
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Safely switch between NAG, gfortran, and Intel compilers when building MAPL
MAPL Fortran coding standards and style conventions
GitHub workflow, commit conventions, and PR process for MAPL
Build MAPL with NAG, gfortran, or Intel compilers on macOS and Linux
First-time MAPL development environment setup and configuration
Run and debug MAPL tests with pFUnit framework
| name | mapl-error-handling |
| description | MAPL error handling macros and best practices |
| compatibility | opencode |
Provide comprehensive guidance on MAPL's error handling system, including:
Use this skill when:
All modules using MAPL error handling must include:
#include "MAPL_Generic.h"
module MyModule
use MAPL
implicit none
private
! Your code here
end module MyModule
This provides access to all MAPL error handling macros.
Standard convention:
_SUCCESS macro)MAPL uses ESMF return code constants:
ESMF_SUCCESS = 0ESMF_FAILURE = non-zeroMAPL macros:
_SUCCESS → ESMF_SUCCESS (0)_FAILURE → ESMF_FAILURE (non-zero)Usage: Compact call + verify pattern
call some_procedure(arg1, arg2, _RC)
Expands to:
rc=status); _VERIFY(status)
What it does:
status variable as rc argumentExample:
subroutine process_data(input, output, rc)
type(DataSet), intent(in) :: input
type(DataSet), intent(out) :: output
integer, optional, intent(out) :: rc
integer :: status
call read_configuration('config.yaml', _RC)
call allocate_workspace(n_items, _RC)
call transform_data(input, output, _RC)
_RETURN(_SUCCESS)
end subroutine process_data
Benefits:
Usage: Check return codes explicitly
call some_procedure(arg1, arg2, rc=status)
_VERIFY(status)
What it does:
status == _SUCCESSUse when:
Example:
call read_file(filename, data, rc=status)
if (status /= _SUCCESS) then
call log_error('Failed to read: ' // trim(filename))
end if
_VERIFY(status)
Usually _RC is preferred over this pattern.
Usage: Check logical conditions
_ASSERT(condition, "Error message")
What it does:
Examples:
_ASSERT(n_columns > 0, "Number of columns must be positive")
_ASSERT(allocated(workspace), "Workspace not allocated")
_ASSERT(size(input) == size(output), "Array size mismatch")
Use for:
Don't use for:
_VERIFY or _RC)_FAIL insteadUsage: Force procedure to fail with message
_FAIL("Error message describing the problem")
What it does:
_FAILURECommon use: SELECT CASE with invalid/unexpected values
Example:
select case(operation_type)
case(ADD)
result = a + b
case(SUBTRACT)
result = a - b
case(MULTIPLY)
result = a * b
case default
_FAIL("Unknown operation type")
end select
Also useful for:
Note: If you find yourself doing _ASSERT(.FALSE., "message"), use _FAIL("message") instead - it's clearer.
Usage: Return from procedure with given status
_RETURN(status_value)
What it does:
Standard pattern at end of successful procedure:
subroutine my_procedure(arg, rc)
integer, intent(in) :: arg
integer, optional, intent(out) :: rc
! ... procedure implementation ...
_RETURN(_SUCCESS) ! Always end successful procedures this way
end subroutine my_procedure
Can return with any value:
if (early_exit_condition) then
_RETURN(_SUCCESS) ! Early successful return
end if
Usage: Represents successful return code (0)
_RETURN(_SUCCESS)
if (status == _SUCCESS) then
! Success path
end if
Expands to: ESMF_SUCCESS (which is 0)
Use instead of: Literal 0 in code
Benefits:
Usage: Represents failure return code (non-zero)
if (status /= _SUCCESS) then
! This is a failure
end if
Expands to: ESMF_FAILURE
Note: Usually don't need this directly - macros handle it. Provided for completeness.
Usage: Check Fortran intrinsic STAT codes
allocate(array(n), _STAT)
deallocate(array, _STAT)
Expands to:
stat=status); _VERIFY(status)
Examples:
subroutine allocate_workspace(n, rc)
integer, intent(in) :: n
integer, optional, intent(out) :: rc
integer :: status
real, allocatable :: workspace(:)
allocate(workspace(n), _STAT)
! Use workspace
deallocate(workspace, _STAT)
_RETURN(_SUCCESS)
end subroutine
Usage: Check Fortran I/O IOSTAT codes
open(unit, file=filename, _IOSTAT)
read(unit, *, _IOSTAT) values
close(unit, _IOSTAT)
Expands to:
iostat=status); _VERIFY(status)
Example:
subroutine read_data(filename, values, rc)
character(len=*), intent(in) :: filename
real, intent(out) :: values(:)
integer, optional, intent(out) :: rc
integer :: status, unit
open(newunit=unit, file=filename, status='old', _IOSTAT)
read(unit, *, _IOSTAT) values
close(unit, _IOSTAT)
_RETURN(_SUCCESS)
end subroutine read_data
Usage: Debug print with file and line information
_HERE, "debug message", variables
Expands to:
print*, __FILE__, __LINE__, "debug message", variables
Examples:
_HERE, "n_columns:", n_columns
_HERE, "Entering iteration:", iteration_count
_HERE, "Checkpoint A"
Use for:
Note: Remember to remove or comment out after debugging!
#include "MAPL_Generic.h"
module MAPL_DataProcessor
use ESMF
use MAPL_BaseMod
implicit none
private
public :: process_dataset
contains
subroutine process_dataset(input_file, output_file, n_iterations, rc)
character(len=*), intent(in) :: input_file
character(len=*), intent(in) :: output_file
integer, intent(in) :: n_iterations
integer, optional, intent(out) :: rc
integer :: status
real, allocatable :: data(:)
integer :: i, n_points
! Validate inputs
_ASSERT(n_iterations > 0, "Iterations must be positive")
_ASSERT(len_trim(input_file) > 0, "Input filename cannot be empty")
! Read number of points from file
call read_file_size(input_file, n_points, _RC)
! Allocate workspace
allocate(data(n_points), _STAT)
! Read data
call read_data(input_file, data, _RC)
! Process
do i = 1, n_iterations
call apply_filter(data, _RC)
end do
! Write results
call write_data(output_file, data, _RC)
! Cleanup
deallocate(data, _STAT)
_RETURN(_SUCCESS)
end subroutine process_dataset
subroutine read_file_size(filename, n_points, rc)
character(len=*), intent(in) :: filename
integer, intent(out) :: n_points
integer, optional, intent(out) :: rc
integer :: status, unit
open(newunit=unit, file=filename, status='old', _IOSTAT)
read(unit, *, _IOSTAT) n_points
close(unit, _IOSTAT)
_ASSERT(n_points > 0, "File contains invalid point count")
_RETURN(_SUCCESS)
end subroutine read_file_size
subroutine apply_filter(data, rc)
real, intent(inout) :: data(:)
integer, optional, intent(out) :: rc
integer :: status, filter_type
! Get filter type from configuration
call get_filter_type(filter_type, _RC)
! Apply appropriate filter
select case(filter_type)
case(1)
call apply_gaussian_filter(data, _RC)
case(2)
call apply_median_filter(data, _RC)
case(3)
call apply_moving_average(data, _RC)
case default
_FAIL("Unknown filter type")
end select
_RETURN(_SUCCESS)
end subroutine apply_filter
end module MAPL_DataProcessor
DO:
call some_procedure(args, _RC)
DON'T:
call some_procedure(args) ! Ignoring potential errors!
Why: If something fails, you want to know immediately, not debug mysterious crashes later.
DO:
subroutine my_proc(rc)
integer, optional, intent(out) :: rc
! ... successful execution ...
_RETURN(_SUCCESS)
end subroutine
DON'T:
subroutine my_proc(rc)
integer, optional, intent(out) :: rc
! ... successful execution ...
! Missing return status!
end subroutine
subroutine process(n_items, tolerance, rc)
integer, intent(in) :: n_items
real, intent(in) :: tolerance
integer, optional, intent(out) :: rc
! Validate first
_ASSERT(n_items > 0, "n_items must be positive")
_ASSERT(tolerance > 0.0, "tolerance must be positive")
_ASSERT(tolerance < 1.0, "tolerance must be less than 1")
! Now proceed with validated inputs
! ...
_RETURN(_SUCCESS)
end subroutine
allocate(workspace(n), _STAT)
allocate(temporary(m), _STAT)
Never:
allocate(workspace(n)) ! Unchecked!
open(newunit=unit, file=filename, _IOSTAT)
read(unit, *, _IOSTAT) data
close(unit, _IOSTAT)
Good:
_ASSERT(n_rows == n_cols, "Matrix must be square for this operation")
_FAIL("Configuration file missing required 'output_dir' parameter")
Poor:
_ASSERT(n_rows == n_cols, "Error")
_FAIL("Bad input")
subroutine process_with_cleanup(rc)
integer, optional, intent(out) :: rc
integer :: status
real, allocatable :: temp(:)
logical :: file_open
file_open = .false.
allocate(temp(100), _STAT)
open(newunit=unit, file='data.txt', _IOSTAT)
file_open = .true.
call risky_operation(_RC)
! Cleanup
if (file_open) close(unit)
deallocate(temp)
_RETURN(_SUCCESS)
end subroutine
Note: Error macros return immediately, so cleanup after error is tricky. Consider Fortran block scope or finalization for robust cleanup.
call read_configuration(config_file, config, rc=status)
if (status /= _SUCCESS) then
call log_error("Failed reading config: " // trim(config_file))
end if
_VERIFY(status)
! Unusual case: want to continue despite errors
call optional_operation(rc=status)
if (status /= _SUCCESS) then
call log_warning("Optional operation failed, continuing")
! Don't call _VERIFY - continue execution
end if
Old macros ending with underscore: VERIFY_, ASSERT_, __RC__
Problem: Required IAM character variable with procedure name
! OLD STYLE - Don't do this!
character(len=*), parameter :: IAM = 'my_procedure'
call something(args, __RC__)
Issues:
Migration:
! OLD
character(len=*), parameter :: IAM = 'my_procedure'
call foo(args, __RC__)
! NEW
call foo(args, _RC)
If you see these in code review: Request update to new macros
Error: Macros not defined Solution:
#include "MAPL_Generic.h"
Must come before module statement.
Error: Macros try to set rc but procedure doesn't have it Solution: Add optional rc parameter
subroutine my_proc(arg, rc) ! Add rc parameter
integer, intent(in) :: arg
integer, optional, intent(out) :: rc
! WRONG - not standard conforming
if (flag == .true.) then
! CORRECT - but redundant
if (flag .eqv. .true.) then
! BEST - direct use
if (flag) then
#include "MAPL_Generic.h" present_RC)_STAT)_IOSTAT)_RETURN(_SUCCESS)VERIFY_, __RC__, etc.)fortran-style - General Fortran coding standardsgithub-workflow - Code review processKey Points:
MAPL_Generic.h in all modules_RC for compact call + check pattern_ASSERT for precondition validation_STAT and _IOSTAT for intrinsics_RETURN(_SUCCESS)Philosophy: Error handling everywhere in calling chain. If something can fail, check it. Your future self (and teammates) will thank you during debugging.