Re: [RFC] Logically composable variant of errexit

2014-10-13 Thread Chet Ramey
On 10/10/14, 5:26 AM, Andreas Grünbacher wrote:
 2014-10-10 3:29 GMT+02:00 Chet Ramey chet.ra...@case.edu:
 What does logically composable mean in this context?
 
 I would like the hypothetical errfail option to:
 
  * Behave like errexit at the top level (outside of functions).
 
  * Be inherited by functions,  subshells, and command substitution.
 
  * Inside functions, it should trigger like errexit would outside of
functions, no matter how the function is called.
It should return instead of exiting, though.

So you want executing shell functions -- and only executing functions --
to change the entire scope of errexit.  For example, you want functions to
return on an error, presumably with a non-zero return status.  However,
this is not compatible with your first point, which says that at the top
level, it would behave like errexit.  Since functions are simple commands,
a function returning a non-zero status would ordinarily cause the `top
level' to behave as if any other simple command failed.

 
 With errexit, you get vastly different results from functions depending
 on how the functions are called, for example,

Sure, because functions are simple commands.  They are subject to the same
conditions as any other simple command.

 
foo() {
   echo foo: top
   false
   echo foo: bottom
}
 
set -o errexit
 
# bottom of foo reached:
 if foo; then
   echo success  # reached
fi
 
# bottom of foo not reached:
foo
 
 With errfail, foo:bottom and success would not be reached.
 
 Command substitutions would continue to behave as basic commands
 do with respect to control flow: inside functions, a failure would cause
 the function to return; outside of functions, the script would exit.

Hmm...but command substitutions are not themselves commands: they are a
word expansion.  The fact that an assignment statement returns the status
of a command substitution in the absence of a command is a very special
case.  Given that special case, though, there is already a way to do
what you want, unless you want

some-command with some $(arguments) here

to exit the shell if $(arguments) ends up returning a non-zero status.

Chet
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/



Re: [RFC] Logically composable variant of errexit

2014-10-10 Thread Dan Douglas
I would still propose that a simple and powerful way to extend Bash with
exception handling would be to extend the ERR trap by passing it some metadata
about the type and location of the exception incurred so that it can be handled
by user code. This proposal allows us to largely avoid having to answer the
question of when and where does it make sense for this to get triggered? for
the user.

It might require a new type of trap that just fires on anything that returns
false or fails so that the user handler can choose what to do about it in
various contexts.

A more ambitious proposal might be to try cloning zsh's try/catch. It would be
familiar to programmers and of course having a pre-existing implementation is a
plus. try/catch is probably more intrusive than my first proposal due to the
additional keywords and control flow changes.

-- 
Dan Douglas



Re: [RFC] Logically composable variant of errexit

2014-10-10 Thread Andreas Grünbacher
2014-10-10 3:29 GMT+02:00 Chet Ramey chet.ra...@case.edu:
 What does logically composable mean in this context?

I would like the hypothetical errfail option to:

 * Behave like errexit at the top level (outside of functions).

 * Be inherited by functions,  subshells, and command substitution.

 * Inside functions, it should trigger like errexit would outside of
   functions, no matter how the function is called.
   It should return instead of exiting, though.

With errexit, you get vastly different results from functions depending
on how the functions are called, for example,

   foo() {
  echo foo: top
  false
  echo foo: bottom
   }

   set -o errexit

   # bottom of foo reached:
if foo; then
  echo success  # reached
   fi

   # bottom of foo not reached:
   foo

With errfail, foo:bottom and success would not be reached.

Command substitutions would continue to behave as basic commands
do with respect to control flow: inside functions, a failure would cause
the function to return; outside of functions, the script would exit.

Thanks,
Andreas



Re: [RFC] Logically composable variant of errexit

2014-10-10 Thread Andreas Grünbacher
2014-10-10 8:38 GMT+02:00 Dan Douglas orm...@gmail.com:
 I would still propose that a simple and powerful way to extend Bash with
 exception handling would be to extend the ERR trap by passing it some metadata
 about the type and location of the exception incurred so that it can be 
 handled
 by user code. This proposal allows us to largely avoid having to answer the
 question of when and where does it make sense for this to get triggered? for
 the user.

 It might require a new type of trap that just fires on anything that returns
 false or fails so that the user handler can choose what to do about it in
 various contexts.

Well, currently, the ERR trap only triggers when errexit would
trigger, so another
type of trap would certainly be needed. I don't think it's reasonable
to expect from
users to use trigger tricks to get basic error handling working in a sane way,
though; this should be built in and trivial to activate.

Thanks,
Andreas



Re: [RFC] Logically composable variant of errexit

2014-10-10 Thread Ángel González
On Andreas Grünbacher wrote:
 With errexit, you get vastly different results from functions depending
 on how the functions are called, for example,
 
foo() {
   echo foo: top
   false
   echo foo: bottom
}
 
set -o errexit
 
# bottom of foo reached:
 if foo; then
   echo success  # reached
fi
 
# bottom of foo not reached:
foo
 
 With errfail, foo:bottom and success would not be reached.

I disagree. IMHO the function should have the errfail value of its
parent scope at the time of its definition.

Otherwise, a function expecting to ignore errors would mysteriously fail
in a script that set -o errexit, unaware that one of the commands it
calls is [shadowed by] a function.

Thus, you would have to put the set at the top for the behavior you expected.


 Command substitutions would continue to behave as basic commands
 do with respect to control flow: inside functions, a failure would cause
 the function to return; outside of functions, the script would exit.

+1




Re: [RFC] Logically composable variant of errexit

2014-10-09 Thread Ángel González
Andreas Grünbacher wrote:
 Hi all,
 
 the errexit option can be very useful in simple scripts. This option
 is being ignored in many contexts like lists and conditionals though.
 I understand that this is by design and that errexit cannot be
 fixed to behave more reasonably. Still, this makes bash a lot less
 useful than it could be; working around this limitation is painful,
 ugly, and leads to fragile code.
 
 So, since we cannot fix errexit, can we maybe introduce another
 option like errfail that behaves like errexit for simple commands,
 but is also logically composable? Let me show what I mean with the
 following pseudo-code:

I think you should explicitely state where and you would like it not to
do it. I find unlikely to develop it, but at least they could be
documented, with its workarounds.
On some cases with non-POSIX features, maybe the behavior could be
changed for some non-POSIX (eg. the change of arighmetic expansion on
bash-4.1)

For reference, the current doc says:
  if the
  failed command is part of the command list immediately following
  an `until' or `while' keyword, part of the test following the `if'
  or `elif' reserved words, part of a command executed in a `' or
  `||' list except the command following the final `' or `||', any
  command in a pipeline but the last, or if the command's return
  status is being inverted using `!'

 
set -o errfail
fail() {
   false
   echo 'oops!' 2  # not reached
}
! fail
fail || :
if fail; then
   :
fi
set -- `fail`  # script fails here
echo 'oops!' 2  # not reached

This seems to request a change on two cases:
- inherit the errexit flag into functions
- make shell expansions fail the command including them


For the first one, I don't see a spec reason for that, other than it
has been done like that, requiring an explicit set -o errfail. Maybe
the set options should be inherited for set -E


While we discuss it, I find odd that this code doesn't run the trap
inside a function but does outside:
 fail() {
   trap echo trap executed ERR
   false
 }


As for the second option, I also missed such a ability a while back, but
was able to get the expected behavior with the workaround:
 FAIL=$(fail)
 set -- $FAIL




 Having such an option would certainly make bash a lot more useful to me.
 What do you guys think, could such an option be implemented with
 reasonable effort?

I don't think it would require special effort, but IMHO adding a
_slightly different errexit_ wouldn't be appropiate. Changing errexit
semantic, has a big potential for broken scripts. And having readily
available workarounds…






Re: [RFC] Logically composable variant of errexit

2014-10-09 Thread Chet Ramey
On 10/9/14, 8:20 AM, Andreas Grünbacher wrote:
 Hi all,
 
 the errexit option can be very useful in simple scripts. This option
 is being ignored in many contexts like lists and conditionals though.
 I understand that this is by design and that errexit cannot be
 fixed to behave more reasonably. Still, this makes bash a lot less
 useful than it could be; working around this limitation is painful,
 ugly, and leads to fragile code.
 
 So, since we cannot fix errexit, can we maybe introduce another
 option like errfail that behaves like errexit for simple commands,
 but is also logically composable? Let me show what I mean with the
 following pseudo-code:

What does logically composable mean in this context?

Maybe it would be better if you described how you would like the behavior
to differ from errexit.  Like Angel, I see that you want errfail to be
`inherited' by functions, like errexit; inhibited in the same set of
exceptions; but that command substitution failures will cause the shell
to exit.  Is that accurate?

Chet


-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/