problem-solving
problem-solving copied to clipboard
`LEAVE` phaser fires when errorring in argument binding
sub foo(Int:D :$x) {
ENTER { say "entering foo" };
LEAVE { say "leaving foo" };
}
foo()
produces:
leaving foo
Parameter '$x' of routine 'foo' must be an object instance of type
'Int', not a type object of type 'Int'. Did you forget a '.new'?
Two things feel surprising to me:
- the
LEAVEblock was run, without theENTERblock being run - the
LEAVEblock was run ever though the sub was not "really" executed (I know that signature binding happens sort-of inside the sub, but I feel that should be an implementation detail, not something visible at the language level)
See also the discussion at https://s.thenautilus.net/notes/99rjsevs52
Perhaps the reason why things are as they are is in case anyone writes a signature that requires post bind attempt clean up, and LEAVE was considered the appropriate hook.
It seems to me that this comment disappeared, even though it might be good to at least be able to read it:
I don't think this issue benefits from mentioning the ENTER phaser, at least not in the title and in comments from here on (unless I'm missing something).
This is first and foremost because I didn't see anyone (in the linked discussion) saying they're surprised by how the ENTER phaser is interacting with signature binding.
But it's also because the design does not keep ENTER and LEAVE phasers symmetrical. For example, the queue of ENTER phasers (there can be more than one) for a block is aborted if there's an exception thrown by an ENTER phaser, whereas the LEAVE phaser queue keeps on trucking even if an exception is thrown by a LEAVE phaser. So expecting symmetry between the ENTER and LEAVE phasers in general is a mistake and it may just be that expecting symmetry in this trial bind aspect is also a mistake.
In summary, I currently suspect mentioning ENTER in any of our subsequent discussion is a red herring, and the mention in the title would best be removed.