How can I add functions to an existing type?

18,891 views
Skip to first unread message

Estiedi

unread,
Jul 1, 2011, 5:18:13 AM7/1/11
to golang-nuts
Hi,

I'm having trouble with understanding how I can add functions to an
existing type.

More concrete, I'm using os.FileInfo in a program that needs to
compare files.

First I tried:

type MyFileInfo FileInfo

This creates me a new type MyFileInfo to which I can add a function
Compare.

But how do I now create an instance of this type based on a real
FileInfo object returned by os.Stat() ?

Or should I better create a new type and embed the FileInfo in it?

type MyFileInfo struct{
*FileInfo
}

Now I can instantiate MyFileInfo with:

fi, _ := os.Stat("/some/file/path")
mfi := &MyFileInfo{fi}

However since I have no need to add other fields than FileInfo to the
struct, I found the first way cleaner.


Thanks,


Estiedi

Peter Bourgon

unread,
Jul 1, 2011, 5:29:59 AM7/1/11
to Estiedi, golang-nuts
> I'm having trouble with understanding how I can add functions to an
> existing type.

You "cannot define new methods on non-local type[s]," by design.

The best practice is to embed the non-local type into your own own
local type, and extend it. Type-aliasing (type MyFoo Foo) creates a
type that is (more-or-less) completely distinct from the original. I'm
not aware of a straightforward/best-practice way to use type
assertions to get around that.

John Meinel

unread,
Jul 1, 2011, 5:34:57 AM7/1/11
to Estiedi, golang-nuts

You can only add functions to types in the package where they are defined.

So you can't extend OS stuff.
John
=:->

Estiedi

unread,
Jul 1, 2011, 7:03:38 AM7/1/11
to golang-nuts
Oh, I didn't know that.

From the Effective Go tutorial on http://golang.org/doc/effective_go.html,
I got the idea it was possible because they do it all the time:

type Sequence []int

// Method for printing - sorts the elements before printing
func (s Sequence) String() string {
sort.IntArray(s).Sort()
return fmt.Sprint([]int(s))
}

type ByteSlice []byte

func (slice ByteSlice) Append(data []byte) []byte {
// Body exactly the same as above
}

type Vector []float64

// Apply the operation to v[i], v[i+1] ... up to v[n-1].
func (v Vector) DoSome(i, n int, u Vector, c chan int) {
for ; i < n; i++ {
v[i] += u.Op(v[i])
}
c <- 1 // signal that this piece is done
}

I only notice now that they only do it on slices of build-in types
([]int,[]byte, []float64).So, this is only possible on build-in types
then?
For all other purposes one must make a struct?

Thanks for your help.

Estiedi

On Jul 1, 11:34 am, John Meinel <j...@arbash-meinel.com> wrote:
> You can only add functions to types in the package where they are defined.
>
> So you can't extend OS stuff.
> John
> =:->

Frits van Bommel

unread,
Jul 1, 2011, 7:24:16 AM7/1/11
to Estiedi, golang-nuts
On 1 July 2011 11:18, Estiedi <dirk.est...@gmail.com> wrote:
> I'm having trouble with understanding how I can add functions to an
> existing type.
>
> More concrete, I'm using os.FileInfo in a program that needs to
> compare files.
>
> First I tried:
>
> type  MyFileInfo FileInfo
>
> This creates me a new type MyFileInfo to which I can add a function
> Compare.
>
> But how do I now create an instance of this type based on a real
> FileInfo object returned by os.Stat() ?

Just convert it:
MyFileInfo(fi)
<http://golang.org/doc/go_spec.html#Conversions>

Note that os.Stat() returns a *os.FileInfo, so it might be easier to
instead define MyFileInfo as
type MyFileInfo *os.FileInfo
.

Estiedi

unread,
Jul 1, 2011, 9:17:04 AM7/1/11
to golang-nuts
type MyFileInfo *os.FileInfo

doesn't work for me, because when I try to define a function on it I
get "Invalid receiver type MyFileInfo (MyFileInfo is a pointer type)"
That sounds reasonable to me.

However this:

type MyFileInfo os.FileInfo

func NewMyFileInfo(filename string) (*MyFileInfo) {
fi, _ := os.Stat(filename)
tmp := MyFileInfo(*fi)
return &tmp
}

func (mine *MyFileInfo) Compare(other *MyFileInfo) bool{....}

is exactly what I wanted and works like a charm!

Thanks a lot, Frits!
And thanks again for omitting "RTFM". ;-)

Estiedi
On Jul 1, 1:24 pm, Frits van Bommel <fvbom...@gmail.com> wrote:

Steven Blenkinsop

unread,
Jul 1, 2011, 12:49:32 PM7/1/11
to Estiedi, golang-nuts
On Friday, July 1, 2011, Estiedi <dirk.est...@gmail.com> wrote:
> type MyFileInfo *os.FileInfo
>
> doesn't work for me, because when I try to define a function on it I
> get "Invalid receiver type MyFileInfo (MyFileInfo is a pointer type)"
> That sounds reasonable to me.
>
> However this:
>
> type MyFileInfo os.FileInfo
>
> func NewMyFileInfo(filename string) (*MyFileInfo) {
>     fi, _ := os.Stat(filename)
>     tmp := MyFileInfo(*fi)
>     return &tmp
> }
>
> func (mine *MyFileInfo) Compare(other *MyFileInfo) bool{....}
>
> is exactly what I wanted and works like a charm!

This works, as long as you don't mind stripping all the methods off
os.FileInfo (you can always access them with a type conversion, but
that might be inconvenient). If you want to have all the methods on
one type, just use the embedding approach. Don't worry about having a
struct with only one field, the struct doesn't carry any overhead.
Then, you don't need to use a *MyFileInfo, since it's already
effectively a pointer. Just define methods on, and pass around,
MyFileInfo directly. I find the embedding cleaner to use (if you care
about the old methods), since it saves you most conversions, and on
the few occasions you *do* have to convert, it's not syntactically
heavier, it's actually syntactically lighter:

Rasmus Schultz

unread,
Dec 8, 2013, 11:11:52 AM12/8/13
to golan...@googlegroups.com
am I missing something here?

just learning Go, and I was under the impression that one of the key reasons for the "detached" method-declaration syntax, was that you would be able to extend somebody else's type with new methods required by your program, in a "non-invasive" manner.

so you can't add methods to a type unless it was declared in the local package, is that right?

what exactly is the point of the detached method-declarations then?

in deed this throws my whole impression of the object model into question... is it really as flexible as I thought it was at first glance?

- Rasmus

Michael Jones

unread,
Dec 8, 2013, 11:30:11 AM12/8/13
to Rasmus Schultz, golang-nuts
It is flexible but not universal; what is missing was omitted purposefully. 

A type's methods are in the package that defines it. 

This is a logical coherence. It is a compilation virtue. It is seen as an important benefit for large-scale maintenance and multi-person development projects.

The power you speak of is not lost, though, because you can embed the base type in a new type as described above and add whatever you want to it, in the kind of functional "is a" that you seek, with the only caveat that your new type must have a new name, and all of its fields and methods must be in its new package.

It seems to work well in practice. Try it and see if it does not quickly become comfortable to you. If nothing else, the speedy implicit building and lack of weak-symbol magic will certainly be comfortable. ;-)


--
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.
For more options, visit https://groups.google.com/groups/opt_out.



--
Michael T. Jones | Chief Technology Advocate  | m...@google.com |  +1 650-335-5765
Reply all
Reply to author
Forward
0 new messages