Why do interfaces not define properties / fields?

12,003 views
Skip to first unread message

tomwilde

unread,
May 9, 2012, 4:17:34 PM5/9/12
to golan...@googlegroups.com
Let me start by saying that I understand where interfaces come from (what they are good for in OOP) and how they are very different in Go.
And exactly because Go interfaces break the traditional notion of interfaces, wouldn't it be acceptable and even practical to allow them to have fields?

Take for instance, the http.ResponseWriter interface type; it has a method called .Header() which just returns the underlying http.Header from the object. It servers purely as an accessor.
Wouldn't it make sense to allow a interface to also define fields that a type has to have in order to implement the interface?
In the http.ResponseWriter example, we could avoid the need for the accessor method, and spare some overhead.

I would really like to read the opinion of one of the core developers, if any happened to stumble upon this thread.

tomwilde

unread,
May 9, 2012, 4:19:58 PM5/9/12
to golan...@googlegroups.com
PS: This question applies only for user types defined with an underlying struct type I guess.

Jan Mercl

unread,
May 9, 2012, 4:29:13 PM5/9/12
to tomwilde, golan...@googlegroups.com
On Wed, May 9, 2012 at 10:19 PM, tomwilde <sedevel...@gmail.com> wrote:
PS: This question applies only for user types defined with an underlying struct type I guess.

I think you have actually just found the answer by yourself. Allowing properties would in effect narrow usability of some interfaces to struct{...} only types (or pointers to such types). But one can find in real usage scalar types satisfying specific interfaces. And even

type T struct{} // not really memory hungry

can have methods attached in Go due to the no-data rule of interfaces in Go. Another neat trick really used is like:

type F func(...)

func (f F) foo(...) ... {} // yes, functions (fn types) can have methods!

Would be a pity to lose such nice things ;-)

Kyle Lemons

unread,
May 9, 2012, 4:31:55 PM5/9/12
to tomwilde, golan...@googlegroups.com
I am not a core developer, but it just doesn't make sense.  Interfaces are about behaviors, not about data.  Yes, a "behavior" can be that there is some associated data like the Header(), but not only would adding "fields" to interfaces break the behavioral nature of interfaces (and be very difficult to implement; the compiler would almost have to generate its own accessors and stick them in the vtable) but it would only work for struct-backed concrete values.  I frequently use empty- or basic-type-backed types on which I can define methods to satisfy interfaces, especially in tests, and this would make that impossible.

Ian Lance Taylor

unread,
May 9, 2012, 4:34:02 PM5/9/12
to tomwilde, golan...@googlegroups.com
The idea has arisen on the mailing list several times.

Interfaces are about methods. Permitting them to have fields is
essentially equivalent to having a getter and setter method. It makes
the language more complex for little gain. With the current compiler,
getter and setter methods should be inlined, so there is no real
efficiency issue here.

If you write your structs with an anonymous embedded struct that has the
fields and the getter and setter methods you want, you will get the
effect of interface fields with little extra work on your part.

Ian

John Asmuth

unread,
May 9, 2012, 7:24:39 PM5/9/12
to golan...@googlegroups.com, tomwilde


On Wednesday, May 9, 2012 4:34:02 PM UTC-4, Ian Lance Taylor wrote: With the current compiler, 
getter and setter methods should be inlined, so there is no real
efficiency issue here.

Since the call is being made on an interface, I feel like the inlining can't happen.

Darren Grant

unread,
May 10, 2012, 3:10:36 AM5/10/12
to John Asmuth, golan...@googlegroups.com, tomwilde
It is possible for many compilers to deduce whether or not a virtual
call site can be safely reduced to an inline expression. This doesn't
mean that it should be done however.
Message has been deleted

Ian Lance Taylor

unread,
May 10, 2012, 3:02:55 PM5/10/12
to John Asmuth, golan...@googlegroups.com, tomwilde
Good point. Forgot about that.

Of course the field access is not so simple either. Adding a field to
an interface doesn't imply that the field is at the same offset in every
type that satisfies the interface. So the interface would have to
record an offset somehow, and the code would have to retrieve the offset
in order to fetch the field.

Ian

Peter Nguyen

unread,
Dec 25, 2013, 3:56:58 AM12/25/13
to golan...@googlegroups.com, tomwilde
Sorry for bringing up an old thread but where can I find the other discussion about this? Has done a search but came up with nothing...

Anyway, I also like the idea of having interfaces that define fields because it will effectively eliminate many use cases for generics and the reflect package. Getters and setters are pointless on exported fields and just add noise and ambiguity to both code and documentation.

Tamás Gulácsi

unread,
Dec 25, 2013, 6:29:41 AM12/25/13
to golan...@googlegroups.com
How is an exported/interface field more than a getter and a setter method in the interface?

Peter Nguyen

unread,
Dec 25, 2013, 10:30:55 AM12/25/13
to golan...@googlegroups.com
It's not that it's more, it just doesn't make sense to have a setter/getter for an exported field as you then introduce ambiguity when you allow multiple ways to access that field. Someone else who interact with that code will wonder which way to do it... It only make sense if the field is unexported.

Kamil Kisiel

unread,
Dec 25, 2013, 10:30:02 PM12/25/13
to golan...@googlegroups.com, tomwilde
Conceptually an interface is a kind of behavioural contract a type can satisfy. It says tells you that you can perform certain operations on a value and that those operations will obey certain properties that are set out in the interface definition. For example fmt.Stringer defines a method that will return a string representation of a value. While having fields in an interface may seem convenient to you as a programmer it doesn't really fit with the concept of interfaces. Fields are data, not behaviour.

Peter Nguyen

unread,
Dec 26, 2013, 4:16:56 AM12/26/13
to golan...@googlegroups.com, tomwilde
It's the contract part that makes it interesting to include fields to an interface. Because it means that your functions/methods can accept an object that satisfy an interface so that it has the required fields to be manipulated:

type DataObject interface{
  Id string
}

func Create(object DataObject) {
  object.Id = "123"
}

vs

type DataObjectAccessor interface {
  GetId() string
  SetId(id string)
}

func Create(da DataObjectAccessor) {
  da.SetId("123")
}

Notice the ambiguity with getters/setters because in another function somewhere else you can do this instead:
func Foo(object DataObject) {
  object.Id = "123"
}

As Go's interface concept is not like any other languages, it shouldn't be too shocking to include such a feature.

Carlos Castillo

unread,
Dec 26, 2013, 7:40:37 AM12/26/13
to golan...@googlegroups.com, tomwilde
It is possible to define methods on any type, including non-structs. By allowing fields in interface declarations it would be impossible to have a non-struct type be able to satisfy such an interface. A non-struct type can still have "accessor" methods, and thus is able to satisfy all possible interfaces that can exist now.

Peter Nguyen

unread,
Dec 26, 2013, 10:02:22 AM12/26/13
to golan...@googlegroups.com, tomwilde
For me it would be acceptable that only struct types can satisfy an interface with fields. If you define an interface without fields, it should still be satisfiable by non-structs

Cao Nguyên

unread,
Dec 26, 2013, 10:55:58 AM12/26/13
to golan...@googlegroups.com, tomwilde
I don't see the ambiguity since DataObject and DataObjectAccessor are two differernt type.
If there is an ambiguity it must because you already have an idea that "the underlying type of DataObjectAccessor allways be DataObject".

Peter Nguyen

unread,
Dec 26, 2013, 11:27:02 AM12/26/13
to golan...@googlegroups.com, tomwilde
To clarify the ambiguity:

type DataObject struct {
  Id string
}

func (d *DataObject) SetId(id string) {
  d.Id = id
}

var do DataObject
do.Id = "123"
do.SetId("456")

Rodrigo Kochenburger

unread,
Dec 26, 2013, 11:35:32 AM12/26/13
to Peter Nguyen, golan...@googlegroups.com, tomwilde
One of the main ideas of interfaces is to promote less coupling and it does that buy creating behavior dependencies vs structural dependency. When using interface, you want something that can *do* something, hiding away the internals. Fields are internal state of the object and it exposes too much of how the implementation is built, even getters and setters IMO are not good on interfaces, cause they also leak the internal structure information.



- RK


--
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.

Peter Nguyen

unread,
Dec 26, 2013, 11:56:54 AM12/26/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde
Well yes, even more of a reason to allow fields in interfaces as it will decouple your dependencies as I see it. You no longer have to pass a specific type of struct, but you can pass one that only satisfy an interface. The alternative is to use reflect or getters/setters...

Rodrigo Kochenburger

unread,
Dec 26, 2013, 12:17:45 PM12/26/13
to Peter Nguyen, golan...@googlegroups.com, tomwilde
The fact that you're exposing/requiring implementation structure to be of a type struct with a specific field definitely makes it *more* coupled. When working with Interfaces you don't want to assume anything about the implementation which is why using reflection to access internal fields depending on the type pretty much throws away the real benefits of interface as well.

I think what is missing for you is a behavior oriented approach when dealing with interfaces, along the lines of the "Tell, don't ask" idea. You don't ask the object for data and act on it, you tell the object to act on it. It enforces better encapsulation which leads to better design. This way you end-up with smaller interfaces, less knowledge about internals of the implementations, which leads to more maintainable code and implementations that can evolve without breaking the rest of the app and with components that can be easily replaced/swapped by another one.

A good example is the sort package. By requiring a Swap method, it's the implementation job to know how to swap values which not only allows to sort different values but also makes it not dependent on the underlying storage structure. It could easily be an slice or a linked list or anything you want.

- RK

Peter Nguyen

unread,
Dec 26, 2013, 2:07:23 PM12/26/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde


Den torsdagen den 26:e december 2013 kl. 18:17:45 UTC+1 skrev Rodrigo Kochenburger:
The fact that you're exposing/requiring implementation structure to be of a type struct with a specific field definitely makes it *more* coupled. When working with Interfaces you don't want to assume anything about the implementation which is why using reflection to access internal fields depending on the type pretty much throws away the real benefits of interface as well.
Please clarify, I don't see how instead of requiring a concrete struct of specific type to require an interface with specific fields be more coupled.
 

I think what is missing for you is a behavior oriented approach when dealing with interfaces, along the lines of the "Tell, don't ask" idea. You don't ask the object for data and act on it, you tell the object to act on it. It enforces better encapsulation which leads to better design. This way you end-up with smaller interfaces, less knowledge about internals of the implementations, which leads to more maintainable code and implementations that can evolve without breaking the rest of the app and with components that can be easily replaced/swapped by another one.

A good example is the sort package. By requiring a Swap method, it's the implementation job to know how to swap values which not only allows to sort different values but also makes it not dependent on the underlying storage structure. It could easily be an slice or a linked list or anything you want.
The sort package with its interface is as it should be, it's not a use case for interfaces with fields. This proposal is not a "critical" one as you can already work around it with getters/setters but rather an improvement as you really want to skip the bookkeeping exactly like the case with embedding structs.

Rodrigo Kochenburger

unread,
Dec 26, 2013, 2:23:20 PM12/26/13
to Peter Nguyen, golan...@googlegroups.com, tomwilde
Den torsdagen den 26:e december 2013 kl. 18:17:45 UTC+1 skrev Rodrigo Kochenburger:
The fact that you're exposing/requiring implementation structure to be of a type struct with a specific field definitely makes it *more* coupled. When working with Interfaces you don't want to assume anything about the implementation which is why using reflection to access internal fields depending on the type pretty much throws away the real benefits of interface as well.
Please clarify, I don't see how instead of requiring a concrete struct of specific type to require an interface with specific fields be more coupled.

What I'm saying is that requiring an interface with specific fields will be more coupled than requiring an interface only with methods, because instead of only depending on behavior you're depending on a specific structure/datatype, which invalidates the benefits of using interfaces in the first place.
 


I think what is missing for you is a behavior oriented approach when dealing with interfaces, along the lines of the "Tell, don't ask" idea. You don't ask the object for data and act on it, you tell the object to act on it. It enforces better encapsulation which leads to better design. This way you end-up with smaller interfaces, less knowledge about internals of the implementations, which leads to more maintainable code and implementations that can evolve without breaking the rest of the app and with components that can be easily replaced/swapped by another one.

A good example is the sort package. By requiring a Swap method, it's the implementation job to know how to swap values which not only allows to sort different values but also makes it not dependent on the underlying storage structure. It could easily be an slice or a linked list or anything you want.
The sort package with its interface is as it should be, it's not a use case for interfaces with fields. This proposal is not a "critical" one as you can already work around it with getters/setters but rather an improvement as you really want to skip the bookkeeping exactly like the case with embedding structs.

The sort package requires an interface which is used to *tell* the object to do something (i.e. swap) instead of asking for the data and swapping the data itself. That difference is crucial for making de-coupled systems and really harvesting the benefits of interface use. I'm pretty sure you can approach your problem differently by thinking about behavior rather than data.

If you really need to worry about the specifics of the type (i.e. the fields) then you're better off using the concrete type rather than an interface type.


Anyway, this is getting off-topic. I'm explaining why interfaces does not have fields: it describes how objects interact with each other, it does not describe how the object expose internal data. That said, I would not expect fields to ever be added to an interface because it goes against a lot of the benefits of why one would use interface, goes against what the term "Interface" means (traditionally), I believe there are some internal implementation details that would make this hard to implement and it would potentially break the Go1 API stability promise (http://golang.org/doc/go1compat).

Rob Pike

unread,
Dec 26, 2013, 2:28:41 PM12/26/13
to Rodrigo Kochenburger, Peter Nguyen, golan...@googlegroups.com, tomwilde
If fields were allowed in interfaces, only structs could satisfy them.
That would be a fundamental breakage in the model.

Structs group data.

Interfaces group behavior.

The separation is deliberate and has major consequences.

-rob

Peter Nguyen

unread,
Dec 26, 2013, 2:39:03 PM12/26/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde


Den torsdagen den 26:e december 2013 kl. 20:23:20 UTC+1 skrev Rodrigo Kochenburger:
Den torsdagen den 26:e december 2013 kl. 18:17:45 UTC+1 skrev Rodrigo Kochenburger:
The fact that you're exposing/requiring implementation structure to be of a type struct with a specific field definitely makes it *more* coupled. When working with Interfaces you don't want to assume anything about the implementation which is why using reflection to access internal fields depending on the type pretty much throws away the real benefits of interface as well.
Please clarify, I don't see how instead of requiring a concrete struct of specific type to require an interface with specific fields be more coupled.

What I'm saying is that requiring an interface with specific fields will be more coupled than requiring an interface only with methods, because instead of only depending on behavior you're depending on a specific structure/datatype, which invalidates the benefits of using interfaces in the first place.

OK, got you. I'm not comparing benefits of interface with methods against interface with fields but rather interface with fields against concrete structs so not arguing with you there.
 
 


I think what is missing for you is a behavior oriented approach when dealing with interfaces, along the lines of the "Tell, don't ask" idea. You don't ask the object for data and act on it, you tell the object to act on it. It enforces better encapsulation which leads to better design. This way you end-up with smaller interfaces, less knowledge about internals of the implementations, which leads to more maintainable code and implementations that can evolve without breaking the rest of the app and with components that can be easily replaced/swapped by another one.

A good example is the sort package. By requiring a Swap method, it's the implementation job to know how to swap values which not only allows to sort different values but also makes it not dependent on the underlying storage structure. It could easily be an slice or a linked list or anything you want.
The sort package with its interface is as it should be, it's not a use case for interfaces with fields. This proposal is not a "critical" one as you can already work around it with getters/setters but rather an improvement as you really want to skip the bookkeeping exactly like the case with embedding structs.

The sort package requires an interface which is used to *tell* the object to do something (i.e. swap) instead of asking for the data and swapping the data itself. That difference is crucial for making de-coupled systems and really harvesting the benefits of interface use. I'm pretty sure you can approach your problem differently by thinking about behavior rather than data.

If you really need to worry about the specifics of the type (i.e. the fields) then you're better off using the concrete type rather than an interface type.


Anyway, this is getting off-topic. I'm explaining why interfaces does not have fields: it describes how objects interact with each other, it does not describe how the object expose internal data. That said, I would not expect fields to ever be added to an interface because it goes against a lot of the benefits of why one would use interface, goes against what the term "Interface" means (traditionally), I believe there are some internal implementation details that would make this hard to implement and it would potentially break the Go1 API stability promise (http://golang.org/doc/go1compat).

 I also agree on that interface is perfect for the behavioral methods such as swap in the sort package, my point is that somewhere you need to get/set your data and fields in interface would be better then getter/setter. This is of course not the traditional term of "interface" as you mentioned and maybe not calling it interface would perhaps be better. I coin for the term "struct contract" :-)

Peter Nguyen

unread,
Dec 26, 2013, 2:48:13 PM12/26/13
to golan...@googlegroups.com, Rodrigo Kochenburger, Peter Nguyen, tomwilde
No, it's not the intention to break the interface model. If it is defined with fields then only structs can satisfy it obviously, but if there are only methods in the interface then any type could satisfy it. So the current model still applies. An idea would be to separate it from interface completely into its own concept as "struct contracts"

Kamil Kisiel

unread,
Dec 26, 2013, 3:00:39 PM12/26/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde
If you want a function that accepts a struct with particular fields, why not just make it accept a struct with those fields? That's already a "struct contact". It's not hard for the caller to populate the struct with values from something else and then call the function. 

Peter Nguyen

unread,
Dec 26, 2013, 3:10:01 PM12/26/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde
Because, then you can't create functions that can accept structs of different types. An example is structs created from JSON data that you want to persist in a db. Currently, you have to accept an interface{} type and use reflect to set/get the values, or using an interface with getters/setters.

Caleb Doxsey

unread,
Dec 26, 2013, 5:38:17 PM12/26/13
to Peter Nguyen, golan...@googlegroups.com, tomwilde
It probably won't get you to where you're trying to go, but you can share fields by embedding structs:

http://play.golang.org/p/21EvukwDGt

The database case isn't a good one because each 'type' of object has different fields (and so couldn't use the same interface anyway). Do you have an example where embedding wouldn't work?


--

Peter Nguyen

unread,
Dec 26, 2013, 5:55:36 PM12/26/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net
Embedding won't do as you still can't assert that the outer struct is the same as the embedded struct:

type A struct {
  Id string
}

type B struct {
  *A
}

func Foo(a A) {
  fmt(a.Id)
}

var b B
Foo(b) // Error

The database case is for example data structs that has common fields such as Id, Created, Updated, Deleted, Active. E.g:

type Foo struct {
  Id string
  Name string
  Created time.Time
}

type Bar struct {
  Id string
  Description string
  Created time.Time
}

When you pass them to a method and you may want for example to set the field Created = time.Now() before the data is persisted, you have to define an interface with a setter for it to work currently.

Caleb Doxsey

unread,
Dec 26, 2013, 6:37:39 PM12/26/13
to Peter Nguyen, golan...@googlegroups.com, tomwilde
func (this A) Foo() {}
b.Foo()

Does work though.

I agree that it won't work in the database case, but my point was the suggested change won't fix that problem. As long as any fields are different between two structs you'd have to pass in interface{} anyway.

I suppose you'd be able to cast easier:

x, ok := o.(interface { Created time.Time })
if ok {
    x.Created = time.Now()
}

Is that what you were imagining? You can pull off a similar trick using embedding:

http://play.golang.org/p/Woz55L30N1

Peter Nguyen

unread,
Dec 26, 2013, 6:46:40 PM12/26/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net


Den fredagen den 27:e december 2013 kl. 00:37:39 UTC+1 skrev Caleb Doxsey:
func (this A) Foo() {}
b.Foo()

Does work though.

Sure, but the point was to access the Id field in B
 

I agree that it won't work in the database case, but my point was the suggested change won't fix that problem. As long as any fields are different between two structs you'd have to pass in interface{} anyway.

No, because then you can do this

type Object interface {
  Created time.Time
}

func Insert(object Object) {
  object.Created = time.Now()
}

// Both Foo and Bar satisfy the struct contract of Object by having the field Created of type time.Time
var foo Foo
var bar Bar
Insert(foo)
Insert(bar)


I suppose you'd be able to cast easier:

x, ok := o.(interface { Created time.Time })
if ok {
    x.Created = time.Now()
}

Is that what you were imagining? You can pull off a similar trick using embedding:

http://play.golang.org/p/Woz55L30N1

Yes, your Init() method is just a setter as discussed in the previous posts

nvc...@gmail.com

unread,
Dec 26, 2013, 7:41:21 PM12/26/13
to Peter Nguyen, golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net
I feel that you're figthing with the language.
It seem that what you want is some kind of abstract class, in general is inheritance that Go don't have, then you want a new feature to fill the old missing one.
Maybe you want to keep your code DRY...but you're trying too much in this case!

Nguyễn Văn Cao Nguyên
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/ZJ5DEv_36S8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.

Peter Nguyen

unread,
Dec 26, 2013, 7:50:31 PM12/26/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net
On the contrary, as mentioned in the previous posts in this discussion this is not a critical issue or a show stopper of any kind as there is already workarounds. It's just a syntactic sugar the way embedding is. Anyway, if anyone else find this idea useful, please chime in. Otherwise, I'm sure there are more important issues in Go to be dealt with first.

Jsor

unread,
Dec 26, 2013, 8:07:28 PM12/26/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net
I think using a "guaranteed data field" would be a bit of a nightmare and would promote inflexible implementations. With a .Header() method I can programmatically fill a header struct and send it to the requesting method. I can wrap my internal header in a mutex, or some channeled request manager if race conditions become a problem. It gives me flexibility as a designer and yet the outward facing data to you is the same. With a Header field things become dicier. Is it your responsibility to avoid concurrent modification problems? What if I have data that relies on the Header? How am I going to update it when it's written to? What if I only want to spend the work assembling the header when it's explicitly requested, and save the effort of making it otherwise? I just lost that option, because now if something could prompt a change, I *must* update the filed *immediately*. That or I have to do some silly nonsense about encouraging people to call my UpdateHeader method before reading from Header.

Obviously having to use discretion isn't something that inherently disqualifies an idea, and sometimes an accessor is only conceivably ever going to be an accessor. But I feel like the "guaranteed field" idea is going to encourage bad design and hasty API rewrites when the developer realizes that they actually DO have to do extra work when setting a value, or protect itself from race conditions, or whatever else. I know I recently had a case where something I definitely would have initially suspected should be a freely exposed field suddenly needed to have a few lines added to the Get and Set methods to prevent problems.

Peter Nguyen

unread,
Dec 26, 2013, 8:22:54 PM12/26/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net


Den fredagen den 27:e december 2013 kl. 02:07:28 UTC+1 skrev Jsor:
I think using a "guaranteed data field" would be a bit of a nightmare and would promote inflexible implementations. With a .Header() method I can programmatically fill a header struct and send it to the requesting method. I can wrap my internal header in a mutex, or some channeled request manager if race conditions become a problem. It gives me flexibility as a designer and yet the outward facing data to you is the same. With a Header field things become dicier. Is it your responsibility to avoid concurrent modification problems? What if I have data that relies on the Header? How am I going to update it when it's written to? What if I only want to spend the work assembling the header when it's explicitly requested, and save the effort of making it otherwise? I just lost that option, because now if something could prompt a change, I *must* update the filed *immediately*. That or I have to do some silly nonsense about encouraging people to call my UpdateHeader method before reading from Header.

I think you miss the point, this is not a discussion about getters/setters versus setting values directly on exported fields, as the decision has already been made and Go support exported fields. If following your argument, then exported fields wouldn't be allowed and you only have getters/setters for everything which is not the case currently.
 

Obviously having to use discretion isn't something that inherently disqualifies an idea, and sometimes an accessor is only conceivably ever going to be an accessor. But I feel like the "guaranteed field" idea is going to encourage bad design and hasty API rewrites when the developer realizes that they actually DO have to do extra work when setting a value, or protect itself from race conditions, or whatever else. I know I recently had a case where something I definitely would have initially suspected should be a freely exposed field suddenly needed to have a few lines added to the Get and Set methods to prevent problems.

It's a case for refactoring and it's nothing wrong with that. But then, you should of course change your field to be non-exported and only allow access through your Get/Set methods. It's irrelevant though for struct contracts. I've already provided a use case in the previous posts and if it is not something that you run into in your code then you'll probably won't find this idea useful.

Bakul Shah

unread,
Dec 26, 2013, 8:47:54 PM12/26/13
to Rob Pike, golan...@googlegroups.com
On Thu, 26 Dec 2013 11:28:41 PST Rob Pike <r...@golang.org> wrote:
>
> Structs group data.
>
> Interfaces group behavior.
>
> The separation is deliberate and has major consequences.

An important distinction that should be stressed more IMHO.
But the word "interface" doesn't bring to mind a grouping of
behavior. In searching for a better word I first hit upon
"actor" but that may get confused with Carl Hewitt's Actors.
It was natural to think next of the word "role" -- an entity
can play a role if it implements behaviors required by that
role and of course an entity can take on more than one role!
This is even implicitly reflected in some of the interface
names: Reader, Writer, Crypter, Stringer and so on! And
finally, the word "role" is shorter than "interface" :-)

I don't expect Go to change but thought this connotation worth
talking about. I particularly like the symmetry of grouping
of data vs behavior and this factoring out of behavior groups.
Perhaps this idea can be further extended to a more structured
behavior? For example, using Campbell & Habermann's Path
Expressions one can describe allowed sequencing of operations
as a regexp. [At least as an annotation! The compiler can
simply ignore it but may be one can generate code that does
more thorough checking -- this seems particularly apt in a
concurrent language]

--bakul

simon place

unread,
Dec 26, 2013, 9:40:53 PM12/26/13
to golan...@googlegroups.com
i have always found not having fields in interfaces strange, i posted about it a long time ago.

what i think is happening, that makes this strange for me, is that when you get familiar with thinking 'functionally', and realise that returning a value is just as much a behaviour as any other, the idea of separation between state and behaviour becomes unnecessary, and just seems cumbersome.

all that having fields separated from methods means, is that you force that there can not be any side-effects when you get or set them, but that seems like its leaking the implementation to me.

isn't it the .NET framework (and others) that treat these transparently, so if you define setter and getter methods you can use as a field or visa versa, very logical IMHO.  So, basically the same thing, having a field satisfy an interface with setter and getters for it, might give you this fairly painlessly.

nvc...@gmail.com

unread,
Dec 26, 2013, 9:14:59 PM12/26/13
to Peter Nguyen, golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net
 And instead of define an interface with getters/setters or interface with fields and then you can modify them, you could let them do it by themself.
This is my prefer way for my db:

type IQueryInsert interface { //C# name type easier for me :D
    QueryInsert() string
}

type IQueryDelete interface{
    QueryDelete() string
}

type IQueryEntity interface {
    IQueryDelete
    IQueryInsert
}

type Foo struct {
    Id int
    CreatedAt time.Time
    FooOnly int
}

func (e *Foo) QueryInsert() string {
    e.CreatedAt = time.Now()
    return "INSERT INTO....."
}

func (e *Foo) QueryDelete() string {
    return "DELETE ....."
}

type Bar struct {
    Id int
    CreatedAt time.Time
    BarOnly string
}

Then delete function can be:
func Delete(e IQueryEntity) {
    db.Query(e.DeleteQuery())
}

Or:
func Delete(e IQueryDelete){...}

func (e *Bar) QueryInsert() string {...}
func (e *Bar) QueryDelete() string {...}
Nguyễn Văn Cao Nguyên
(84)0935.7045.95
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/ZJ5DEv_36S8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.

Dmitri Shuralyov

unread,
Dec 26, 2013, 9:41:34 PM12/26/13
to golan...@googlegroups.com, Rob Pike
> Anyway, if anyone else find this idea useful, please chime in.

I just want to say +1. I've had very similar thoughts and wishes as Peter Nguyen describes. It feels bad having two ways to set/get a field:

// Which do I use? There is no clear choice
a.Id += 1
a.SetId(a.Id() + 1)

Making the field private just forces the getter/setter methods to be created for each field you want to export and be able to access/modify. Which is 3x the typing, and reminds me of header files in C/C++.

To me, "read/write access to a field of some type" is a part of possible behaviors.

The best solution I've found so far is to have a ModifyId() *Id field that returns a pointer, in order to cut down from 2 methods (get/set) to one. But it requires * to be used.

Anyway, those are my thoughts. I don't have a perfect solution.

gordon...@gmail.com

unread,
Dec 27, 2013, 3:50:32 AM12/27/13
to golan...@googlegroups.com, Rob Pike
I think the 3rd way you mention is worthy of a bit more consideration.  That is, have the accessor method return a pointer:

type T struct { id int }
func (t *T) Id() *int { return &t.id }

t := T{4}
*t.Id() += 3

The need to dereference is slightly annoying, but not a big deal.  But I also think it wouldn't be going too far to propose that Go automatically dereference pointers in appropriate contexts.  It already does so on method invocations.  What would be the harm in also doing so in operator expressions and assignments?  There is no ambiguity in "t.Id() += 3" because Go doesn't support pointer arithmetic.

One nice side effect is that slice range loops could provide a mutable slice element.

Of course, more magic might reduce readability.

Gerard

unread,
Dec 27, 2013, 4:34:11 AM12/27/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net
What do you mean with "there are more important issues in Go to be dealt with first." ?

Peter Nguyen

unread,
Dec 27, 2013, 4:39:51 AM12/27/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net
I was just thinking about the Go 1.3 (https://docs.google.com/document/d/1s6MxBsLyBG45SRS60a-aM01DmZ4hD1nMzGAKdTopKGY/edit), I'm sure it has higher priority than syntatic sugar :-)

Gerard

unread,
Dec 27, 2013, 5:10:44 AM12/27/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net
That's an impressive list indeed.

Returning to the issue:

The only thing I want to say is that maybe it's better to just accept the language Go as it is right now.

When you are facing a problem, try to solve it with the tools you have and forget about the tools you get in other languages.

That means that sometimes you have to write more code and sometimes less. That's how it is.

It also helps to look at other packages and books.

Peter Nguyen

unread,
Dec 27, 2013, 5:21:54 AM12/27/13
to golan...@googlegroups.com, tomwilde, ca...@doxsey.net


Den fredagen den 27:e december 2013 kl. 11:10:44 UTC+1 skrev Gerard:
That's an impressive list indeed.

Returning to the issue:

The only thing I want to say is that maybe it's better to just accept the language Go as it is right now.

When you are facing a problem, try to solve it with the tools you have and forget about the tools you get in other languages.

I agree, but also think that it is important not to discard new ideas and suggestions as there will be no improvement if everybody was just content with the way it is.

Andy Balholm

unread,
Dec 27, 2013, 10:52:26 AM12/27/13
to golan...@googlegroups.com, tomwilde, ca...@doxsey.net
In another thread, Rob just described how to wrap a type that has the method you need, but with the wrong name to satisfy an interface. There would be no way to do that with fields—unless you could create magic getters and setters that would somehow satisfy an interface that calls for a field.

Peter Nguyen

unread,
Dec 27, 2013, 11:05:46 AM12/27/13
to golan...@googlegroups.com, tomwilde, ca...@doxsey.net
Struct contracts is not supposed to replace interfaces... Don't know why people have that misconception. So Rob's solution to wrap a type would still work as well with normal interfaces. I suppose though that a struct contract should be embeddable into another struct contract, just as interfaces do if it would ever be considered...

Caleb Doxsey

unread,
Dec 27, 2013, 11:39:35 AM12/27/13
to Peter Nguyen, golan...@googlegroups.com, tomwilde
type Object interface {
  Created time.Time
}

func Insert(object Object) {
  object.Created = time.Now()
}

// Both Foo and Bar satisfy the struct contract of Object by having the field Created of type time.Time
var foo Foo
var bar Bar
Insert(foo)
Insert(bar)

I think you're missing the point about the database. Presumably Foo and Bar have additional properties that aren't shared, and you would want to access them in your Insert method so that you could insert them into the the database. Even with fields defined via an interface you would still have to use reflection or casting to get to those additional properties.

func Insert(object Object) {
  // yes we could do this
  object.Created = time.Now()
  // but we still have to get to all the other fields to do this:
  db.Exec("INSERT INTO foo (created, some_other_field) VALUES ($1, $2)", object.Created, object.SomeOtherField)
}

The cases where we don't have to do the reflection/casting are also the cases where we can just use the same struct. (If we really only need .Created, why not just use the same struct for Foo & Bar?)

I agree that reflection and casting can be a bit tedious, but if you have to do it even a little what's the pain in having to do it one more time?

Peter Nguyen

unread,
Dec 27, 2013, 2:21:05 PM12/27/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net
Because the reflection and casting could be in a separated package and not necessarily in your own code. That's the case with for example drivers for NoSQL databases such as MongoDB or Rethinkdb where you can pass on an arbitary struct to their methods. Btw, getters/setters would be a better alternative than reflection.

Here is another example use case for struct contracts:

type Saleable contract {
  Name string
  Price float
  Vat float
}

type Item struct {
  Name string
  Price float
  Vat float
  // Item specific fields
}

type Service struct {
  Name string
  Price float
  Vat float
  // Service specific fields
}

type Shipping struct {
  Name string
  Price float
  Vat float
  // Shipping specific fields
}

func PrintOrder(order []*Saleable) {
  for _, orderLine := range order {
    fmt.Println("Product: ", orderLine.Name)
    fmt.Sprintf("Sum: %f", orderLine.Price * (float(1) + orderLine.Vat))
  }
}

func main() {
  var order []*Saleable
  order = append(order, &Item{"Product A", 10.0, 0.25, ...})
  order = append(order, &Service{"Service A", 15.0, 0.25, ...})
  order = append(order, &Shipping{"Shipping", 5.0, 0.25, ...})
  PrintOrder(order)
}

Wouldn't it be nice to write code this way?

egon

unread,
Dec 27, 2013, 3:30:39 PM12/27/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net
Instead of http://play.golang.org/p/1AOvPGBWXU or http://play.golang.org/p/mNKkLR8Mtu... or better yet http://play.golang.org/p/JwsLXNh5Yr.

To me it seems, with your example, you are trying to fit all of the different bounded contexts into a single model, which doesn't model anything that well. The question is, why do each of the order lines have to be a different type? I see those types coming and going, and probably a string would even suit better than an int.

+ egon

Peter Nguyen

unread,
Dec 27, 2013, 4:27:14 PM12/27/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net
Yes, that's how I currently work around it too, but it has 2 issues:

1. Tight coupling with the common struct. As with interfaces, a struct will implicit implements a contract just by having the defined fields. It can satisfy multiple contracts that are overlapping, so advantages with interfaces also apply here.
2. Unnecessary bookkeeping when assigning data to the structs, instead of:

type Saleable contract {
  Name string
  Price float
  Vat float
  Sold bool
}

func PrintOrder(order []*Saleable) {
  for _, orderLine := range order {
    fmt.Println("Product: ", orderLine.Name)
    fmt.Sprintf("Sum: %f", orderLine.Price * (float(1) + orderLine.Vat))
    orderLine.Sold = true
  }
}

Why specific fields for different struct is that they are of different data models. They may have specific logic for their type. An Item may have SKU and a Service maybe needs start and end dates etc.

Tamás Gulácsi

unread,
Dec 27, 2013, 5:06:17 PM12/27/13
to golan...@googlegroups.com
But that logic won't be called when you use fields, instead of methods.

I just don't understand, what is your problem withinterfaces and methods. These solves your problem, and without too much hassle.

This struct contract is not orthogonal to interfaces, thus I think is a bad candidate for language extension.

Peter Nguyen

unread,
Dec 27, 2013, 6:02:12 PM12/27/13
to golan...@googlegroups.com
Thanks, you made me learn a new word :-), but still I don't know what you mean with "orthogonal" in this context. Anyway I have absolutely no problem with interfaces and methods. In fact, I think Go's interface implementation is great. "Struct contract" is just a suggestion for a syntax which I find convenient based on the same idea of interface.

Btw, if you don't make the fields non-exported, then you can't be sure that your getters/setters will be called with whatever extra logic in them. 

Kevin Gillette

unread,
Dec 27, 2013, 7:34:10 PM12/27/13
to golan...@googlegroups.com
For any Go feature being proposed, it must be considered whether it will produce any negative consequences; if so, those negative consequences should be considered much more strongly than any positive consequences, in order to keep the language clean and small.

With your proposal, yes, this would allow interfaces to specify struct fields that must be present, but the negative consequence is that when the feature is abused (and it will *always* be abused), third party libraries will be filled with senseless interface definitions that can only be implemented by strongly coupled structs. Because of this, it can't be considered a feature that benefits struct use, but rather, it's just a feature that limits the usefulness of non-struct types.

Orthogonality, when used in Go related discussions, means features which work well together but don't overlap with each other (so that there won't be multiple redundant ways to accomplish the same task). This proposal is not orthogonal to other aspects of the language.

egon

unread,
Dec 28, 2013, 5:39:45 AM12/28/13
to golan...@googlegroups.com, Peter Nguyen, tomwilde, ca...@doxsey.net
On Friday, December 27, 2013 11:27:14 PM UTC+2, Peter Nguyen wrote:
Yes, that's how I currently work around it too, but it has 2 issues:

1. Tight coupling with the common struct. As with interfaces, a struct will implicit implements a contract just by having the defined fields. It can satisfy multiple contracts that are overlapping, so advantages with interfaces also apply here.

Yes, it is more coupled with the common struct.
 
2. Unnecessary bookkeeping when assigning data to the structs, instead of:

type Saleable contract {
  Name string
  Price float
  Vat float
  Sold bool
This "Sold" is just wrong from a modeling perspective.... see http://en.wikipedia.org/wiki/Ledger .
You can't just set arbitrarily "Sold = true" whenever you like; you need a proper audit trail for it.
}

func PrintOrder(order []*Saleable) {
  for _, orderLine := range order {
    fmt.Println("Product: ", orderLine.Name)
    fmt.Sprintf("Sum: %f", orderLine.Price * (float(1) + orderLine.Vat))
    orderLine.Sold = true
  }
}

Why specific fields for different struct is that they are of different data models. They may have specific logic for their type. An Item may have SKU and a Service maybe needs start and end dates etc.

Yes, but then their printing models would be different... so you couldn't write a single function for all of them anyway.
 
What I'm trying to say that you are building poor models and because of that you have problems expressing the code. Although, yes, when such situation arises it would be convenient to express it that way... but the problem is in the initial model, not the language. Unless you can provide a good example with an excellent model then you can argue about the necessity of such "contract"-s.

+ egon

greg...@gmail.com

unread,
Jun 9, 2014, 9:04:44 PM6/9/14
to golan...@googlegroups.com, peter.ng...@gmail.com, sedevel...@gmail.com, ca...@doxsey.net
Hello,

I hate dredge up an old topic but I found this today while googling for my particular issue.  I was assisted on #go-nuts with the following solution which is exactly what I needed, so hopefully it helps somebody else: http://play.golang.org/p/R2HI7WDnal . I'll paraphrase here:

type Foo struct {
  Id string
}
type Bar struct {
  Foo
}
func DoSomethingWithFoo(foo *Foo) {
  fmt.Println(foo.Id)
}
bar := &Bar{}
bar.Id = "One"
DoSomethingWithFoo(bar.Foo)

So essentially it's tearing out the embedded Foo bits and passing it on to the function.  Modification works as expected because pointers: http://play.golang.org/p/o_N9GliXDu .  It's a bit more explicit than it could be, and I think the compiler could definitely figure this out for you, but it works well enough for me.

Kevin Gillette

unread,
Jun 9, 2014, 9:28:05 PM6/9/14
to golan...@googlegroups.com, peter.ng...@gmail.com, sedevel...@gmail.com, ca...@doxsey.net, greg...@gmail.com
On Monday, June 9, 2014 7:04:44 PM UTC-6, greg...@gmail.com wrote:
DoSomethingWithFoo(bar.Foo)

I'm sure you mean:

DoSomethingWithFoo(&bar.Foo)

Jeffrey 'jf' Lim

unread,
Jun 9, 2014, 10:22:36 PM6/9/14
to Kevin Gillette, greg...@gmail.com, peter.ng...@gmail.com, sedevel...@gmail.com, golan...@googlegroups.com, ca...@doxsey.net

Yup. The complete source, btw (because it makes the point more clearly):

========
package main

import "fmt"

type A struct {
Id string
}

type B struct {
A
}

func main() {
fmt.Println("Hello, playground")
b := &B{}
b.Id = "One"
DoSomethingWithAnA(&b.A)
fmt.Println(b.Id)
}

func DoSomethingWithAnA(a *A) {
a.Id = "Two"
}
========

-jf

Reply all
Reply to author
Forward
0 new messages