Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: Go 2: permit goto over declaration if variable is not used after goto label #26058

Open
pjebs opened this Issue Jun 26, 2018 · 15 comments

Comments

Projects
None yet
7 participants
@pjebs
Copy link

pjebs commented Jun 26, 2018

Right now you get this error: goto SKIP jumps over declaration of queryArgs

if len(s.standardDays) == 0 {
goto SKIP
}

queryArgs := []interface{}{}
//Do stuff with queryArgs

SKIP:
//Do stuff here BUT queryArgs is not used ANYWHERE from SKIP onwards

Currently I have to refactor all my code like this (including placing var err error at the top):

var queryArgs []interface{}

if len(s.standardDays) == 0 {
goto SKIP
}

queryArgs = []interface{}{}
//Do stuff with queryArgs

SKIP:
//Do stuff here BUT queryArgs is not used ANYWHERE from SKIP onwards
@pjebs

This comment has been minimized.

Copy link
Author

pjebs commented Jun 26, 2018

This can be fixed in Go 1 too since it's backwards compatible.

@ianlancetaylor ianlancetaylor changed the title Go 2 proposal: fix goto proposal: Go 2: permit goto over declaration if variable is not used after goto label Jun 26, 2018

@gopherbot gopherbot added this to the Proposal milestone Jun 26, 2018

@gopherbot gopherbot added the Proposal label Jun 26, 2018

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

ianlancetaylor commented Jun 26, 2018

This seems like it makes code a bit fragile: if you do this, and then later add a use of the variable, you will get a compilation error about lines that you didn't touch at all.

What is the benefit of making this change? How often does this problem arise?

@pjebs

This comment has been minimized.

Copy link
Author

pjebs commented Jun 26, 2018

The benefit is that the goto does what intuitively it is meant to do.

I can't tell you how often the problem arises because the use of goto is extremely rare ..... but when I do attempt to use goto, it arrises VERY VERY often and it usually means I have to refactor my code to place the variable definitions at the top (above the goto), rather than have the variables where they are most appropriate, and also I lose the ability to use := for variable define+assign.

Re:
if you do this, and then later add a use of the variable, you will get a compilation error about lines that you didn't touch at all.

Of the best parts of Go is how amazing and helpful the compiler is. If I later add a use of the variable, I would want to get a compilation error. It usually means that goto is no longer the best way to write the code.

@mark-rushakoff

This comment has been minimized.

Copy link
Contributor

mark-rushakoff commented Jun 26, 2018

Instead of moving variable declarations to the top, you could just introduce a new block around what you're goto-ing over:

package main

import (
	"fmt"
)

func main() {
	if true {
		goto FINISH
	}

	// New block, so it's safe to skip the declaration and assignment of secret.
	{
		secret := "You'll never see this line."
		fmt.Println(secret)
	}

FINISH:
	fmt.Println("Bye!")
}

https://play.golang.org/p/kzFxyaeOmkQ

@cznic

This comment has been minimized.

Copy link
Contributor

cznic commented Jun 26, 2018

The status quo enables optimizations that would be no more [easily] possible under the proposal.

@mark-rushakoff

This comment has been minimized.

Copy link
Contributor

mark-rushakoff commented Aug 23, 2018

Looks like this could be closed as a duplicate of #27165.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

ianlancetaylor commented Aug 23, 2018

This is a slightly different approach to the same problem.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

ianlancetaylor commented Aug 23, 2018

@griesemer

This comment has been minimized.

Copy link
Contributor

griesemer commented Aug 23, 2018

I believe the intent of this proposal is the same as in #27165 (with that proposal based on an idea discussed in May of this year at an internal Go Team summit, but only written down yesterday).

However, this proposal disallows a goto if it jumps over a variable declaration of a variable that is used (lexically) after the target label (but always allows the variable access). In contrast, proposal #27165 disallows access of a variable (lexically) after a label, if there is a goto that jumped over it's declaration (but always allows the goto).

It does not seem immediately clear which approach is better. I think we should leave this proposal open as a clearly viable alternative.

@pjebs

This comment has been minimized.

Copy link
Author

pjebs commented Oct 8, 2018

My proposal is much clearer to understand in my opinion. The alternative proposal will be confusing for beginners.

It is also Go 1 compatible. I don't think the alternative is.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

ianlancetaylor commented Oct 8, 2018

This is what I said over on #27165:

Closing in favor of #26058, which is the same idea expressed in a slightly different way. Both issues accept the same set of programs; the difference is whether the error is reported on the use of the variable or on the goto statement. The (small) advantage of #26058 is that it does not change variable scope. It just relaxes, slightly, the existing constraint on goto over a variable declaration.

(I do still think that both proposals accept the same set of programs. Might be interesting to see a program that behaves differently under the two proposals. Not very important, though.)

@pjebs

This comment has been minimized.

Copy link
Author

pjebs commented Oct 8, 2018

will it be applied to Go 1 too?

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

ianlancetaylor commented Oct 8, 2018

We aren't making any language changes until the Go 2 process starts.

Note that this has not been accepted.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

ianlancetaylor commented Oct 8, 2018

To clarify, it hasn't been declined, either. It's pending a decision.

@darkfeline

This comment has been minimized.

Copy link

darkfeline commented Jan 26, 2019

Isn't this proposal just syntactic sugar for @mark-rushakoff's suggestion? In which case the decision to accept this proposal boils down to whether we want such syntactic sugar. Consider:

if foo {
	goto done
}
x := 1
if bar {
	goto done
}
y := 1
if baz {
	goto done
}
z := 1
fmt.Println(x, y, z)
done:
doStuff()

Under this proposal, this is exactly equivalent to:

if foo {
	goto done
}
{
   	x := 1
	if bar {
		goto done
	}
        {
        	y := 1
		if baz {
			goto done
		}
                {
			z := 1
        		fmt.Println(x, y, z)
                }
        }
}
done:
doStuff()

https://play.golang.org/p/4W6wRO-rmel

The syntactic sugar would very desirable in such an example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.