JustThisGuy
JustThisGuy

Reputation: 1189

Possible Bug with run as Last Statement in try Block

I don't know if this is a bug, or I just don't understand what's happening. If I have a run statement as the last statement in a try block, any error in the run statement is not caught. If it is not the last statement in the block, the exception is caught. Here's what I get when run is the last statement:

try {
  CATCH {
    default {
      say 'CAUGHT!';
    }
  }

  run 'lss', '-al';
}

Output:

$ raku try-run-bug.raku 
The spawned command 'lss' exited unsuccessfully (exit code: -1, signal: 254)
(OS error = Failed to spawn process lss: no such file or directory (error code -2))
  in block <unit> at try-run-bug.raku line 1

Here's what I get if it isn't the last statement:

try {
  CATCH {
    default {
      say 'CAUGHT!';
    }
  }

  run 'lss', '-al';
  say 'foo';
}

Output:

$ raku try-run-bug-workaround.raku
CAUGHT!

This has been tested on:

$ raku -v
Welcome to Rakudo™ v2024.09.
Implementing the Raku® Programming Language v6.d.
Built on MoarVM version 2024.09.

via rakubrew.

Edit

Based on a comment below, I did try moving the CATCH block to the bottom in the first example, and it did fix the problem. It still seems like a bug to me because I thought that CATCH blocks could appear anywhere within the scope of the line that throws the exception. Please correct me if I'm wrong.

Upvotes: 6

Views: 129

Answers (1)

codesections
codesections

Reputation: 9600

run returns a Proc object, and Procs behave differently in sink context versus expression context. Specifically, in expression context, a Proc isn't run immediately (more or less like a lazy computation); instead, it's run when you call methods that require it to be run, such as .spawn, .out.slurp, or .exitcode.

Another method that runs a Proc is sink (which runs the command and throws an error if it failed). All that happens when a Proc is in sink context is that the .sink method gets called automatically.

With that background, we should be able to see why run behaves differently in your two code examples. At first, it might look like they're both in sink context since nether value is used. But remember: Raku blocks implicitly return their final expression – so when the run command is that final expression, it gets returned and thus is not in sink context. (The block that contains run is in sink context, but that doesn't "flow through" to the run).

But we can tell Raku what context we want. Specifically, we can use sink statement prefix:

try {
  CATCH {
    default {
      say 'CAUGHT!';
    }
  }

  sink run 'lss', '-al';
}

And once we're explicit about the context we want, we get the expected result:

CAUGHT!

Upvotes: 0

Related Questions