Following Jose Valim's response regarding proposal posted in elixir-lang-core earlier today, I'm publishing an issue here (mostly it's a copy-paste).
It's already possible to break on a function with a particular arity:
IEx.Pry.break(Ecto.Repo.Schema, :dump_field!, 6, 100)
But usually during debugging I'm waiting for a specific argument to be passed to a function, so ideally I'd like to do this:
IEx.Pry.break(Ecto.Repo.Schema, :dump_field!, [:_, :_, :_, :birth_date, ~D[1996-12-12], :_])
Right now every time I get to the break point, I check if the field is :birth_date, and the date is the one I'm interested in. If they are not – I move on to the next break point via continue. It is a manual process, so I wonder if it make sense (and also whether it is technically possible) to break by matching on argument values.
Would it make sense to support something similar to tracing match specs? If we ever have support for tracing in Elixir itself, we'd probably want to have the same syntax for both.
Would it make sense to support something similar to tracing match specs?
It would be exceedingly nice to get a matchspec generator built-in into Elixir, it would be quite useful to generate AST from.
@michalmuskala forgive me my ignorance, what are the tracing match specs?
@gmile http://erlang.org/doc/apps/erts/match_spec.html
It is a standard of defining a way to specify a 'match', with the shape, guards, and return 'value' and all. The 'raw' syntax is pretty low level but erlang has helpers that make is blissful to use. It is used in tracing, ets, and more.
@OvermindDL1 oh I knew about match specs, but didn't know they had anything to do with tracing. Thank you!
I think breaking on a match_spec as suggested above would be an essential way of implementing this.
I've been looking at the code and so far see several routes to start tackling this:
add IEx.Pry.break_on_matchspec/4, and treat breaking on match_spec completely separately from current IEx.Pry.break/4 implementation,
change IEx.Pry.break/4 implementation, so that it accepts both arity number (as it is right now) and now also a list of match_specs. Then there are two ways to go from here:
match_spec and arity in separate branches of code (where it makes sense) – the underlying support for match_spec would be no different than in item 1 above, orconvert arity into a simplest match_spec list of form:
[{:erlang.make_tuple(arity, :"_"), [], []}]
somewhere during IEx.Pry.break/4 itself, and then refactor the code path from break down to instrument_definition to always operate on a match_spec.
This is off the top of my head, and not thought our thoroughly yet. There are likely blockers that I have not thought of.
I'm in favor of the 2.2 option, as it will consolidate both approached into the same code. I suspect breaks function would have to be changed to list match_specs too. Taking 2.2 route, it might be easier to just list all match_specs (including the simple "arity match_spec") waiting to be tested on each function call.
@josevalim what do you think? If none of the above options looks good, how do you see match_specs making it into debug?
@gmile I don't think we need to introduce the complexity of match_spec. Because everything is done at compilation time, we can just take the user AST and inject that directly into the code.
So if someone writes:
break! URI.decode_query(_, %{})
or even:
break! URI.decode_query(_, map) when map_size(map) > 0
we could inject a clause inside the breakpoint that looks like this:
def decode_query(original_arg1 = arg1, original_arg2 = arg2) do
case {arg1, arg2} do
{_, map) when map_size(map) > 0 ->
# check the breakpoint as today
_ -> :ok
end
# rest of the implementation
end
The tricky part is more related to silencing warnings and making sure we raise proper errors if the breakpoint is malformed.
Most helpful comment
@gmile http://erlang.org/doc/apps/erts/match_spec.html
It is a standard of defining a way to specify a 'match', with the shape, guards, and return 'value' and all. The 'raw' syntax is pretty low level but erlang has helpers that make is blissful to use. It is used in tracing, ets, and more.