Question
· Jan 23, 2020

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)

Discussion (9)5
Log in or sign up to continue

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.

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.