-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider code coverage (as a code generation technique) #557
Comments
To make this concrete, I also enjoyed how the test specifications are laid out: small code examples, checking coverage of lines/statements/functions/branches. Extra nice is that the focus is on the API-level expectations (BDD-style), and not on low-level implementation details. |
There's a clear connection here between the kind of "invisible code injection" we want to do here, and the one discussed in #417. I could even see cases where one would like to do both of them at once on the same code base (without coordinating or even being aware of each other, and getting the right result regardless of order). This maybe suggests some constraints on the shape of the API in question. |
I thought of another alluring example (which might belong in a separate issue, except it feels like it shares and highlights the same general technique): I have a private repository called The main point is to not change the code written without a visualization in mind. In fact, either instrumentation would work, or perhaps using a different evaluator. I'm undecided on which one is preferable; maybe each has its own advantages. Perhaps extra thought need to be spent to uphold the illusion of the instrumented code supporting the full gamut of debugging (such as "step into"), but still fully giving the impression of running the original code. In that sense, the instrumented code is invisible to the debugger. |
Just found this quote:
Feels relevant. |
The thing I would like to capture here is this: when we are authoring the instrumentation code, we are basically visiting the nodes of interest and injecting the non-invasive code. The most natural thing to do would probably be to just write the code we want, as |
This paper uses the code injection technique on quite an impressive scale: it injects pre- and post-conditions in the right place in the program. But then it also creates entire parallel pre/post class hierarchies to mirror the ones already in the program, in order to capture that method dispatch is late-bound; finally, if the pre- and post-conditions tested fail in a certain way that violates the Liskov substitution property, a "hierarchy error" is signaled at runtime. All of this is proven to have no semantic effect on the original program, as long as the pre- and post-conditions are themselves side effect free. |
From this HN discussion:
That's a funny/cynical way to put what this technique does. I feel though that there is (or ought to be) some kind of "safety property" involved, some kind of generalization of "injecting non-invasive code" described above. There's also a super-interesting kind of duality here between hijacking/modifying the evaluator (the runtime approach) and hijacking/modifying the source code (the static approach). |
Put it like this. Take the concept of "slicing", wherein you can turn a program into a smaller program by keeping only a subset of the variables in it. I think the AOP safety property can be expressed in terms of this: that the "original slice" of the program still behaves the same after the code injection — proximally, because the extending slice only does side-effect-free mutations to "private" data; gensym'd variables that the original slice has no way to see or interact with. |
I hadn't heard about Meta-AspectJ before, but it seems to be playing around in this issue's ballpark. |
I was just reading details of how Istanbul.js instruments source code to emit coverage information on a side channel, and it's pretty fascinating. (That file details how to go through a JavaScript compunit's AST and insert "counter increments" (per statement, function, and branch) — all without disrupting things like source code location, of course.)
There is something there which concerns us macro-aficionados. I would say the technique sits somewhere between a custom language, a custom backend, and full-program AST transformation. Also related somehow to the staged-languages discussion of #555.
The text was updated successfully, but these errors were encountered: