27 ms·
Interesting. Browsing the code it looks like they are using closures[1] in a way I haven't seen other Go code use them. Similar to the "using" keyword in .NET o
by howeyc 13y ago
Interesting. Browsing the code it looks like they are using closures[1] in a way I haven't seen other Go code use them. Similar to the "using" keyword in .NET or the "with-" macros (with-open-file) in Common Lisp.
[1] https://github.com/rackspace/gophercloud/blob/master/acceptance/04-create-server.go https://github.com/rackspace/gophercloud/blob/master/accepta...
- zemo 13y agoYou don't see it because it's not really idiomatic Go code. Another way to do this would be to define a type that is a function type, and then to put a method on that function type. Yes, functions can have methods in Go. This seems a bit odd at first, and it may not seem particularly important, but because a function can have a method, and an interface is just a method set, you can use a function to satisfy an interface. A more idiomatic way to accomplish the same thing would be to define the argument function as it's own type: type AccessFn func(gophercloud.AccessProvider) so now AccessFn describes any function that takes an AccessProvider as its sole parameter, and returns nothing. On this function type, define WithIdentity as a method (edited for brevity): func (fn AccessFn) WithIdentity(allowReauth bool) { acc, _ := gophercloud.Authenticate(...) fn(acc) } Inside of the function's method, you can invoke the function itself. Then you would define the actual AccessFn as some variable: fn := AccessFn(func(gophercloud.AccessProvider ) { // ... }) and then call its WithIdentity method: fn.WithIdentity(ar) And then, if you were so inclined, you could define an interface over your WithIdentity method, so that in whatever context you're in, anything that has a WithIdentity method will do. This often (but not always) leads to code that's a bit easier to read. Nested callbacks... not always the easiest to wrap your head around. shameless plug: I've written about this in more detail here, if this sort of thing interests you: http://jordanorelli.tumblr.com/post/42369331748/function-types-in-go-golang http://jordanorelli.tumblr.com/post/42369331748/function-typ...
- jnoller 13y agoI shot this to Samuel the current dev lead - thank you!
- kc5tja 13y agoGoodness, I'm confused. I'm going to need a lot of time to digest this. That said, much discussion about ideal way of writing Gophercloud happened on the #go-nuts IRC channel, and nobody objected to what I have now as being unidiomatic. You're the first! Deeply nested closures are definitely a problem, but I usually solve that by factoring closures out into top-level functions of their own. That said, one of Gophercloud's goals is to be as idiomatic as possible. Are you available on #go-nuts if I have questions? I'd like to play with this technique some more and get a feel for it before applying it to (and risk breaking) gophercloud's existing API.
- kc5tja 13y agoOh, I'm thick! I see what's happening now! The problem is it doesn't produce any gain in clarity for the purposes I'm using it for. I think for the acceptance tests, it's use is fine. I can see if it were part of the public API, there's an argument that an interface could be used, but even there, I'm not sure it'd aid readability. Semantically, however, they're of course identical.
- zemo 13y agoyeah, to be honest, it may have been eggregious of me to call how I did it idiomatic. There's a lot we just don't have idioms for. Anyway, callback chains tend to be uncommon; that's just one way to avoid it. There's a handful of ways you could write this. Generally if you can expose functionality through methods, things tend to work out better in the end since you can transition into interfaces more readily. I'm jordanorelli in #go-nuts.