Casting channel's secondary type

1,351 views
Skip to first unread message

Petar Maymounkov

unread,
Dec 9, 2011, 1:56:52 AM12/9/11
to golan...@googlegroups.com
I ran into an interesting use case, which prompted me to think that
one should be able to statically and explicitly convert, say, "chan time.Time" 
to "chan int64"

The function time.After(d) returns a "<-chan time.Time" which send the current
time after attempting to wait for a given duration.

I need to make a "helper" type that gives access to time functionality, while
respecting the interface specification of some third-party code.

In particular, this interface requires that the signature for After be:

After(d int64) <-chan int64

One is tempted to implement the wrapping method as follows:

func After(d int64) <-chan int64 {
  return (<-chan int64)(time.After(time.Duration(d)))
}

This is not possible because you cannot cast "<-chan time.Time" to "<-chan int64".
This seems like an odd restriction seeing how we can downcast "time.Time" to "int64".

Without this cast, implementing the After wrapper requires forking a new goroutine
and so forth. Not pleasant.

Comments?

David Symonds

unread,
Dec 9, 2011, 2:06:02 AM12/9/11
to golan...@googlegroups.com
time.Time is not an int64. It's a struct with three fields. What
possible semantic meaning could casting a chan time.Time to a chan
int64 have?


Dave.

Petar Maymounkov

unread,
Dec 9, 2011, 2:10:30 AM12/9/11
to David Symonds, golan...@googlegroups.com
I am sorry. The example is flawed, but what I really wanted to say is that
you cannot cast:

chan time.Duration

to

chan int64

And that seems should be possible.

--Petar

David Symonds

unread,
Dec 9, 2011, 2:24:42 AM12/9/11
to Petar Maymounkov, golan...@googlegroups.com
On Fri, Dec 9, 2011 at 6:10 PM, Petar Maymounkov <pe...@csail.mit.edu> wrote:

> And that seems should be possible.

Perhaps, but it's still a bit contrived. There's nothing in the time
package that gives you a chan time.Duration either.


Dave.

Petar Maymounkov

unread,
Dec 9, 2011, 2:30:15 AM12/9/11
to David Symonds, golan...@googlegroups.com
Yes, I was confused about the time package (my mistake).
However, I realized generally that the situation is plausible:

You have a function like

func F() chan T

where T is a type defined as

type T Q (or maybe as type struct { Q })

for Q some other type.

You should be able (it seems) to convert

chan T to chan Q

since you are downgrading the type (meaning) of the channel messages,
and there is nothing logically wrong with that.

I was just noting that if you don't allow this. You would have
to start a new goroutine that converts messages upon reception
and sends them to a different channel. Seems clunky.

P

Rob 'Commander' Pike

unread,
Dec 9, 2011, 2:36:05 AM12/9/11
to Petar Maymounkov, David Symonds, golan...@googlegroups.com
You can't change a *T to a *Q either.

-rob

John Asmuth

unread,
Dec 9, 2011, 9:29:50 AM12/9/11
to golan...@googlegroups.com, Petar Maymounkov, David Symonds

Rob 'Commander' Pike

unread,
Dec 9, 2011, 10:06:02 AM12/9/11
to golan...@googlegroups.com, Petar Maymounkov, David Symonds

On Dec 9, 2011, at 6:29 AM, John Asmuth wrote:

I admit to being surprised by that; I didn't think that would work.

So let me try again: You can't convert a []int to a []X. http://play.golang.org/p/PenyWj0pMe

-rob

roger peppe

unread,
Dec 9, 2011, 10:30:44 AM12/9/11
to Rob 'Commander' Pike, golan...@googlegroups.com, Petar Maymounkov, David Symonds
On 9 December 2011 15:06, Rob 'Commander' Pike <r...@google.com> wrote:
>
> On Dec 9, 2011, at 6:29 AM, John Asmuth wrote:
>
>> You can't?
>>
>> http://play.golang.org/p/aEkJIMKxUg
>
> I admit to being surprised by that; I didn't think that would work.

"A non-constant value x can be converted to type T in any of these cases: [...]
x's type and T are unnamed pointer types and their pointer base types
have identical underlying types."

it can be a useful technique - here's an example from the Go source:
http://weekly.golang.org/src/pkg/sync/rwmutex.go#L87

roger peppe

unread,
Dec 9, 2011, 10:37:40 AM12/9/11
to Rob 'Commander' Pike, golan...@googlegroups.com, Petar Maymounkov, David Symonds

although looking at that code, i think the following is probably clearer,
and with struct equality allowed, it doesn't even change the
comparison semantics:

func (rw *RWMutex) RLocker() Locker {
return rlocker{rw}
}

type rlocker struct {
m *RWMutex
}

func (r rlocker) Lock() { r.m.RLock() }
func (r rlocker) Unlock() { r.m.RUnlock() }

John Asmuth

unread,
Dec 9, 2011, 10:41:23 AM12/9/11
to golan...@googlegroups.com, David Symonds
On Friday, December 9, 2011 2:30:15 AM UTC-5, Petar Maymounkov wrote:

I was just noting that if you don't allow this. You would have
to start a new goroutine that converts messages upon reception
and sends them to a different channel. Seems clunky.


Not only is it a bit "clunky" (subjectively, and I don't actually agree), but it is semantically different. Channels with buffers simply behave differently than channels without - you can no longer use it as a synchronization tool.


Kyle Lemons

unread,
Dec 9, 2011, 1:28:29 PM12/9/11
to Rob 'Commander' Pike, golan...@googlegroups.com, Petar Maymounkov, David Symonds
I admit to being surprised by that; I didn't think that would work.

Yeah.  I was surprised too.  Luckily, I learned about it before I had to write protobuf code.  I wind up needing that little bit of magic way more often than I would like.

Rob 'Commander' Pike

unread,
Dec 9, 2011, 1:30:54 PM12/9/11
to Kyle Lemons, golan...@googlegroups.com, Petar Maymounkov, David Symonds
It's there to make conversions work for method sets with pointer receivers.

-rob

Petar Maymounkov

unread,
Dec 9, 2011, 3:06:26 PM12/9/11
to Rob 'Commander' Pike, Kyle Lemons, golan...@googlegroups.com, David Symonds
OK, so if you have the definition

type X int

then you can't convert

[]X to []int

or

chan X to chan int

using the current compiler. Agreed.

My question was more of a language design question:
Why shouldn't we be able to?
If you were to allow it, would that break anything else in the language design?

In the case of chan X to chan int, you could take the clumsy approach
and implement a go routine which proxies between the two channels. And then
argue that it is the compiler optimizer's job to get rid of one of the
goroutines.

But then this argument would not apply to the case []X to []int. Since the only
way to make the cast within the language (without using unsafe)
would be to copy the array, or to
convert the elements one at a time, when you use them individually.
Both of which, seem "clunky" as well.

P

Russ Cox

unread,
Dec 9, 2011, 3:20:01 PM12/9/11
to Petar Maymounkov, Rob 'Commander' Pike, Kyle Lemons, golan...@googlegroups.com, David Symonds
You used to be able to do this conversion as
long as everything was the same shape in memory,
but it made for fragile code, because there is an
implicit assumption in any conversion from []int to []X
that X is actually int underneath. Most of the time
that is not a good assumption to make, especially
in large programs where you can't keep everything
in your head.

We allow the conversion in two cases:
1. When T and U have identical definitions, can convert T <-> U.
2. When T and U have identical definitions, can convert *T <-> *U.

Both of these are allowed so that the method set can be
controlled, as Rob pointed out. If not for method sets,
even those would not be allowed.

In general I think a better solution to your specific
problem is to make the code agree on what to call
the type.

Russ

Steven Blenkinsop

unread,
Dec 9, 2011, 5:21:11 PM12/9/11
to r...@golang.org, Petar Maymounkov, Rob 'Commander' Pike, Kyle Lemons, golan...@googlegroups.com, David Symonds
On Fri, Dec 9, 2011 at 3:20 PM, Russ Cox <r...@golang.org> wrote:
Both of these are allowed so that the method set can be
controlled, as Rob pointed out.  If not for method sets,
even those would not be allowed.

Almost seems like types and method sets should be separate things... the Go compromise seems simpler somehow though. Too late for that at this point anyways.
Reply all
Reply to author
Forward
0 new messages