Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upproposal: Default implementation for interface #16254
Comments
mkideal
changed the title from
Default implementation for interface
to
proposal: Default implementation for interface
Jul 3, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mezoni
Jul 3, 2016
then DBTransaction automatically owns Process() error method while it's used as Transaction
What means automatically owns if this method does not specified in the type declaration (interface)?
type Transaction interface {
Begin()
Exec() error
End()
// Process() error
}Sorry, but I cannot understand how an interface can have implementation?
mezoni
commented
Jul 3, 2016
•
What means type Transaction interface {
Begin()
Exec() error
End()
// Process() error
}Sorry, but I cannot understand how an |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mkideal
Jul 3, 2016
Did you know trait in rust language(@mezoni)? It's very similar to interface in golang, but support default implementation.
trait Transaction {
fn begin(&self);
fn exec(&self) -> Result;
fn end(&self);
fn process(&self) -> Result {
...
}
}And pure virtual class in c++
class Transaction {
public:
virtual void begin() = 0;
virtual int exec() = 0;
virtual void end() = 0;
int process() {
...
}
};
mkideal
commented
Jul 3, 2016
|
Did you know trait Transaction {
fn begin(&self);
fn exec(&self) -> Result;
fn end(&self);
fn process(&self) -> Result {
...
}
}And class Transaction {
public:
virtual void begin() = 0;
virtual int exec() = 0;
virtual void end() = 0;
int process() {
...
}
}; |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mezoni
Jul 3, 2016
Did you know trait in rust language(@mezoni)? It's very similar to interface in golang, but support default implementation.
Mixins, traits used in OOP.
Also I know abstract classes.
Also I know that in Go language there are no such thing as OOP and inheritance.
What benefits from the mixins and traits in the Go language if the Go language does not supports inheritance?
Also I know that the Go language does not supports abstract and virtual methods only because they are useless in the Go language (without inheritance).
P.S.
In computer programming, a trait is a concept used in object-oriented programming, which represents a set of methods that can be used to extend the functionality of a class.
I think that these terms are not an applicable to the Go language.
- Object-oriented programming
- Class
The Go language supports only a value based types.
Most of them are bits based structs.
Even an int16 type is only a struct with a length of the 16 bits.
This is the main advantage: a value based types with support of references (pointers).
mezoni
commented
Jul 3, 2016
Mixins, traits used in OOP. P.S. I think that these terms are not an applicable to the Go language.
The Go language supports only a value based types. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
creker
Jul 3, 2016
You can achieve kind of the same thing with embedding. Here's an example
type II interface {
foo() int
bar() int
}
//empty struct with shared foo() implementation
type S1 struct {
}
func (s S1) foo() int {
return 123
}
type S2 struct {
S1
}
func (s S2) bar() int {
return 456
}
func main() {
var v II
v = S2{}
fmt.Println(v.foo(), v.bar())
}
https://play.golang.org/p/MHo14zUpq1
Given that interfaces are implemented implicitly, it would be difficult to track down where exactly all the methods are implemented with this proposal.
creker
commented
Jul 3, 2016
|
You can achieve kind of the same thing with embedding. Here's an example
https://play.golang.org/p/MHo14zUpq1 Given that interfaces are implemented implicitly, it would be difficult to track down where exactly all the methods are implemented with this proposal. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mkideal
Jul 3, 2016
In essence, func (tr Transaction) Process() error just a syntactic sugar of func Process(tr Transaction) error
For example, Reader interface of package io:
type Reader interface {
Read(b []byte) (n int, err error)
}
func ReadFull(r Reader, buf []byte) (n int, err error) { ... }Can we use ReadFull function as a method of Reader:
func (r Reader) ReadFull(buf []byte) (n int, err error) { ... }It's just a syntactic sugar
Certainly, Any structure which implements Reader can overide ReadFull method.
mkideal
commented
Jul 3, 2016
•
|
In essence, For example, type Reader interface {
Read(b []byte) (n int, err error)
}
func ReadFull(r Reader, buf []byte) (n int, err error) { ... }Can we use func (r Reader) ReadFull(buf []byte) (n int, err error) { ... }It's just a syntactic sugar Certainly, Any structure which implements |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
starius
Jul 3, 2016
If your proposal is implemented, one will be able to add any methods to any types by creating an empty interface with desired methods with default implementation, because any type satisfies the empty interface.
starius
commented
Jul 3, 2016
|
If your proposal is implemented, one will be able to add any methods to any types by creating an empty interface with desired methods with default implementation, because any type satisfies the empty interface. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mkideal
Jul 3, 2016
one will be able to add any methods to any types by creating an empty interface with desired methods
Can you tell how to to this?
Can you write a example?
If you write:
type Any interface {}
func (any Any) MyMethod() { ... }In this case, MyMethod is one method of Any only.
mkideal
commented
Jul 3, 2016
Can you tell how to to this? If you write: type Any interface {}
func (any Any) MyMethod() { ... }In this case, |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
What problem does this proposal solve? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mezoni
Jul 4, 2016
What problem does this proposal solve?
Possible the idea of this proposal (default implementation for interface) is useful but this is impossible in the Go language, with it it structural type system.
Initially, I also cannot undestood why Go language does not allowed some concepts (based on the inheritance) wihich are works very well in the nominative type systems.
This is because nominal subtyping means that one type is a subtype of another if and only if it is explicitly declared to be so in its definition.
In structural typing, an element is considered to be compatible with another if, for each feature within the second element's type, a corresponding and identical feature exists in the first element's type.
That is, this is impossible to have a default implementation only because it (implementation of the interface, as the first element) should be defined explictly in the second element (interface implementer) to be compatible with the interface, as the first element.
mezoni
commented
Jul 4, 2016
Possible the idea of this proposal (default implementation for interface) is useful but this is impossible in the Go language, with it it structural type system. This is because nominal subtyping means that one type is a subtype of another if and only if it is explicitly declared to be so in its definition. In structural typing, an element is considered to be compatible with another if, for each feature within the second element's type, a corresponding and identical feature exists in the first element's type. That is, this is impossible to have a default implementation only because it (implementation of the interface, as the first element) should be defined explictly in the second element (interface implementer) to be compatible with the interface, as the first element. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
starius
Jul 4, 2016
one will be able to add any methods to any types by creating an empty interface with desired methods
Can you tell how to to this?
Can you write a example?
I'll continue your example:
type Any interface {}
func (any Any) MyMethod() { ... }
type Foo struct {
// some members
}
func main() {
var foo Foo
foo.MyMethod()
}In this example, Foo satisfies Any interface and (according to your proposal) gets default method MyMethod from it.
starius
commented
Jul 4, 2016
I'll continue your example: type Any interface {}
func (any Any) MyMethod() { ... }
type Foo struct {
// some members
}
func main() {
var foo Foo
foo.MyMethod()
}In this example, Foo satisfies Any interface and (according to your proposal) gets default method MyMethod from it. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mezoni
Jul 4, 2016
Possible an author want to say about the following:
type Foo interface {
Baz() Baz
SomeFoo() Baz
}
func (r Foo) SomeFoo() Baz {
return r.Baz()
}
type foo struct {
baz Baz
}
func (r *foo) Baz() Baz {
return r.baz
}
// Abstract method, to be compatible with: interface { SomeFoo() Baz }
abstract func (r *foo) SomeFoo() Baz
func main() {
var foo Foo
foo = &Foo{}
baz := foo.SomeBaz()
}
mezoni
commented
Jul 4, 2016
•
|
Possible an author want to say about the following: type Foo interface {
Baz() Baz
SomeFoo() Baz
}
func (r Foo) SomeFoo() Baz {
return r.Baz()
}
type foo struct {
baz Baz
}
func (r *foo) Baz() Baz {
return r.baz
}
// Abstract method, to be compatible with: interface { SomeFoo() Baz }
abstract func (r *foo) SomeFoo() Baz
func main() {
var foo Foo
foo = &Foo{}
baz := foo.SomeBaz()
}
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mezoni
Jul 4, 2016
The above example is a trivial example but in a real life it can save a lot of time.
And also allows do not duplicate some code.
Eg.
type Expr interface {
// Some members
String() string
}
type UnaryExpr interface {
Expr
GetExpr() Expr
}
type PrefixExpr interface {
UnaryExpr
GetPrefix() string
}
// Default impl
func (r PrefixExpr) String() string {
retrun Sprintf(%s%s, r.GetPrefix(), r.GetExpr())
}
type NotPredicateExpr struct {
}
abstract func (r *NotPredicateExpr) String() string
func (r *NotPredicateExpr) GetPrefix() string {
return "!"
}Currently this is impossible.
Every implementer of the type PrefixExpr interface should implement their own String() method which is not very useful.
Or programmer should use the following approach:
// Somewhere not far from `type PrefixExpr interface`
// Implementation of the `type PrefixExpr intrface { String() } `
func PrefixExpr_String(r PrefixExpr) string {
retrun Sprintf(%s%s, r.GetPrefix(), r.GetExpr())
}
// Should take into account about the existing `PrefixExpr_String` default implementation
func (r *NotPredicateExpr) String() string {
return PrefixExpr_String(r)
}
Which is not a very graceful.
Using an embedded structs (what I do) also does not works.
mezoni
commented
Jul 4, 2016
|
The above example is a trivial example but in a real life it can save a lot of time. Eg. type Expr interface {
// Some members
String() string
}
type UnaryExpr interface {
Expr
GetExpr() Expr
}
type PrefixExpr interface {
UnaryExpr
GetPrefix() string
}
// Default impl
func (r PrefixExpr) String() string {
retrun Sprintf(%s%s, r.GetPrefix(), r.GetExpr())
}
type NotPredicateExpr struct {
}
abstract func (r *NotPredicateExpr) String() string
func (r *NotPredicateExpr) GetPrefix() string {
return "!"
}Currently this is impossible. // Somewhere not far from `type PrefixExpr interface`
// Implementation of the `type PrefixExpr intrface { String() } `
func PrefixExpr_String(r PrefixExpr) string {
retrun Sprintf(%s%s, r.GetPrefix(), r.GetExpr())
}
// Should take into account about the existing `PrefixExpr_String` default implementation
func (r *NotPredicateExpr) String() string {
return PrefixExpr_String(r)
}
Which is not a very graceful. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mezoni
Jul 4, 2016
Another interesting approach:
type Foo interface {
String()
}
// Default impl
func (r Foo) String() string {
return "Foo"
}
type Baz interface {
Foo
}
// Default impl
func (r Baz) String() string {
return "Baz"
}
type baz struct {
}
func main() {
var baz Baz
var foo Foo
baz := &baz{}
fmt.Prinln(baz) // => "baz"
foo := &baz{}
fmt.Prinln(foo) // => "foo"
}How this works?
The fmt.Println() takes an agrument as the interface {}.
The interface {} holds info about the type.
The foo := &baz{} is an type Foo interface{} value.
The type Foo interface{} has its own default implemenattion.
The baz := &baz{} is an type Baz interface{} value.
The type Baz interface{} has its own default implemenattion.
mezoni
commented
Jul 4, 2016
|
Another interesting approach: type Foo interface {
String()
}
// Default impl
func (r Foo) String() string {
return "Foo"
}
type Baz interface {
Foo
}
// Default impl
func (r Baz) String() string {
return "Baz"
}
type baz struct {
}
func main() {
var baz Baz
var foo Foo
baz := &baz{}
fmt.Prinln(baz) // => "baz"
foo := &baz{}
fmt.Prinln(foo) // => "foo"
}How this works? The The |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
davecheney
Jul 4, 2016
Contributor
I have no idea what this proposal is proposing. There are too many Foo's and Bar's and so on to make sense of what you are proposing.
Can you please write a piece of code that uses this feature, it does to have to compile, but it has to show how to this would be used in the real world.
Thanks
Dave
|
I have no idea what this proposal is proposing. There are too many Foo's and Bar's and so on to make sense of what you are proposing. Can you please write a piece of code that uses this feature, it does to have to compile, but it has to show how to this would be used in the real world. Thanks Dave |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
kostya-sh
Jul 4, 2016
Contributor
What would fmt.Println(&baz{}) print?
In other words if a type implements two interfaces that have default
methods with the same name, which of them the type should "inherit"?
On Jul 4, 2016 15:47, "mezoni" notifications@github.com wrote:
Another interesting approach:
type Foo interface {
String()
}
// Default implfunc (r Foo) String() string {
return "Foo"
}
type Baz interface {
Foo
}
// Default implfunc (r Baz) String() string {
return "Baz"
}
type baz struct {
}
func main() {
var baz Baz
var foo Foo
baz := &baz{}
fmt.Prinln(baz) // => "baz"
foo := &baz{}
fmt.Prinln(foo) // => "foo"
}How this works?
The fmt.Println() takes an agrument as the interface {}.
The interface {} holds info about the type.The foo := &baz{} is an type Foo interface{} value.
The type Foo interface{} has its own default implemenattion.The baz := &baz{} is an type Baz interface{} value.
The type Baz interface{} has its own default implemenattion.—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#16254 (comment), or mute
the thread
https://github.com/notifications/unsubscribe/AGy9A6qAr0hiePENb8CDRSQtqQ64pHNzks5qSMi5gaJpZM4JD1Cm
.
|
What would fmt.Println(&baz{}) print? In other words if a type implements two interfaces that have default
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mezoni
Jul 4, 2016
Can you please write a piece of code that uses this feature, it does to have to compile, but it has to show how to this would be used in the real world.
Do you need a very easy example for the very small real world?
Do you need a very complex example for the very big real world?
I think thet this comment explains a lot:
#16254 (comment)
It explains that currently in the Go language need to implements a spike-nail:
// Somewhere not far from `type PrefixExpr interface`
// Implementation of the `type PrefixExpr intrface { String() } `
func PrefixExpr_String(r PrefixExpr) string {
retrun Sprintf(%s%s, r.GetPrefix(), r.GetExpr())
}
// Should take into account about the existing `PrefixExpr_String` default implementation
func (r *NotPredicateExpr) String() string {
return PrefixExpr_String(r)
}
mezoni
commented
Jul 4, 2016
Do you need a very easy example for the very small real world? I think thet this comment explains a lot: // Somewhere not far from `type PrefixExpr interface`
// Implementation of the `type PrefixExpr intrface { String() } `
func PrefixExpr_String(r PrefixExpr) string {
retrun Sprintf(%s%s, r.GetPrefix(), r.GetExpr())
}
// Should take into account about the existing `PrefixExpr_String` default implementation
func (r *NotPredicateExpr) String() string {
return PrefixExpr_String(r)
} |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
davecheney
Jul 4, 2016
Contributor
Do you need a very easy example for the very small real world?
Do you need a very complex example for the very big real world
The former would be preferred.
Re. Your example, I don't understand what that is doing or why go need to change to support that.
Is this a proposal that functions can be accessed as methods on a type assuming the reciever matches the first argument of the function? D has this.
The former would be preferred. Re. Your example, I don't understand what that is doing or why go need to change to support that. Is this a proposal that functions can be accessed as methods on a type assuming the reciever matches the first argument of the function? D has this. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mezoni
Jul 4, 2016
OK.
I think that this is impossible to implement similar features in the Go language only because identification of the interface performed only in the assignment expression.
After when an assignment has been made the original type remains the same.
Yes, interfaces are only interfaces.
In the Go language the values only can satisfies an interface specification but not implements them.
I was incorrect.
mezoni
commented
Jul 4, 2016
•
|
OK. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
dup2X
commented
Jul 4, 2016
|
No need to do this. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ulikunitz
Jul 4, 2016
Contributor
My understanding of the proposal is to define methods on concrete types by defining them on interfaces that the types satisfies. In the example below method Println is defined for stringer extending the method set of type A satisfying stringer. The intention seems to be to save work if a method can be implemented using other functions of a type.
package main
import (
"fmt"
"strconv"
)
type A int
func (a A) String() string {
return strconv.Itoa(int(a))
}
type stringer interface {
String() string
}
func (s stringer) Println() {
fmt.Println(s.String())
}
func main() {
a := A(1).
a.Println()
}
It doesn't compile because an interface type cannot be a receiver. On top a.Println() would also not work, because it is not clear how the compiler chooses the particular interface type with Println as method if there are several interfaces satisfied by A supporting a Println method. The alternative stringer(A).Println() would solve this issue, but it doesn't extend the method set of type A which appears to be the intention. But the method could be provided explicitly in a single line of code calling the general implementation of the interface as in the code below, which compiles and works.
package main
import (
"fmt"
"strconv"
)
type A int
func (a A) String() string {
return strconv.Itoa(int(a))
}
type stringer interface {
String() string
}
func pr(s stringer) {
fmt.Println(s.String())
}
func (a A) Println() { pr(a) }
func main() {
a := A(1)
a.Println()
}
|
My understanding of the proposal is to define methods on concrete types by defining them on interfaces that the types satisfies. In the example below method Println is defined for stringer extending the method set of type A satisfying stringer. The intention seems to be to save work if a method can be implemented using other functions of a type.
It doesn't compile because an interface type cannot be a receiver. On top
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
adg
Jul 4, 2016
Contributor
Can you please write a piece of code that uses this feature, it does to have to compile, but it has to show how to this would be used in the real world.
I second this request. Alternatively, please point to a real piece of Go code and show how it could be better written using this feature. All these tiny hypothetical examples demonstrate the what, but not the why. The "why' is critical.
I second this request. Alternatively, please point to a real piece of Go code and show how it could be better written using this feature. All these tiny hypothetical examples demonstrate the what, but not the why. The "why' is critical. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mezoni
Jul 5, 2016
I second this request. Alternatively, please point to a real piece of Go code and show how it could be better written using this feature. All these tiny hypothetical examples demonstrate the what, but not the why. The "why' is critical.
If you ask me then I already wrote that I was wrong in my judgements.
This feature is impossible to have in the Go language.
mezoni
commented
Jul 5, 2016
If you ask me then I already wrote that I was wrong in my judgements. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
adg
Jul 5, 2016
Contributor
@mezoni thanks for making that clear. My comments are addressed to anyone interested in pushing this proposal forward.
|
@mezoni thanks for making that clear. My comments are addressed to anyone interested in pushing this proposal forward. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mkideal
Jul 5, 2016
Here is an exmaple from package io:
// src/io.go
type Writer interface {
Write(b []byte) (n int, err error)
}
type stringWriter interface {
WriteString(s string) (n int, err error)
}
func WriteString(w Writer, s string) (n int, err error) {
if sw, ok := w.(stringWriter); ok {
return sw.WriteString(s)
}
return w.Write([]byte(s))
}But, if we have this feature(Default implementation for interface), we can rewrite it like below:
type Writer interface {
Write(b []byte) (n int, err error)
}
func (w Writer) WriteString(s string) (n int, err error) {
return w.Write([]byte(s))
}The strange interface stringWriter not needed because your implemented Writer can overides WriteString method. And using WriteString as a method of Writer maybe better than a package-level function.
mkideal
commented
Jul 5, 2016
•
|
Here is an exmaple from package // src/io.go
type Writer interface {
Write(b []byte) (n int, err error)
}
type stringWriter interface {
WriteString(s string) (n int, err error)
}
func WriteString(w Writer, s string) (n int, err error) {
if sw, ok := w.(stringWriter); ok {
return sw.WriteString(s)
}
return w.Write([]byte(s))
}But, if we have this feature( type Writer interface {
Write(b []byte) (n int, err error)
}
func (w Writer) WriteString(s string) (n int, err error) {
return w.Write([]byte(s))
}The strange interface |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
davecheney
Jul 5, 2016
Contributor
I'm sorry, I cannot see how you could write down the rules for how the
discovery of a default implementation would work. And even if they could be
described in sure this would be backwards incompatible with a significant
portion of existing go code.
I vote to close this proposal.
On Tue, 5 Jul 2016, 15:42 王仕晋 notifications@github.com wrote:
Here is an exmaple from package io:
// src/io.gotype Writer interface {
Write(b []byte) (n int, err error)
}
type stringWriter interface {
WriteString(s string) (n int, err error)
}
func WriteString(w Writer, s string) (n int, err error) {
if sw, ok := w.(stringWriter); ok {
return sw.WriteString(s)
}
return w.Write([]byte(s))
}But, if we have this feature(Default implementation for interface), we
can rewrite like below:type Writer interface {
Write(b []byte) (n int, err error)
}
func (w Writer) WriteString(s string) (n int, err error) {
return w.Write([]byte(s))
}The strange interface stringWriter not needed because if your Writer can
overides WriteString method. And using WriteString as a method of Writer
better than a package-level function.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#16254 (comment), or mute
the thread
https://github.com/notifications/unsubscribe/AAAcA-KCxmX_ZbT1Qlrr2-ghhpM-TrExks5qSe7BgaJpZM4JD1Cm
.
|
I'm sorry, I cannot see how you could write down the rules for how the I vote to close this proposal. On Tue, 5 Jul 2016, 15:42 王仕晋 notifications@github.com wrote:
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mkideal
commented
Jul 5, 2016
|
Thanks, bye bye! |
mkideal commentedJul 3, 2016
•
edited
Edited 1 time
-
mkideal
edited Jul 3, 2016 (most recent)
Can we support default implementation for interface?
Here is an example:
Now, if I have a struct
DBTransactionwhich implementsBegin(),Exec() errorandEnd()methods(i.e. implements interfaceTransaction), thenDBTransactionautomatically ownsProcess() errormethod while it's used asTransaction.