FWIW I think what OP is ultimately asking about is some form of nominal
subtyping. When they say "automatic upcasting", they refer (I believe) to
what Go calls "assignability", which is in essence a subtype relationship.
So they want to be able to define a new type, that is a subtype of an
existing type, but add some methods to it.

And - controversially, perhaps - I don't think they would be anything
inherently wrong about it. Except that it means we'd have two ways to have
subtyping in the language.

First, I agree with other posters here that it would be bad if `type String
string` would create a subtype relationship between `String` and `string`.
Ultimately, we do want to have the ability to create genuinely new types,
with no relationship between them. It's an important safety mechanism. But
we could imagine having a new form of type declaration, say `type A < B`
(syntax only illustrative) that would create a new type `A`, which inherits
all methods from `B`, could add its own and which is assignable to `B` (but
not vice-versa). We basically would have three kinds of declarations: 1.
`type A B`, introducing no subtype relationship between `A` and `B`, 2.
`type A < B`, which makes `A` a subtype of `B` and 3. `type A = B`, which
makes them identical (and is conveniently equivalent to `A < B` and `B <
A`).

I think this would honestly be fine and perfectly safe. You'd still have to
explicitly declare that you want the new type to be a subtype, so you don't
get the weak typing of C/C++. And the subtype relationship would only
"flow" in one direction, so you can't *arbitrarily* mix them up.

Where difficulties would arise is that it naturally leads people to want to
subtype from *multiple* types. E.g. it would make sense wanting to do

type Quadrilateral [4]Point
func (Quadrilateral) Area() float64
type Rhombus < Quadrilateral
func (Rhombus) Angles() (float64, float64)
type Rectangle < Quadrilateral
func (Rectangle) Bounds() (min, max Point)
type Square < (Rhombus, Rectangle) // again, syntax only illustrative)

The issue this creates is that subtype relationships are transitive and in
this case would become *path-dependent*. `Square` is a subtype of
`Quadrilateral`, but it can get there either via `Rhombus` or via
`Rectangle` and it's not clear which way to get there. This matters if
`Rhombus` or `Rectangle` (or both) start overwriting methods of
`Quadrilateral`. The compiler needs to decide which method to call. Usually
it does that by defining some tie-breaks, e.g. "use the type named first in
the subtype declaration". But there is a lot of implicity there and with
deeper hierarchies, you can get spooky breakages at a distance, if some
type in the middle of the hierarchy does some seemingly harmless change
like overloading a method. Look up "Python Method Resolution Order" for the
kinds of problems that can arise.

Structural subtyping does not have these issues, because the subtype
relationship is completely determined by a subset relationship - in Go's
case, sets of methods of the dynamic type of the interface. And since it
can't override methods, there is no path-dependence - any two methods sets
uniquely determine a maximal common subset and a minimum common superset
and the path from any interface type to any other interface is unique
(structural subtyping is a Lattice
<https://en.wikipedia.org/wiki/Lattice_(order)>).

I think any kind of subtyping relationship *should* ultimately allow you to
have multiple super types - these kinds of hierarchies are just far too
common to ignore. For example, look at the `io` package - pretty much every
combination of `Reader`, `Writer` and `Closer` has some reasonable use
cases. I also think there are good technical reasons to avoid the
path-dependency pitfall. So it seems to me an easily defensible decision to
use structural subtyping as the primary form of subtype relationship, as it
allows you to have the benefits without the problems.

We could do both (and disallow multiple inheritance for the nominal subtype
relationship). But I also think it's easy to argue that this is redundant
and a bit confusing. And ultimately you *can* express most of the useful
hierarchies, even if you need a bit more boilerplate.

On Fri, Oct 20, 2023 at 8:07 AM Bakul Shah <ba...@iitbombay.org> wrote:

> On Oct 19, 2023, at 9:02 PM, Nurahmadie Nurahmadie <nurahma...@gmail.com>
> wrote:
> >
> > Is it not possible to have both _auto_ downcasting and new method
> binding to work in Go?
>
> What you are suggesting may make things more *convenient* but
> at the same time the potential for accidental mistakes goes
> up. The key is find a happy medium. Not too much discipline,
> not too much freedom!
>
>
> --
> 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+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/BB7C6A9A-F0BE-4180-B495-93E4B195EA97%40iitbombay.org
> .
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAEkBMfHRZLhxCM%2BMRNK7san%3D_%3DSgRF79QfZgKhu1%3Df1twWdSRw%40mail.gmail.com.

Reply via email to