Feature assertions on embedded types

470 views
Skip to first unread message

Matt Joiner

unread,
Mar 7, 2015, 9:03:04 PM3/7/15
to golan...@googlegroups.com
I'm wrapping a http.ResponseWriter to track bandwidth use and peek at headers before they're sent. There's a helper function http.ServeContent that makes use of several extra optional methods on response writers, such as Flush, and via io.CopyN, ReaderFrom. For performance and transparency reasons it's desirable that my wrapper offer these functions when type assertions check for them. But their supposed existence depends on whether the wrapped response writer implements them. By using anonymous fields, it's possible to mix and optionally override the methods those fields types provide. However type assertions don't also pass through to the embedded fields. Here's an example: http://play.golang.org/p/t9AZNb1MiG. In the example, Eminem is stored as a poser, but he's actually the Real Slim Shady. But attempts to type assert him so don't work.

What are my options here? If my wrapper purports to implement methods that its embedded types *may* implement, I risk changing the behaviour of callers, and having to implement work arounds when the embedded types don't actually support something.

For a concrete example:

type wrapper struct {
  http.ResponseWriter
}

func (me wrapper) ReadFrom(src io.Reader) (int64, error) {
  if rf, ok := me.ResponseWriter.(io.ReaderFrom); ok {
    return rf.ReadFrom(src)
  }
  // ????
  return io.Copy(me.ResponseWriter, src)
}


Chris Hines

unread,
Mar 7, 2015, 9:31:41 PM3/7/15
to golan...@googlegroups.com
I haven't totally groked what you are trying to do, so forgive me if this doesn't help.


Your example hides the real value behind two levels of interface values. One where it is embedded in the eminem struct and the other where it is assigned to the realShady variable of type poser. As a result you need to perform two type assertions to dig it back out, or replace one of the interface values with a non-interface value.

Chris

Matt Joiner

unread,
Mar 7, 2015, 10:16:31 PM3/7/15
to Chris Hines, golang-nuts
Thanks for looking. Unfortunately neither help, since the user of my wrapper won't be asserting for, and doesn't care for the type of the wrapper. It's intended to be transparent, which is why it implements ResponseWriter in the first place.

--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/HKY3mI7Q2jY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

speter

unread,
Mar 7, 2015, 10:53:08 PM3/7/15
to Matt Joiner, Chris Hines, golang-nuts
If you only care about few extra methods (2-3), you can create (generate) wrappers for all combinations of them (2^n wrapper types in the worst case) and return the appropriate type based on the instance to be wrapped, but I'm guessing that's exactly what you're trying to avoid.

For a general solution reflect.MakeInterface could help but it's not implemented ( https://golang.org/issue/4146 ). That could allow proxying any and all methods, so consumers asserting for any interface could keep working. (Asserting for concrete types still wouldn't work and I don't see any way for making that work transparently in general.)

Peter


--
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...@googlegroups.com.

Matt Joiner

unread,
Mar 7, 2015, 11:19:44 PM3/7/15
to golan...@googlegroups.com, anac...@gmail.com, ggr...@cs-guy.com
Thanks, this comment precisely describes my problem: https://github.com/golang/go/issues/4146#issuecomment-66070605
Reply all
Reply to author
Forward
0 new messages