On Friday, November 8, 2019 at 7:16:42 PM UTC+1, Ian Lance Taylor wrote:
>
> On Fri, Nov 8, 2019 at 10:06 AM André Eriksson <ean...@gmail.com 
> <javascript:>> wrote: 
> > 
> > Interesting. Do you have a reference to where that happens? 
>
> The method (*Package).rewriteCall in cmd/cgo/gcc.go.  But more useful 
> might be to experiment with some cgo code and build with `go build 
> -work` and look in the $WORK directory to see the generated files. 
>
>
> > If i understand you correctly, however, it doesn't appear to solve the 
> case where the called function fn lives in a different package, and takes 
> an argument which is a private type. That is: 
> > 
> > -- a/a.go -- 
> > package a 
> > 
> > type myString string 
> > 
> > func Fn(str myString) { } 
> > 
> > -- b/b.go -- 
> > package b 
> > 
> > import "a" 
> > 
> > func rewrite() { 
> >     go a.Fn("some string") 
> > } 
> > 
> > In this example knowing the desired type from the function signature 
> does not help, I would think? 
>
> That is correct. 
>
> Fortunately for a case like that you don't need to use a temporary 
> variable at all, since the argument is a constant. 
>
> Ian 
>

That makes sense. I did some more research and came across another case 
where even this might not work.
It appears that there is a distinction between an untyped value and an 
untyped constant. I hadn't appreciated this distinction until now.

According to the spec (https://golang.org/ref/spec#Comparison_operators), 
"Comparison operators compare two operands and yield an untyped boolean 
value."
As a result, it's possible to get untyped, non-constant values from 
non-constant expressions.

So we could have fn(a() == b()) passed to fn(b myBool) with no ability to 
store this argument in a temporary variable without coercing the type to a 
regular typed bool.


>
> > On Friday, November 8, 2019 at 6:58:02 PM UTC+1, Ian Lance Taylor wrote: 
> >> 
> >> On Fri, Nov 8, 2019 at 9:08 AM André Eriksson <ean...@gmail.com> 
> wrote: 
> >> > 
> >> > That works in simple cases, but does not work when the expression is 
> an untyped constant, like 1 or nil. In the case of 1 the variable will get 
> a concrete type of int, while fn may accept a float32, or even a private 
> type that cannot be named in the current package. 
> >> 
> >> You might want to look at the rewriting that cmd/cgo does, as it 
> >> handles this exact kind of case.  Basically, for untyped constants, 
> >> you know the desired type, because it's in the function signature.  So 
> >> use that. 
> >> 
> >> It does get kind of complicated, though. 
> >> 
> >> Ian 
> >> 
> >> 
> >> > 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> 
> 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. 
> >> >>> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/golang-nuts/a92641f3-2eda-4d4a-ab02-d2b40e3bde75%40googlegroups.com.
>  
>
> >> >> 
> >> >> 
> >> >> 
> >> >> -- 
> >> >> Michael T. Jones 
> >> >> michae...@gmail.com 
> >> > 
> >> > -- 
> >> > 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. 
> >> > To view this discussion on the web visit 
> https://groups.google.com/d/msgid/golang-nuts/ec41a345-163f-4a8a-a24f-b868def081a0%40googlegroups.com.
>  
>
> > 
> > -- 
> > 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/0ff39043-4699-4f0b-a1c0-6c4ebc5eb208%40googlegroups.com.
>  
>
>

-- 
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/afb22234-ecb2-46b7-a5af-7a2ee4525774%40googlegroups.com.

Reply via email to