understanding interface conversions

124 views
Skip to first unread message

Rory Campbell-Lange

unread,
Sep 22, 2022, 6:28:05 PM9/22/22
to golan...@googlegroups.com
This email follows my email yesterday "cannot convert fs.FS zip file to io.ReadSeeker (missing Seek)". Thanks very much to those who replied and provided solutions.

Following that, I'm interested to learn how people negotiate interface interchangeability in their programmes as my query above showed a basic misunderstanding of how that operates and how to approach the topic in general.

At a basic level my assumption that an fs.File would be "file like" and therefore act like a file was upended by the need for a PDF importer library to require an *io.ReadSeeker. This assumption broke for an fs.File from a zip archive since that doesn't support seeking. That is logical but was hard to find out. Although I can easily jump to methods and see related docs using vim-go, I still find interface interpolation (if that is a reasonable term) difficult to understand.

At a more abstract level, the concept of interfaces was a key attraction to me of go, next to goroutines. They not only promise loose coupling of independently developed pieces, but also allow functionality to be easily re-used through types sharing method signatures, not to mention interface embedding. But, perhaps because of my background in python and SQL, I find this abstraction tricky to grasp. It's difficult to know, offhand, what interfaces are best to implement in a particular case. That difficulty is compounded when one interface can be interpolated (in some cases only, depending on the underlying concrete type) to another interface. The set of possible interface "contracts" offered to an fs.File, for example, could approach a very large number (ignoring interface{}) depending on the underlying concrete type.

The https://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go article (pointed to by "Go by Example") by Jordan Orelli uses the example of "...the Animal type will be an interface, and we’ll define an Animal as being anything that can speak". He writes:

We start by defining our Animal interface:

type Animal interface {
Speak() string
}

I suppose my question is (and forgive me if this is a terrifically naive), how can one negotiate the go landscape of commonly used modules to re-utilise, where possible, a more commonly named interface implementing "Speak()" or convertible to provide "Speak()"?

Finally I was surprised that I did not get a compile-time error when trying to convert an fs.File to a io.ReadSeeker for the (possible) case when an underlying concrete type did not support Seek.

Many thanks,
Rory

Robert Engels

unread,
Sep 22, 2022, 6:47:54 PM9/22/22
to golan...@googlegroups.com
I struggle with the same in any large project. You have to hope they documented the api very well.

Needless to say I’m not a fan of “duck typing”. It makes a few things easier and a lot of important things much harder.

> On Sep 22, 2022, at 5:27 PM, Rory Campbell-Lange <ro...@campbell-lange.net> wrote:
>
> This email follows my email yesterday "cannot convert fs.FS zip file to io.ReadSeeker (missing Seek)". Thanks very much to those who replied and provided solutions.
> --
> 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.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/YyzhV8S8WgH7mrJK%40campbell-lange.net.

Ian Davis

unread,
Sep 22, 2022, 7:58:05 PM9/22/22
to golan...@googlegroups.com
On Thu, 22 Sep 2022, at 11:27 PM, Rory Campbell-Lange wrote:

I just wanted to respond to this part:

> I suppose my question is (and forgive me if this is a terrifically
> naive), how can one negotiate the go landscape of commonly used modules
> to re-utilise, where possible, a more commonly named interface
> implementing "Speak()" or convertible to provide "Speak()"?
>

Generally, when writing Go, the consumer of the object defines the interface it requires. So rather than you looking for interfaces that might exist in the wild, it's better to focus on your application and its needs. If you have a component that uses the Speak method on objects then define that as an interface that your component can accept. Any other user of your component can see that interface is needed and provide a suitable object that implements it or create a shim to adapt one.


Robert Engels

unread,
Sep 22, 2022, 8:08:38 PM9/22/22
to Ian Davis, golan...@googlegroups.com
100% true. The difficulty when examining a “large” system is that it becomes very difficult to understand the relationships. Documentation can help but it is not a great substitute for automated tools.

In Java - actually all of OO - type casting is severely frowned upon - but it seems a lot of Go code does it liberally.

If I designed a language today I would prohibit any type casts. It is a huge problem and points to insufficient design skills.

> On Sep 22, 2022, at 6:57 PM, Ian Davis <m...@iandavis.com> wrote:
> --
> 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.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/1fb8a3c4-b135-4ab1-b969-d6f4c239b7d9%40www.fastmail.com.

burak serdar

unread,
Sep 22, 2022, 8:20:11 PM9/22/22
to Rory Campbell-Lange, golan...@googlegroups.com
On Thu, Sep 22, 2022 at 4:27 PM Rory Campbell-Lange <ro...@campbell-lange.net> wrote:
This email follows my email yesterday "cannot convert fs.FS zip file to io.ReadSeeker (missing Seek)". Thanks very much to those who replied and provided solutions.

Following that, I'm interested to learn how people negotiate interface interchangeability in their programmes as my query above showed a basic misunderstanding of how that operates and how to approach the topic in general.

At a basic level my assumption that an fs.File would be "file like" and therefore act like a file was upended by the need for a PDF importer library to require an *io.ReadSeeker. This assumption broke for an fs.File from a zip archive since that doesn't support seeking. That is logical but was hard to find out. Although I can easily jump to methods and see related docs using vim-go, I still find interface interpolation (if that is a reasonable term) difficult to understand.

At a more abstract level, the concept of interfaces was a key attraction to me of go, next to goroutines. They not only promise loose coupling of independently developed pieces, but also allow functionality to be easily re-used through types sharing method signatures, not to mention interface embedding. But, perhaps because of my background in python and SQL, I find this abstraction tricky to grasp. It's difficult to know, offhand, what interfaces are best to implement in a particular case. That difficulty is compounded when one interface can be interpolated (in some cases only, depending on the underlying concrete type) to another interface. The set of possible interface "contracts" offered to an fs.File, for example, could approach a very large number (ignoring interface{}) depending on the underlying concrete type.

The https://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go article (pointed to by "Go by Example") by Jordan Orelli uses the example of "...the Animal type will be an interface, and we’ll define an Animal as being anything that can speak". He writes:

I think one of the problems in this particular example is that it is for some reason easy for people to accept Animal type to be something that can speak. I can see that it is simply an example to show the mechanics of interfaces, but it also sets the expectation that the interface name means more than what it actually is: in Go, an interface is simply a method set. This is a difficult concept for people coming from other languages. So you can have:

if speaker, yes:=someInterfaceValue.(interface{Speak() string}); yes {
    spearer.Speak()
}

without having a named interface at all.

That is one of the properties of duck-typing I enjoy, especially after working with Java for many years. In Java, an interface is a contract. In Go, an interface is just a method set, which can be used as a contract.


    We start by defining our Animal interface:

    type Animal interface {
        Speak() string
    }

I suppose my question is (and forgive me if this is a terrifically naive), how can one negotiate the go landscape of commonly used modules to re-utilise, where possible, a more commonly named interface implementing "Speak()" or convertible to provide "Speak()"?

Finally I was surprised that I did not get a compile-time error when trying to convert an fs.File to a io.ReadSeeker for the (possible) case when an underlying concrete type did not support Seek.

Many thanks,
Rory

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

burak serdar

unread,
Sep 22, 2022, 8:25:03 PM9/22/22
to Robert Engels, Ian Davis, golan...@googlegroups.com
On Thu, Sep 22, 2022 at 6:08 PM Robert Engels <ren...@ix.netcom.com> wrote:
100% true. The difficulty when examining a “large” system is that it becomes very difficult to understand the relationships. Documentation can help but it is not a great substitute for automated tools.

In Java - actually all of OO - type casting is severely frowned upon - but it seems a lot of Go code does it liberally.

If I designed a language today I would prohibit any type casts.  It is a huge problem and points to insufficient design skills.

Type-assertion is not exactly type-casting, though. And Go isn't exactly OO. 
 


> On Sep 22, 2022, at 6:57 PM, Ian Davis <m...@iandavis.com> wrote:
>
> On Thu, 22 Sep 2022, at 11:27 PM, Rory Campbell-Lange wrote:
>
> I just wanted to respond to this part:
>
>> I suppose my question is (and forgive me if this is a terrifically
>> naive), how can one negotiate the go landscape of commonly used modules
>> to re-utilise, where possible, a more commonly named interface
>> implementing "Speak()" or convertible to provide "Speak()"?
>>
>
> Generally, when writing Go, the consumer of the object defines the interface it requires. So rather than you looking for interfaces that might exist in the wild, it's better to focus on your application and its needs. If you have a component that uses the Speak method on objects then define that as an interface that your component can accept. Any other user of your component can see that interface is needed and provide a suitable object that implements it or create a shim to adapt one.
>
>
> --
> 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.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/1fb8a3c4-b135-4ab1-b969-d6f4c239b7d9%40www.fastmail.com.

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

Robert Engels

unread,
Sep 22, 2022, 8:31:03 PM9/22/22
to burak serdar, Ian Davis, golan...@googlegroups.com
I would like to understand the reason to type assert but not cast? That is an OO design flaw.

On Sep 22, 2022, at 7:24 PM, burak serdar <bse...@computer.org> wrote:



burak serdar

unread,
Sep 22, 2022, 8:58:18 PM9/22/22
to Robert Engels, Ian Davis, golan...@googlegroups.com
On Thu, Sep 22, 2022 at 6:30 PM Robert Engels <ren...@ix.netcom.com> wrote:
I would like to understand the reason to type assert but not cast? That is an OO design flaw.

You can only type-assert an interface. With type-assertion, you are either checking if the underlying value of an interface is a specific type, or if the value underlying the interface also implements a different set of methods.

And Go isn't OO.

Robert Engels

unread,
Sep 22, 2022, 9:01:58 PM9/22/22
to burak serdar, Ian Davis, golan...@googlegroups.com
Exactly. The world figured out long ago that OO and it’s principles are a better way to go. The fact that Go is not OO doesn’t make it bad or not useful - but the proponents of that state doesn’t make it better. 

On Sep 22, 2022, at 7:58 PM, burak serdar <bse...@computer.org> wrote:



Robert Engels

unread,
Sep 22, 2022, 9:06:17 PM9/22/22
to burak serdar, Ian Davis, golan...@googlegroups.com
As a follow up, good OO is not easy. It’s not for everyone. If you have a utility need it’s probably overkill - but so many of the discussions in this list revolve around people not understanding OO and what it provides. 

On Sep 22, 2022, at 8:01 PM, Robert Engels <ren...@ix.netcom.com> wrote:



Robert Engels

unread,
Sep 22, 2022, 9:08:44 PM9/22/22
to burak serdar, Ian Davis, golan...@googlegroups.com
And on more follow up, you could do interface based design in C - aka Linux - the principles do not depend on a particular language but certain languages make it easier. 

On Sep 22, 2022, at 8:01 PM, Robert Engels <ren...@ix.netcom.com> wrote:



burak serdar

unread,
Sep 22, 2022, 9:13:04 PM9/22/22
to Robert Engels, Ian Davis, golan...@googlegroups.com
On Thu, Sep 22, 2022 at 7:01 PM Robert Engels <ren...@ix.netcom.com> wrote:
Exactly. The world figured out long ago that OO and it’s principles are a better way to go. The fact that Go is not OO doesn’t make it bad or not useful - but the proponents of that state doesn’t make it better. 

I, for one, disagree with the assessment that OO principles are the better way of doing things. If good OO is hard to do, which I agree with, then most OO programs out there are wrong. I think OO with very limited inheritance and a more pragmatic approach to encapsulation is much easier to get right, which is, I believe, something Go got right.

Dan Kortschak

unread,
Sep 22, 2022, 10:14:18 PM9/22/22
to golan...@googlegroups.com
On Thu, 2022-09-22 at 20:01 -0500, Robert Engels wrote:
> The world figured out long ago that OO and it’s principles are a
> better way to go.

This is a very strong assertion (pun not intended). I heartily disagree
with the claim, particularly when it comes to how OO is implemented by
class-based languages. They take the world, which is messy and attempt
to fit it into a clean hierarchical taxonomy. We've had a couple of
hundred years to learn that this kind of taxonomic approach is
insufficiently powerful to properly describe the world in the general
case.

Kurtis Rader

unread,
Sep 22, 2022, 10:50:29 PM9/22/22
to Dan Kortschak, golan...@googlegroups.com
I concur. I remember languages like Prolog and similar attempts at "expert systems" in the 1980's. I've also been underwhelmed by classic OO; especially the problems created by multiple-inheritance as used in languages like Python and C++. I'm not a CS major (just a practicing SWE who started programming in the Jurassic period) so my viewpoint is likely widely out of date. Nonetheless, I find the Go approach preferable to older object oriented languages.

--
Kurtis Rader
Caretaker of the exceptional canines Junior and Hank

Robert Engels

unread,
Sep 23, 2022, 12:20:25 AM9/23/22
to golan...@googlegroups.com
I didn’t expect a warm reception.  :)

I’m not by any stretch an OO purist - which is a big reason I like Go. I’m not here as a troll. 

I think many people got side tracked with the Gof4 and thought that was OO. Interfaced based design - which I think is a foundational principle of OO - is incredibly powerful and leads to far more maintainable systems. 

BUT - it requires people capable of building “proper” apis. It is a difficult skill to master - as much art as science - but when you’re exposed to great apis you just “know”. So much skill and experience comes into play to do it right. The Java peeps didn’t get everything right but as a whole they did so much for the community. Where other lesser orgs took it is on them. And there’s a lot of bad Java - and a lot of bad C and C++ and Go and so on. 

I “think” I understand the Go creators thoughts when it comes to duck typing - but when you use Go in a large system it’s a problem. 

On Sep 22, 2022, at 9:50 PM, Kurtis Rader <kra...@skepticism.us> wrote:


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

Rory Campbell-Lange

unread,
Sep 23, 2022, 8:01:45 AM9/23/22
to burak serdar, golan...@googlegroups.com
On 22/09/22, burak serdar (bse...@computer.org) wrote:
> On Thu, Sep 22, 2022 at 4:27 PM Rory Campbell-Lange <ro...@campbell-lange.net>
> wrote:
>
> > ...I'm interested to learn how people negotiate interface
> > interchangeability in their programmes as my query above showed a basic
> > misunderstanding of how that operates and how to approach the topic in
> > general.
> >
...
> > ...Jordan Orelli uses the example of "...the Animal type will be an
> > interface, and we’ll define an Animal as being anything that can speak". He
> > writes:
>
> I think one of the problems in this particular example is that it is for
> some reason easy for people to accept Animal type to be something that can
> speak. I can see that it is simply an example to show the mechanics of
> interfaces, but it also sets the expectation that the interface name means
> more than what it actually is: in Go, an interface is simply a method set.
> This is a difficult concept for people coming from other languages. So you
> can have:
>
> if speaker, yes:=someInterfaceValue.(interface{Speak() string}); yes {
> spearer.Speak()
> }
>
> without having a named interface at all.
>
> That is one of the properties of duck-typing I enjoy, especially after
> working with Java for many years. In Java, an interface is a contract. In
> Go, an interface is just a method set, which can be used as a contract.

Thank you for thoughtful comment about interface names being simply labels on method sets.

In this case the compiler did not enforce the contract. (As I noted in my original email, converting an fs.File to an io.ReadSeeker for an underlying zip file failed, but only at runtime).

If interfaces provide contracts, though, it would be great if type "interface satisfaction"[1] could be more thoroughly checked at compile time.

Regards,
Rory

[1] The description "Interface Satisfaction" is used in section 7.3 of "The Go Programming Language"


Rory Campbell-Lange

unread,
Sep 23, 2022, 8:07:43 AM9/23/22
to Ian Davis, golan...@googlegroups.com
I find this is a very interesting perspective. It certainly seems easier to think about defining interfaces for one's own types than trying to select from n possible interface "contracts" on offer.

I assume, though, that it makes sense to support commonly occuring method sets a.k.a. interfaces to improve reusability and readability of one's own modules? If so, how does one go about getting to know what those commonly occuring interfaces are?

Thanks
Rory
Reply all
Reply to author
Forward
0 new messages