Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Distinguish one sub invocation from another

In the following fragment, how can I distinguish the second invocation instance of my sub foo from the first?

while ($whatever) {
  foo(); foo();     # foo() and foo() have the same caller package, file, and line
}

Something like a super-caller() that returned file, line and column would do the trick. I'd prefer not to use source filters.

Background, or, isn't this a bit of an XY Problem?

I have a convenience module, Local::Thread::Once, that exposes functionality like pthread_once/std::call_once in an OO-ish way and also as a subroutine attribute. These are easy enough, since there is a natural and unambiguous "once_control" or "once_flag" in either case.

However, there is additionally a procedural interface — once { ... } — that currently serializes based on the $filename and $line returned by caller. Something like this:

sub once(&) {
  my $user_routine = shift;
  my (undef, $file, $line) = caller;

  my $once_control = get_a_shared_flag_just_for_this_invocation($file, $line);

  lock($once_control);
  if (! $once_control) { $once_control++; $user_routine->(); }
  return;
}

That's not precisely how it works — the real one is more efficient — but the point, again, is that invocation is keyed off of the file and line of the caller. This works, except that it cannot distinguish two invocations on the same line.

while ($whatever) {
  once { foo(); }
  once { bar(); }                    # OK, foo() and bar() each called only once
  once { baz(); }; once { buz(); };  # :(  buz() not called, not even once
}

Note that the address of $user_routine cannot be used as an additional discriminant, since subs are copied from one ithread to another.

I can live with this problem as a documented limitation for a very contrived use case, but I'd prefer to fix it somehow.

like image 720
pilcrow Avatar asked Dec 25 '22 21:12

pilcrow


1 Answers

Devel::Callsite was written precisely for this purpose.

like image 74
tobyink Avatar answered Jan 12 '23 21:01

tobyink