QUIT argument not allowed

   try{
        ....
        ....
        ....

        Set tSC = method_invocation()

        If $$$ISERR(tSC) {
            Quit tSC
        }

        ....
        ....
        ....

}

On compiling the above, I get an error saying "QUIT argument not allowed : 'tSC' ".

  • When I replace Quit tSC with Return tSC, it compiles
  • On replacing Quit tSC with Quit $$$OK, I get the error: QUIT argument not allowed : '1'
  • On replacing Quit tSC with Quit, it compiles
  • A 'Quit tSC' statement outside of the try-catch block does not cause a compile-time error.

The reason this happens is because a 'Quit' inside a try-catch block causes control to be passed to the code immediately outside the try catch block instead of quitting the function and returning a value.

 

Sharing this here because it took me a while to realize what was happening (and although something related is briefly mentioned in the try-catch docs, I could only find it after I realized that the problem was related to try-catch)

Replies

try {

    Set tSC = method_invocation()

    If $$$ISERR(tSC) {

      THROW tSC 

}

} catch err {

}

Assuming that tSC is a %Library.Status, I don't think this will work the way you intend it to.  The argument to a THROW has to be an oref to a class that extends %Exception.AbstractException:

https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_cthrow
If you have a %Status that you need to throw as an exception, you can use $$$ThrowOnError or $$$ThrowStatus, both defined in %occStatus.inc. They both call ##class(%Exception.StatusException).ThrowIfInterrupt(), but $$$ThrowOnError only does so if the status is an error, so it's slightly more efficient if you haven't checked the status yet.

Try {

    $$$ThrowOnError(method_invocation()) {

} Catch ex {

     $$$LOGSTATUS(ex.AsStatus())

}

It should be noted that this applies not only to the try/catch block, but also to other blocks, for example:

i=1:1:2 {
  ; runtime error, but the line is highlighted
}

do {
  ; compilation error
}while(0)

while {
  ; compilation error
}

Suggest use "Return" keyword instead of "Quit"

For example:

Class Test.ReturnOfTheTry [ Abstract ]
{

  ClassMethod GetReturn(state = 0)
    {
    try {
      if state=1 return "In Try"
      set x=3/0
    } catch {
      if state=2 return "In Catch"
  }
  quit "At Methods End"
  }

}

// Usage example

Write ##class(Test.ReturnOfTheTry).GetReturn(1)
In Try
Write ##class(Test.ReturnOfTheTry).GetReturn(2)
In Catch
Write ##class(Test.ReturnOfTheTry).GetReturn()
At Methods End

Its a very common coding issue. I achieve what you are trying to do by this construct

Method DoStuff() As %Status
{
  set tSC = $$$OK

  do {

    set tSC = method_invocation1()
    quit:$$$ISERR(tSC) 

    set tSC = method_invocation2()
    quit:$$$ISERR(tSC)

  } while 0
  quit tSC
}
 

This enables you to exit at the first issue with the relevant status.
The do while loop is just there to act as a 'container' for the code so you can jump out of it with a quit with no arguments, it can be replaced with a try catch block.

Even though Tim's article talks about this, I'll mention it briefly here. Since ObjectScript Try/Catch construct doesn't have a "Finally" block like some other languages, the code following the Try/Catch is often used for "Finally" code. Since Return inside Try/Catch exits the Try or Catch and terminates the method, this would bypass any "Finally" code at the end. Therefore, I'd recommend avoiding using Return inside Try/Catch.

So if $$$ISERR(tSc), convert tSc into an exception and Throw it, and then handle the error in the Catch. After that, any "Finally" code will run.