bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Error handling with nofork command substitution


From: jm
Subject: Error handling with nofork command substitution
Date: Tue, 22 Aug 2023 02:41:30 +0000

Hi,

With the new funsub syntax ${ cmd;} and ${| cmd;} that encourages
returning the value of $REPLY to the caller, I've been thinking about
an idiomatic way of doing error handling and propagation that may
call for a new shell option or new type of funsub.

So the idea is natural, when a function encounters an error condition
it "raises" an error message by setting it in $REPLY and returning a
non-zero exit code, when there's no error it simply sets $REPLY to a
return value and returns a zero exit code.

For example:

function div {
  local -i x="$1" y="$2"
  if ((y==0)); then
    REPLY='CANNOT DIVIDE BY 0'
    return 100
  else
    REPLY=$((x/y))
  fi
}

function bin {
  local -i x="$1"
  case "$x" in
  (*[!01]*)
    REPLY='NOT BINARY NUMBER: '"$x"
    return 200
  ;;
  (*)
    REPLY=$((2#$x))
  esac
}

Now, "catching" an error can be done with an if or case statement
plus ${| cmd;} and propagation can be done by simply returning the
exit code (which the caller has to again catch with REPLY=${| cmd;}).
For example:

function main {
  REPLY=${| bin 10102; }
  case $? in
  (0) ;;
  (*)
    local code=$?
    echo "Error Message: [$REPLY], Exit Code: [$code]"
    return $code
  esac

  echo "There was no error! Decimal: $REPLY"
}

This is good but verbose for propagation, to address this languages
like Rust or Swift introduced a `?` operator that simply returns back
the code and message to the caller. We could emulate this in Bash
like this:

function ? {
  if REPLY=${| "$@"; }; then
    printf -- '%s' "$REPLY"
  else
    return $?
  fi
}

function calculation_steps {
  local -i ratio bi
  ratio=${ ? div 10 5  ;} || return $?   # ratio = div(10,5)?;
  bi=${ ? bin "$ratio" ;} || return $?   # bi = bin(ratio)?;
  REPLY="$bi"
}

If there was an error in a step, it gets propagated, if not, we
return the REPLY value.

And here is where I'd like to have like an option or syntactic sugar
that allows me to nest funsubs but returning out of the funsub if an
error was found, simulating `?` method chaining like in those other
languages.

This one doesn't work:

bi=${ ? bin ${ ? div 10 5; } ; } || return $?  # bi = div(10,5)?.bin()?;

This one does work, but is not better than the original:

bi=${
  ratio=${ ? div 10 5; } || return $?
  ? bin "$ratio"
} || return $?

Something like:

bi=${? bin ${? div 10 5; } ; }   # (1)
bi=${ div 10 5 ?| bin ; }        # (2)
bi=${
  local -
  set -o errpropagate            # (3)
  ? bin ${ ? div 10 5; }
}

I haven't found a solution in pure bash so that's why I'm throwing
new syntax ideas and making this thread; maybe there is and I'd love
to know, otherwise one of these 3 constructions could be implemented
if users find it useful.

(1) is clean, but parsing could be tricky because of $?
(2) would resemble method chaining in other languages but
it's not very idiomatic and probably the hardest to implement
(3) is probably easier to implement, no new syntax, but users
would still have to know and define their `?` propagation function

I'd also like some feedback on this error handling strategy.
Is there a better way? Does it have pitfalls?

Thanks, José



reply via email to

[Prev in Thread] Current Thread [Next in Thread]