I tried to explain why that does not work in the general case. Specifically, that coerces expr to take a concrete type. The constant 1 would become int, while fn might take a float32 or even a private type that cannot be named in the package being rewritten. It would similarly fail if expr is untyped nil.
On Friday, November 8, 2019 at 5:51:10 PM UTC+1, Michael Jones wrote: > > If expr was evaluable in the original code then why not rewrite in place > after assigning temporaries? > > go fn(e1,e2) > > { > t1,t2 := e1,e2 > go func() { > defer instrument() > fn(t1,t2) > } > > > On Fri, Nov 8, 2019 at 8:38 AM André Eriksson <ean...@gmail.com > <javascript:>> wrote: > >> I am working on a type of Go preprocessor that rewrites source code to >> add additional instrumentation to certain types of statements. >> >> One such statement is the go statement. I would like to instrument the >> newly created goroutine, injecting some instrumentation code at the start >> and finish of the goroutine. >> >> In the simple case, the rewrite is straightforward: >> >> go fn() >> >> becomes >> >> go func() { >> defer instrument()() >> fn() >> }() >> >> However this approach does not work when fn takes parameters. >> If we were to rewrite go fn(expr) into the equivalent form above: >> >> go func() { >> defer instrument()() >> fn(expr) >> }() >> >> >> the semantics change, since in the rewrite expr gets evaluated inside >> the newly created goroutine, which can change the behavior and introduce >> data races. >> >> My attempts to address this have not been particularly fruitful. >> >> One cannot pass in expr as an argument to the closure, because the type >> of the expression may not have a valid name in the current package (for >> example if expr evaluates to a private type in some other package). >> >> Similarly, if expr is a constant expression (like 1 or nil) the type may >> depend on the corresponding parameter in fn’s signature. >> >> The only semantics-preserving rewrite I can think of revolves around >> using package reflect, and rewriting like so: >> >> go func(fn reflect.Value, vals …reflect.Value) { >> defer instrument() >> fn.Call(vals) >> }(reflect.ValueOf(fn), reflect.ValueOf(expr)) >> >> As far as I understand, this should be semantics-preserving, although >> with a slight performance cost. (Though I imagine the cost of a >> reflection-based call is dwarfed by the cost of spawning a goroutine.) >> >> Unfortunately this also comes with a major downside: the rewritten code >> does not typecheck identically to the original code. Ideally I would like >> the rewritten form to cause identical typechecking failures to the old >> code, so that these errors are caught at compile time without requiring a >> separate typechecking pass for the original code. >> >> Am I correct in the above reasoning? Can anyone think of a way to do this >> sort of rewrite in a semantics-preserving and typechecking-preserving way? >> >> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golan...@googlegroups.com <javascript:>. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/a92641f3-2eda-4d4a-ab02-d2b40e3bde75%40googlegroups.com >> >> <https://groups.google.com/d/msgid/golang-nuts/a92641f3-2eda-4d4a-ab02-d2b40e3bde75%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > > > -- > > *Michael T. jonesmichae...@gmail.com <javascript:>* > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/67118711-d7c7-4ea0-9260-1ff50f38cf43%40googlegroups.com.