How to send type as function argument

17,263 views
Skip to first unread message

aka.spin

unread,
Oct 21, 2010, 9:13:16 PM10/21/10
to golang-nuts
How to made something like:

type SomeType interface {
F func()
}

type SomeImpl struct {
Field string
}
func (s *SomeImpl) F() { return s.Field }

func NewVar(t SomeType) {
return new(t)
}

main () {
a := NewFunc(SomeImpl)
...
}

I'm really stuck.

jimmy frasche

unread,
Oct 21, 2010, 9:16:17 PM10/21/10
to aka.spin, golang-nuts
You need to send an instance of SomeImpl to NewVar/NewFunc. Types
aren't first-class values. To work with types you need to use the
reflect package.

nsf

unread,
Oct 21, 2010, 9:25:14 PM10/21/10
to golan...@googlegroups.com
On Thu, 21 Oct 2010 18:16:17 -0700
jimmy frasche <soapbo...@gmail.com> wrote:

> You need to send an instance of SomeImpl to NewVar/NewFunc. Types
> aren't first-class values. To work with types you need to use the
> reflect package.

Btw, it's an interesting topic. Why they are not the first class
values. Why can't we add a syntax sugar for "reflect" package. Syntax
allows us to pass types as function arguments (it is used in functions
like 'make' and 'new'). Therefore it would be nice to have implicit
conversion from a type identifier to the reflect.Type.

Because currently the only way to get a reflect.Type is through using
an interface. But interface is a value also, of course we can make a
zero pointer value and get a type we're interested in through it, but
why can't we have a syntax sugar for that?

Steven

unread,
Oct 21, 2010, 9:50:10 PM10/21/10
to nsf, golan...@googlegroups.com
The other annoying thing about reflect is that you need to dynamically determine information that is statically known at the call site, which adds a performance hit where it is completely unnecessary, as well as making it clunky to use.

aka.spin

unread,
Oct 21, 2010, 10:01:08 PM10/21/10
to golang-nuts


On 22 окт, 07:25, nsf <no.smile.f...@gmail.com> wrote:
> On Thu, 21 Oct 2010 18:16:17 -0700
>
If you are not hard, you can give a specific example? How expensive it
is
in terms of performance?

Russ Cox

unread,
Oct 21, 2010, 10:43:25 PM10/21/10
to nsf, golan...@googlegroups.com
> Btw, it's an interesting topic. Why they are not the first class
> values. Why can't we add a syntax sugar for "reflect" package. Syntax
> allows us to pass types as function arguments (it is used in functions
> like 'make' and 'new'). Therefore it would be nice to have implicit
> conversion from a type identifier to the reflect.Type.

When we fixed up the grammar to avoid needing
a symbol table during the parse, one of my goals
was to make make and new not special, exactly
so that we could pass types to other things in
the future, like the case you've mentioned or some
unspecified form of generics.

The real question is whether the argument would
be a runtime.Type or a reflect.Type. Why are there
two at all? Because runtime.Type doesn't have
methods, which made it easier to lay down as
pre-initialized data (as opposed to initialized by code)
and also didn't require tight coupling of reflect with
the language proper.

The next time we do reflect (and I'm sure there will
be a next time) it's definitely something I'd like to
consider. We are accumulating a number of
of functions that take "zero values" as a proxy for
getting the type.

Russ

roger peppe

unread,
Oct 22, 2010, 4:47:41 AM10/22/10
to r...@golang.org, nsf, golan...@googlegroups.com
On 22 October 2010 03:43, Russ Cox <r...@golang.org> wrote:
> The next time we do reflect (and I'm sure there will
> be a next time) it's definitely something I'd like to
> consider.  We are accumulating a number of
> of functions that take "zero values" as a proxy for
> getting the type.

Tthe problem with this, of course, is that you can't use this
method to pass an interface type.

I'd like to see first-class types more integrated. Here's one
possibility:

- Add a new basic type to represent a runtime type, say rtype,
comparable for equality.

- Add a built in function, say typeof, which would return the rtype for
a type or an expression.

- Add a function to reflect, say NewType, to create a reflect.Type
from an rtype, and a method in reflect.Type to return its rtype.

These changes would have minimal impact on the system (nothing outside
reflect and unsafe uses runtime.Type) and I think they'd feel quite
natural.

I think it's probably worth having an explicit operator to convert
from a type expression to an rtype, to save confusion between:

x := draw.Point

and:

x := draw.Point{}

I think:

x := typeof(draw.Point)

reads just fine, and it draws the reader's attention to the fact that there's
some runtime type shenanigans going on.

aka.spin

unread,
Oct 22, 2010, 2:24:27 PM10/22/10
to golang-nuts
Ok. I understand. I guess I'll rest from it somewhere for six months.
Until...

- Normal type interihance. Now for handling different nature of the
data that come from the same source I have come up with a strange
design with a lot of crutches. Yes I talk about normal classes. Go is
not functional language - without normal OO system it useless. The
closures do not solve the problem. And write lost of identical
functions like "New..." which differ by only a few characters is -
it's just stupid.

- Humane installation, assembly, testing and documenting system. Again
now I see lots of bash scripts that depends of system variables and
the phases of the moon.

- Normal and understandable packaging system.

Sorry for the criticism. Go is great language. Small footprint, great
speed, natural parallelism - because of all this, it became interested
for me. But, unfortunately, not in its present state.

Russ Cox

unread,
Oct 22, 2010, 2:36:16 PM10/22/10
to aka.spin, golang-nuts
> - Normal type interihance. Now for handling different nature of the
> data that come from the same source I have come up with a strange
> design with a lot of crutches. Yes I talk about normal classes. Go is
> not functional language - without normal OO system it useless.

I think you'll find that people disagree on exactly what OO means.
It doesn't have to mean type hierarchies and type inheritance.
Alan Kay famously once said "I invented the term Object-Oriented,
and I can tell you I did not have C++ in mind."

I doubt Go will ever have a C++/Java-style type hierarchy.
The interface idea is one of the core features of the
language. If you're not open to learning a new way to
think about programming, you're probably better off sticking
with C++ or Java or whatever you're currently using.

Russ

Michael Hoisie

unread,
Oct 22, 2010, 5:19:29 PM10/22/10
to golang-nuts
++1 on the idea of passing a type without having to do a reflection
lookup on an empty value. It would some of my API's a lot cleaner.

- Mike

Daniel Smith

unread,
Oct 22, 2010, 5:24:35 PM10/22/10
to Michael Hoisie, golang-nuts
I just pass a *MyType(nil) as an interface{}, seems to work well.
--
Daniel Smith
http://dailyjoseki.com/
http://www.schaumburggoclub.org/

aka.spin

unread,
Oct 22, 2010, 5:59:54 PM10/22/10
to golang-nuts
Oh. I'm open. Speed matters :) But interfaces NOT solve all problems.
Ok. Simple production problem: set of handlers for processing.

On first try (Paradigm implicit in the slides from http://golang.org/doc/GoCourseDay2.pdf):

package main

import "log"

type Handler interface {
Handle() // Calls Do()
Do()
}

// Base handler
type B struct {
Data string // Some variable data
}
func (b *B) Handle() {
b.Do()
}
func (b *B) Do() {
log.Print("B: ", b.Data)
}

// Child
type C struct {
B
}
func (c *C) Do() {
log.Print("C1: ", c.Data)
}

func main () {
h := &C{B{"data"}} // Why not &C{"data"}? If make embedding, lets
// do it in all ways.
h.Handle()
}

BANG! B.Handle() calls only B.Do() (from language spec)

2010/10/23 01:58:47 B: data

Second try from http://groups.google.com/group/golang-nuts/browse_thread/thread/7cc11e5324bfc39f/a87127871783769c.

package main

import "log"

type Handler interface {
Handle() // Calls Do()
Do()
}

// Base handler
type B struct {
self Handler
Data string // Some variable data
}
// Fake constructor
func (b *B) Init(data string) {
b.Data = data
}
func (b *B) Handle() {
b.self.Do()
}
func (b *B) Do() {
log.Print("B: ", b.Data)
}

// Child
type C struct {
B
}
// Need set self in each child
func (c *C) Init(data string) {
c.B.Init(data) // Call base fake constructor
c.self = c // set instance
}
func (c *C) Do() {
log.Print("C1: ", c.Data)
}
// Child
type C1 struct {
C
}
// Need set self in each child
func (c *C1) Init(data string) {
c.C.Init(data) // Call base fake constructor
c.self = c // set instance
}
func (c *C1) Do() {
log.Print("C2: ", c.Data)
}

func main () {
h := &C{}
h.Init("data1")
h.Handle()

h1 := &C1{}
h1.Init("data2")
h1.Handle()
}


Success!

"2010/10/23 02:08:45 C1: data1"
"2010/10/23 02:08:45 C2: data2"

Some frustrating code but works OK. It's not inheritance. It's
composition. And it's can be done by another (Go) way (I hope to
understand it):

package main

import "log"

type Doer interface {
Do(*Handle) // Calls Serv
Serv() // Service function
}

// Handler. Keeps data and runs Doer.Do()
type Handle struct {
Data string
D Doer
}
func (h *Handle) Handle(){
h.D.Do(h)
}

// Doer one. Not keeps any data.
// Calls other self methods only through Handle.D
type Do1 struct {}
func (d *Do1) Do(h *Handle) {
log.Print("Do1", h.Data)
h.D.Serv()
}
func (d *Do1) Serv() {
log.Print("Serv1")
}

type Do2 struct { Do1 }
func (d *Do2) Serv() {
log.Print("Serv2")
}

func main () {
h1 := &Handle{"data1", &Do1{}}
h2 := &Handle{"data2", &Do2{}}

h1.Handle()
h2.Handle()
}

Another win. Looks better, works faster, eats less memory:

2010/10/23 03:03:28 Do1data1
2010/10/23 03:03:28 Serv1
2010/10/23 03:03:28 Do1data2
2010/10/23 03:03:28 Serv2

But in these two examples lies a two traps.

First: &C{}, &C1{}, &Do1{}, &Do2{}. Why I say that Doer
implementations can't keep any data? There is no native way to write
function that makes instance based on type. Let us recall the title of
this discussion.

And second: h *Handle. If I want to duer worked with various handlers
and make Handler interface ...

...
type Handler interface {
Handle()
}
...
func (d *Do1) Do(h *Handler) {
log.Print("Do1", h.Data)
h.D.Serv()
}

... I received the following:

../src/main.go:22: cannot use h (type *Handle) as type *Handler in
function argument
../src/main.go:29: h.Data undefined (type *Handler has no field or
method Data)
../src/main.go:30: h.D undefined (type *Handler has no field or
method D)

In this step, Go-way leads into the abyss. As we see interfaces NOT
solve all problems. Sad but true.

So. At the end of looong post. Ok. No OO. But two things will make
life better:

- First - dynamic casting and "super" (first example). It certainly
set interfaces are not so mighty.
- And second - ability to store type in variable is the first thing
that comes to mind in absence of normal class system.

But if you know a better solution of the above examples, I'd be happy
to know it.
Message has been deleted

Steven

unread,
Oct 22, 2010, 6:43:47 PM10/22/10
to aka.spin, golang-nuts
Please read the language spec and effective go if you have not already done so.

Please also stop making extreme statements. They are invariably wrong, and stem from the fact that you do not know the language yet. They only detract from the discussion and put everyone (or at least me ;-)) in a bad mood. If something seems ridiculous to you at this point, its probably due to a lack of understanding rather than a flaw in the language.

Do not use pointers to interfaces. They are next to useless as they only point to an interface and cannot abstract values. Store a pointer in an interface.

Ie: this function signature:
func (d *Do1) Do(h *Handler)

should be
func (d *Do1) Do(h Handler)

If you want all values that implement Handler to have data, then add a "Data" method to Handler. If you only want a Do1 to have data, then use a type assertion to expose the Do1 (see below).

Go does have "dynamic casting". See:
And

Go can store a type in a variable. See
It isn't the most convenient thing, and the language designers are planning to redesign the reflection interface eventually, when they have time. But it works in most cases for now.

If you want help with any of these things, after making a reasonable shot of trying to understand them yourself, ask nicely, and people will be gladly help you :)

Finally, rather than writing code to try to emulate idioms in other languages, try to solve a more general problem, and see how you can solve it using go idioms (functions, composition, interface abstraction, concurrency, channel communication, reflection...)

PS - Effective go code rarely makes use of anything resembling a type hierarchy. Most problems do not require one, and it only adds unnecessary complexity. There are a few rare situations where you do need it, and it is possible to emulate it in Go in those cases, though they should be rare. Rather than trying to think in terms of "a this is a that is a this", think of what each thing does, and group related tasks into an interface. Use package functions or composition to share implementation where it is convenient to.

aka.spin

unread,
Oct 22, 2010, 8:19:53 PM10/22/10
to golang-nuts
Thanks. Now everything is much clearer.

On 23 окт, 04:43, Steven <steven...@gmail.com> wrote:
> >http://groups.google.com/group/golang-nuts/browse_thread/thread/7cc11...
> > .
> Please read the language spec <http://golang.org/doc/go_spec.html> and
> effective
> go <http://golang.org/doc/effective_go.html> if you have not already done
> so.
>
> Please also stop making extreme statements. They are invariably wrong, and
> stem from the fact that you do not know the language yet. They only detract
> from the discussion and put everyone (or at least me ;-)) in a bad mood. If
> something seems ridiculous to you at this point, its probably due to a lack
> of understanding rather than a flaw in the language.
>
> Do not use pointers to interfaces. They are next to useless as they only
> point to an interface and cannot abstract values. Store a pointer *in *an
> interface.
>
> Ie: this function signature:
> func (d *Do1) Do(h *Handler)
>
> should be
> func (d *Do1) Do(h Handler)
>
> If you want all values that implement Handler to have data, then add a
> "Data" method to Handler. If you only want a Do1 to have data, then use a
> type assertion to expose the Do1 (see below).
>
> Go does have "dynamic casting". See:http://golang.org/doc/go_spec.html#Type_assertions
> Andhttp://golang.org/doc/go_spec.html#Type_switches
>
> Go can store a type in a variable. Seehttp://golang.org/pkg/reflect

aka.spin

unread,
Oct 23, 2010, 6:13:43 AM10/23/10
to golang-nuts
> Go can store a type in a variable. Seehttp://golang.org/pkg/reflect
> It isn't the most convenient thing, and the language designers are planning
> to redesign the reflection interface eventually, when they have time. But it
> works in most cases for now.

Have mercy on me! How? I can't find any info about this.

Russ Cox

unread,
Oct 23, 2010, 11:07:07 AM10/23/10
to aka.spin, golang-nuts

The documentation is usually a good place to start:
http://golang.org/pkg/reflect/

From there you might see the name Typeof and go looking for example
uses: godoc -q Typeof or type Typeof in the search box in the upper right
corner of golang.org: http://golang.org/search?q=Typeof

Also, a Google web search for [go language reflect package] turns up:
http://bitsfromthomas.blogspot.com/2010/05/go-language-reflection-examples.html

Russ

aka.spin

unread,
Oct 24, 2010, 1:07:30 PM10/24/10
to golang-nuts
Good docs :) No examplest. You need something to do with each other
and your relationship to the community.
http://groups.google.com/group/golang-nuts/browse_thread/thread/c5dc1a44c5bff95a

On 23 окт, 21:07, Russ Cox <r...@golang.org> wrote:
> Also, a Google web search for [go language reflect package] turns up:http://bitsfromthomas.blogspot.com/2010/05/go-language-reflection-exa...
>
> Russ

gab...@soundtrackyourbrand.com

unread,
Jul 10, 2015, 6:50:01 AM7/10/15
to golan...@googlegroups.com, hoi...@gmail.com
On Friday, October 22, 2010 at 11:24:35 PM UTC+2, Daniel Smith wrote:
I just pass a *MyType(nil) as an interface{}, seems to work well.

Thanks for the tip! Simplest way to pass type info that I've seen so far.

But if someone finds this and wonders why you get error "cannot convert nil to type MyType" it's because it should be written like (*MyType)(nil).


--
Gabriel Falkenberg
Reply all
Reply to author
Forward
0 new messages