From: "Eregon (Benoit Daloze) via ruby-core" Date: 2024-03-14T14:52:08+00:00 Subject: [ruby-core:117174] [Ruby master Feature#20335] `Thread.each_caller_location` should accept the same arguments as `caller` and `caller_locations` Issue #20335 has been updated by Eregon (Benoit Daloze). I think omitting the first N frames is useful. However I see little reason to have a `length` or `Range`, one can just `break/return` out of the `Thread.each_caller_location`, and it seems pretty rare to need that. So I think it's best to only add `start = 1` for now. In fact the `length` argument is already an issue for `caller_locations`: if it's too high it causes `caller_locations` to return an empty Array instead of whatever is available: ``` irb(main):001:0> caller_locations(10) => ["/home/eregon/.rubies/ruby-3.2.2/lib/ruby/3.2.0/irb/ruby-lex.rb:248:in `catch'", "/home/eregon/.rubies/ruby-3.2.2/lib/ruby/3.2.0/irb/ruby-lex.rb:248:in `each_top_level_statement'", "/home/eregon/.rubies/ruby-3.2.2/lib/ruby/3.2.0/irb.rb:566:in `eval_input'", "/home/eregon/.rubies/ruby-3.2.2/lib/ruby/3.2.0/irb.rb:500:in `block in run'", "/home/eregon/.rubies/ruby-3.2.2/lib/ruby/3.2.0/irb.rb:499:in `catch'", "/home/eregon/.rubies/ruby-3.2.2/lib/ruby/3.2.0/irb.rb:499:in `run'", "/home/eregon/.rubies/ruby-3.2.2/lib/ruby/3.2.0/irb.rb:421:in `start'", "/home/eregon/.rubies/ruby-3.2.2/lib/ruby/gems/3.2.0/gems/irb-1.6.2/exe/irb:11:in `'", "/home/eregon/.rubies/ruby-3.2.2/bin/irb:25:in `load'", "/home/eregon/.rubies/ruby-3.2.2/bin/irb:25:in `
'"] irb(main):002:0> caller_locations(20) => [] ``` That implies it needs to count how many frames are available, which is inefficient. So we certainly wouldn't want that behavior for `each_caller_location` as it would ruin a significant part of its performance advantage. (we should probably also fix this for `caller_locations`, but that should be a separate ticket) Similarly the Range form is also problematic as it also requires iterating all the stack to find how many frames there are to know which frames `0..-2` should use. ---------------------------------------- Feature #20335: `Thread.each_caller_location` should accept the same arguments as `caller` and `caller_locations` https://bugs.ruby-lang.org/issues/20335#change-107264 * Author: byroot (Jean Boussier) * Status: Open ---------------------------------------- `Thread.each_caller_location` was added to Ruby 3.2 as part of [Feature #16663] and is a very useful API for emitting warnings with a proper source location and similar use cases. However in many of the cases where I used it, or seen it used, it was needed to skip the first, or a couple frames: Examples: Sorbet: https://github.com/Shopify/sorbet/blob/b27a14c247ace7cabdf0f348bfb11fdf0b7e9ab4/gems/sorbet-runtime/lib/types/private/caller_utils.rb#L6-L18 ```ruby def self.find_caller skiped_first = false Thread.each_caller_location do |loc| unless skiped_first skiped_first = true next end next if loc.path&.start_with?("= 1 frames_to_skip -= 1 next end # snipp... ``` ### Proposal I think it would be very useful if `Thread.each_caller_location` accepted the same arguments as `caller` and `caller_locations`: ```ruby #each_caller_location(start = 1, length = nil) #each_caller_location(range) ``` @jeremyevans0 what do you think? -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/