Unexpected circular type definition limitation

92 views
Skip to first unread message

christoph...@gmail.com

unread,
Jun 15, 2023, 4:15:59 AM6/15/23
to golang-nuts
It is possible to define two structures globally with mutual type dependency as this:

type A struct {
    B []B
}

type B struct {
    A A[]
}

but I just noticed that we can't do that inside a function:

func Foo() {
    type A struct {
        B []B
    }
   
    type B struct {
       A A[]
    }
}

Is there a reason for this limitation ?

I would like to use this inside a test function to avoid polluting the name space and so that I can reuse these simple type names for different tests with slightly different definitions.


Jan Mercl

unread,
Jun 15, 2023, 4:29:48 AM6/15/23
to christoph...@gmail.com, golang-nuts
On Thu, Jun 15, 2023 at 10:16 AM christoph...@gmail.com
<christoph...@gmail.com> wrote:

> It is possible to define two structures globally with mutual type dependency as this:
>
> type A struct {
> B []B
> }
>
> type B struct {
> A A[]
> }
>
> but I just noticed that we can't do that inside a function:
>
> func Foo() {
> type A struct {
> B []B
> }
>
> type B struct {
> A A[]
> }
> }
>
> Is there a reason for this limitation ?

Syntax error: https://go.dev/play/p/ZOGyZyQDW0I

Christophe Meessen

unread,
Jun 15, 2023, 4:32:35 AM6/15/23
to Jan Mercl, christoph...@gmail.com, golang-nuts
The following playground example shows the problem:

https://go.dev/play/p/1kC2j57M_fW
--
Bien cordialement,
Ch.Meessen

Axel Wagner

unread,
Jun 15, 2023, 4:47:39 AM6/15/23
to Christophe Meessen, golang-nuts
Type declarations in functions are only scoped from the point of their declaration until the end of the function.
So the reason you can not do the recursive type definition in a function is that at the point of the first declaration, the second is not yet in scope.
Package scoped declarations are different from function scoped definitions, because in a function, you have a notion of "progress" - one statement comes after the next. At the package scope, that isn't he case. All package scoped declarations are "simultaneous", in a sense. That was intentional, to avoid an issue C has, where you have to sometimes declare a function before separately, to get mutual recursion.

I think it would have been possible to make type declarations apply to the entire function scope. But that wouldn't even solve the entire issue - for example, you run into a similar problem when defining recursive functions locally. Python does actually solve this by making every declaration apply to the entire function scope - but that has its own surprises. Either way, it's a decision that was made and we can't really reverse it now, as it would break existing code. For example, you can do this today:

func F(x int) {
    x = 42
    type x string
    var y x
}

which would presumably break.

Ultimately, you just have to bite the bullet here and define your types at package scope. You can always solve name spacing issues by splitting it up into separate packages.

--
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/801e7e6b-d3f8-c1df-8eae-46aa619d49a5%40gmail.com.

Brian Candler

unread,
Jun 15, 2023, 4:52:36 AM6/15/23
to golang-nuts
> You can always solve name spacing issues by splitting it up into separate packages.

Or type aliases:
Reply all
Reply to author
Forward
0 new messages