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.

Reply via email to