The "declared and not used" error

6,395 views
Skip to first unread message

Brett

unread,
Dec 16, 2011, 6:19:36 PM12/16/11
to golan...@googlegroups.com
Hey all,

I've been trying to learn and use Go more. I wanted to share with you the difficulty I found as a beginner with the specific error "declared and not used". I thought the best way to illustrate how this felt to me is by showing you a beginner's session from the Go playground.


Round 1: Run hello world

package main
import "fmt"
func main() {
  fmt.Printf("Hello World\n")
}

> Hello World


Round 2: Cool; now let me try a nice literal

package main
import "fmt"
func main() {
  fmt.Printf("Hello World\n") 
  foo := []int{1,2,3}
}
 
prog.go:5: foo declared and not used

Round 3: Doh; well, at least it compiled otherwise; I'll just use it in a loop, that should fix it

package main
import "fmt"
func main() {
  fmt.Printf("Hello World\n") 
  foo := []int{1,2,3}
  for i := range foo {
    fmt.Printf("Yay\n")
  }
}

prog.go:6: i declared and not used

Round 4: Doh again; searched around a bit and found mention of the blank identifier (http://golang.org/doc/effective_go.html#maps); I'll try that

package main
import "fmt"
func main() {
  fmt.Printf("Hello World\n") 
  foo := []int{1,2,3}
  for _ := range foo {
    fmt.Printf("Yay\n")
  }
}

prog.go:6: no new variables on left side of :=

Round 5: Doh thricely; I guess I need the other kind of equals sign or something

package main
import "fmt"
func main() {
  fmt.Printf("Hello World\n") 
  foo := []int{1,2,3}
  for _ = range foo {
    fmt.Printf("Yay\n")
  }
}

> Hello world
Yay
Yay
Yay

At last!


My first impression was that I was getting a lot of errors for such simple beginner code. This turned me off a lot. As I have continued writing more complex programs, I still find myself grappling with "declared and not used" frequently. I'm not sure why this is the case; maybe I'm a breadth-first coder and build scaffolding too early?

Either way, I'm concerned this kind of thing is hurting the adoption of Go. I expect people on this list to say "you're just an idiot". But seriously, I think this little thing may be important. So hypothetically, what minimal changes to Go (language, tools) could improve this experience for beginners?

Thanks,

-Brett


PS: If you agree with me but are embarrassed, feel free to reply privately and I'll keep your identity a secret!

Sanjay Menakuru

unread,
Dec 16, 2011, 9:32:30 PM12/16/11
to golan...@googlegroups.com
Hey,

Well, I find this error make it pretty nice to read Go code written by other people, because its very obvious when they're 'throwing away' a value. No more playing the 'did they ever use this variable in this 70 line function' game. You can recognize _ without context, much as one recognizes /dev/null in a shell script.

Secondly, you have to admit the error message and the progression to a working program was relatively intuitive even for a newcomer. (I remember my first legit g++ template error... ahh the bad old days).

As to grappling with this error in my own code, I haven't found this to be the case.

Sanjay


Rodrigo Moraes

unread,
Dec 17, 2011, 1:05:21 AM12/17/11
to golang-nuts, Brett
This wasn't an issue for me. Really. The error is very clear: you must
use the stuff you declare or comment it out.

> So hypothetically, what minimal
> changes to Go (language, tools) could improve this experience for beginners?

Maybe give more attention to it in the beginner tutorials. And
introduce some tricks. I now commonly use _ when prototyping when I
expect that error:

foo := []int(1, 2, 3}
_ = foo

or:

import "fmt"
_ = fmt.Printf

This totally defeats the purpose of the error, but throw a rock if you
don't do that sometimes. :)

I remember wondering about make() and new() when I was learning. I
still think they should be a single polymorphic built-in, now for
other reasons. But this is a different subject.

-- rodrigo

Christoffer Hallas

unread,
Dec 18, 2011, 5:18:33 PM12/18/11
to golan...@googlegroups.com
I have a hard time understand people who complain about this.

How can it bother you, and turn you off, that you have to write understandable and maintainable code?

If you just want to print out "Yay!" three times, simply:

package main

func main() {
println("Hello world")
for _ = range [3]int{} {
println("Yay")
}
}

On a side note, I'd like to see an actual use for a program that does this.

Newcomers to Go needs to see Go for what it is. For me it's a tool that helps me with a lot of things, including becoming somewhat a better programmer, at least it forces me to appreciate the pretty little details that makes me proud of what I do, like a carpenter would appreciate a beautifully crafted piece of wood.

And I don't think you're an idiot. :)

Best regards

Andrew Gerrand

unread,
Dec 18, 2011, 6:53:25 PM12/18/11
to golan...@googlegroups.com
On Saturday, December 17, 2011 10:19:36 AM UTC+11, Brett wrote:
Either way, I'm concerned this kind of thing is hurting the adoption of Go. I expect people on this list to say "you're just an idiot". But seriously, I think this little thing may be important. So hypothetically, what minimal changes to Go (language, tools) could improve this experience for beginners?

At the risk of sounding a bit harsh, I'm not sure how much time we should invest in people who are put off by a few compile errors when learning a new language. If the errors are inscrutable, we should certainly improve them. In this case it is clear what the problem is, and you were able to resolve the problem by further experimenting with the language.

Besides, this is just one of many differences to which one must adjust when learning a new language. This may be your particular bugbear, but someone else might be bothered by the variable declaration syntax. That doesn't mean we should change it.

"It makes it easier for beginners," is not a good criteria for changing the language (or the behavior of the compiler, as in this case). For instance, long discussions about "make" vs "new" have always concluded with something like "it may be harder for beginners, but once you understand it, it becomes clear." The same is true here; the "no unused variables" rule has an important function - it catches programming errors that would be otherwise difficult to detect.

Andrew

Jan Mercl

unread,
Dec 18, 2011, 7:07:46 PM12/18/11
to golan...@googlegroups.com
On Monday, December 19, 2011 12:53:25 AM UTC+1, Andrew Gerrand wrote:

Yeah, unused values... After years of coding in Go this still, though not so often anymore, bites me in *every case I deserve it* (modulo perhaps some few false positives).

I'm pretty happy being bitten in this specific way. It perpetually saves me uncountable hours of debugging headaches ;-)

Rodrigo Moraes

unread,
Dec 18, 2011, 8:10:57 PM12/18/11
to golang-nuts
On Dec 18, 9:53 pm, Andrew Gerrand wrote:
> For instance,
> long discussions about "make" vs "new" have always concluded with something
> like "it may be harder for beginners, but once you understand it, it
> becomes clear."

I was told that this discussion happened many times; I don't follow
the list as closely as I'd like so I missed them all. A while ago this
occurred to me about make() vs new(): I had a struct "foo" with some
fields and methods that later I refactored to be a simple map. So
suddenly what was "f := new(foo)" had to be "f := make(foo)" (http://
play.golang.org/p/OcQfM4Y2z5). It is not a common case but I wish this
could be avoided. I know the difference between make and new and that
it won't change; but I still think they should be a single built-in
just because it would taste better. No big deal anyway.

Sorry for the off-topic. ;)

-- rodrigo

David Symonds

unread,
Dec 18, 2011, 8:43:44 PM12/18/11
to Rodrigo Moraes, golang-nuts
On Mon, Dec 19, 2011 at 12:10 PM, Rodrigo Moraes
<rodrigo...@gmail.com> wrote:

> I was told that this discussion happened many times; I don't follow
> the list as closely as I'd like so I missed them all. A while ago this
> occurred to me about make() vs new(): I had a struct "foo" with some
> fields and methods that later I refactored to be a simple map. So
> suddenly what was "f := new(foo)" had to be "f := make(foo)" (http://
> play.golang.org/p/OcQfM4Y2z5). It is not a common case but I wish this
> could be avoided. I know the difference between make and new and that
> it won't change; but I still think they should be a single built-in
> just because it would taste better. No big deal anyway.

If you're expecting the calling code to use the object directly (e.g.
indexing) then the type's underlying type matters, and you're probably
going to have to update more than just the object construction. If
you're wanting to insulate the underlying type identity then you
probably want to add a NewT constructor function.


Dave.

Kees Varekamp

unread,
Dec 18, 2011, 10:59:37 PM12/18/11
to golan...@googlegroups.com
+1 from me for making this a configurable compiler flag.  It's pretty much the only thing that I wish was different from the way it is.  When I'm prototyping some code or debugging it there are often variables or packages that sometimes I use, and sometimes I don't.  Currently I constantly need to do something like commenting them out , rename them to _, or print them just to make my code compile, which always seems a bit silly to me.

And it would make it easier for beginners, too :-)

John Asmuth

unread,
Dec 18, 2011, 11:53:53 PM12/18/11
to golan...@googlegroups.com
"If it's worth warning about, it's worth fixing." - Abraham Lincoln.

Also, down with any more compiler flags than are completely necessary.

Daniel Jo

unread,
Dec 18, 2011, 11:54:20 PM12/18/11
to golan...@googlegroups.com


On Sun, Dec 18, 2011 at 8:59 PM, Kees Varekamp <ke...@mroffice.org> wrote:
+1 from me for making this a configurable compiler flag.  It's pretty much the only thing that I wish was different from the way it is.  When I'm prototyping some code or debugging it there are often variables or packages that sometimes I use, and sometimes I don't.  Currently I constantly need to do something like commenting them out , rename them to _, or print them just to make my code compile, which always seems a bit silly to me.

And it would make it easier for beginners, too :-)

At first I had the exact same problem as you, but as I've gotten more and more used to the language I've started automatically remembering to comment out variables when I disable certain functionality during debugging. Also, from the docs:

"Some have asked for a compiler option to turn those checks off or at least reduce them to warnings. Such an option has not been added, though, because compiler options should not affect the semantics of the language and because the Go compiler does not report warnings, only errors that prevent compilation.

There are two reasons for having no warnings. First, if it's worth complaining about, it's worth fixing in the code. (And if it's not worth fixing, it's not worth mentioning.) Second, having the compiler generate warnings encourages the implementation to warn about weak cases that can make compilation noisy, masking real errors that should be fixed."


-Daniel

Norbert Roos

unread,
Dec 19, 2011, 5:16:38 AM12/19/11
to golan...@googlegroups.com
On 12/19/2011 05:54 AM, Daniel Jo wrote:

> *There are two reasons for having no warnings. First, if it's worth


> complaining about, it's worth fixing in the code. (And if it's not worth
> fixing, it's not worth mentioning.)

There is at least one case where this is not true:

i:= 0

for i := 0; true; i++ {
if something
break
}

fmt.Printf("processed %d\n", i)


Imagine this in a larger function, where the error is not so obvious.
This _is_ something worth complaining - or warning - about, but it's
still valid go code. Those programming mistakes do happen, and not
warning me about it costed me in this particular case about half an hour
to find. Compared to 30s with a warning.

And the bad thing: I know right now it will happen again, and i will
again start searching for the error, at other locations, where it
becomes visible for the first time.

> Second, having the compiler generate
> warnings encourages the implementation to warn about weak cases that can
> make compilation noisy, masking real errors that should be fixed

The implementation could still be modified in a way that no warnings are
generated. When programming in C, i am very happy to get warnings, and i
try to eliminate all of them, so in the end the output is a silent as
with warnings disabled.

Norbert

Jim Whitehead II

unread,
Dec 19, 2011, 5:38:08 AM12/19/11
to Norbert Roos, golan...@googlegroups.com
On Mon, Dec 19, 2011 at 10:16 AM, Norbert Roos <nr...@webware-experts.de> wrote:
> On 12/19/2011 05:54 AM, Daniel Jo wrote:
>
>> *There are two reasons for having no warnings. First, if it's worth
>>
>> complaining about, it's worth fixing in the code. (And if it's not worth
>> fixing, it's not worth mentioning.)
>
>
> There is at least one case where this is not true:
>
> i:= 0
>
> for i := 0; true; i++ {
>  if something
>    break
> }
>
> fmt.Printf("processed %d\n", i)
>
>
> Imagine this in a larger function, where the error is not so obvious. This
> _is_ something worth complaining - or warning - about, but it's still valid
> go code. Those programming mistakes do happen, and not warning me about it
> costed me in this particular case about half an hour to find. Compared to
> 30s with a warning.
>
> And the bad thing: I know right now it will happen again, and i will again
> start searching for the error, at other locations, where it becomes visible
> for the first time.

I think you have proven the case we're talking about. This code
doesn't do what you think it does, the outer i is never incremented
(even once) and the value of the inner one is thrown away when the
loop is completed. This is precisely the kind of error you WANT the
compiler to tell you about.

What you wanted to do was have the outer i declared (as you do) and
then increment that within the for loop, breaking when your condition
is met. No error, fixes a bug in your code, and much clearer what is
going on.

>> Second, having the compiler generate
>> warnings encourages the implementation to warn about weak cases that can
>> make compilation noisy, masking real errors that should be fixed>
>
> The implementation could still be modified in a way that no warnings are
> generated. When programming in C, i am very happy to get warnings, and i try
> to eliminate all of them, so in the end the output is a silent as with
> warnings disabled.

All Go code that compiles is guaranteed to be free from errors and
warnings. Isn't that a better guarantee?

- Jim

Norbert Roos

unread,
Dec 19, 2011, 6:03:33 AM12/19/11
to golan...@googlegroups.com
On 12/19/2011 11:38 AM, Jim Whitehead II wrote:

>> There is at least one case where this is not true:
>>
>> i:= 0
>>
>> for i := 0; true; i++ {
>> if something
>> break
>> }
>>
>> fmt.Printf("processed %d\n", i)
>>
>>
>> Imagine this in a larger function, where the error is not so obvious. This
>> _is_ something worth complaining - or warning - about, but it's still valid
>> go code. Those programming mistakes do happen, and not warning me about it
>> costed me in this particular case about half an hour to find. Compared to
>> 30s with a warning.
>>
>> And the bad thing: I know right now it will happen again, and i will again
>> start searching for the error, at other locations, where it becomes visible
>> for the first time.
>

> I think you have proven the case we're talking about. This code
> doesn't do what you think it does, the outer i is never incremented
> (even once) and the value of the inner one is thrown away when the
> loop is completed. This is precisely the kind of error you WANT the
> compiler to tell you about.

You mean the compiler generates an error because the inner i is never
used? Ok, the example was then maybe too simple. What about this one here:

var i int

for i := 0; true; i++ {

if i == 10 {
break
}
}

fmt.Printf("processed %d\n", i)


No error, but the program is doing something wrong.

> What you wanted to do was have the outer i declared (as you do) and
> then increment that within the for loop, breaking when your condition
> is met. No error, fixes a bug in your code, and much clearer what is
> going on.

Em, what fixes a bug in my code? I didn't get it.. this was just a
simple example, complex code can hide the error much better.

> All Go code that compiles is guaranteed to be free from errors and
> warnings. Isn't that a better guarantee?

This would be a better guarantee, but this is not the case. Shadowing a
variable IS a warning, go simply doesn't print the warning. So it is
actually not guaranteed to be warning-free.

I guess almost every variable shadowing is a programming error. And the
warning can easily be fixed, just by renaming the inner variable.

Norbert

Jan Mercl

unread,
Dec 19, 2011, 6:21:16 AM12/19/11
to golan...@googlegroups.com
On Monday, December 19, 2011 12:03:33 PM UTC+1, Norbert Roos wrote:

You mean the compiler generates an error because the inner i is never
used? Ok, the example was then maybe too simple. What about this one here:

var i int

for i := 0; true; i++ {
   if i == 10 {
     break
   }
}

fmt.Printf("processed %d\n", i)


No error, but the program is doing something wrong.

The program is not doing anything wrong. It's just doing something else wrt what the programmer *probably/perhaps* intended. What if the compared value be instead of 10, say 1e9 and it's e.g. a (silly but valid) HW delay loop. This is not a mechanically decidable problem. From some heuristics it can be considered as a place for a warning. But then you have the remaining valid cases generate just noise instead of real warnings.

I think if anyone insist on such warnings (the scope variable shadowing is just one of the virtually endless possibilities) then an external tool for such source code instrumentation is the way to go. In this context it's a pity the Go stdlib type checker package never reached full implementation.

Norbert Roos

unread,
Dec 19, 2011, 8:52:12 AM12/19/11
to golan...@googlegroups.com
On 12/19/2011 12:21 PM, Jan Mercl wrote:

> The program is not doing anything wrong. It's just doing something else wrt
> what the programmer *probably/perhaps* intended.

And the development tool doesn't help the programmer to avoid the
probable error, it lets him run straight into a debug session (it could
be even worse, if the error shows only under certain circumstances). The
programmer is not even allowed to enable such warnings, because

"There are two reasons for having no warnings. First, if it's worth
complaining about, it's worth fixing in the code. (And if it's not worth
fixing, it's not worth mentioning.)"

Shadowed variables _are_ worth complaining about, because they almost
every time mean something worth fixing. But there are also situations
thinkable where shadowed variables are wanted by the programmer.

Short declarations introduce a new danger of making errors, in declaring
variables where they shouldn't. So this danger should be handled by the
compiler.

> What if the compared value
> be instead of 10, say 1e9 and it's e.g. a (silly but valid) HW delay loop.

What would be wrong with it? If 1e9 is larger than the range of i, the
compiler should produce an error.

> This is not a mechanically decidable problem. From some heuristics it can
> be considered as a place for a warning. But then you have the remaining
> valid cases generate just noise instead of real warnings.

I prefer a compiler who helps me to get fast results over a bureaucratic
compiler who lets me run into traps. One of the first i do with C is to
enable -Wall. Then i improve the code untill there are no warnings left
- and no noise.

> I think if anyone insist on such warnings (the scope variable shadowing is
> just one of the virtually endless possibilities) then an external tool for
> such source code instrumentation is the way to go.

This could be one way, but i can't see what is so bad about a warning
switch in the compiler.

Norbert

Aram Hăvărneanu

unread,
Dec 19, 2011, 9:51:44 AM12/19/11
to golan...@googlegroups.com
Andrew Gerrand wrote:
> "It makes it easier for beginners," is not a good criteria for changing the
> language

I agree.

When I was a kid I used to play with hammers and nails. I've hit my
fingers a few times, but that didn't stop me, I liked what I was
doing. Hurting my fingers was a part of the learning process. Now I
know how to work with wood without hurting myself.

--
Aram Hăvărneanu

John Asmuth

unread,
Dec 19, 2011, 10:05:11 AM12/19/11
to golan...@googlegroups.com
The difference between shadowed variables and unused variables is simple.

Changing a variable to no longer be shadowed changes the semantics of the code.

Changing an unused variable to no longer exist does not change the semantics of the code.

Unused variables are universally extra stuff that does nothing and clutters up the screen. A shadowed variable can *sometimes* be a bug, but often it is intentional. For instance, sometimes people will copy/paste code in from somewhere else and they want it to behave the same way without having to go through and check all the variable names (try doing this with python!).

Or who knows, maybe they just want to. Maybe it is clearer for them and for the code.

But the bottom line is that it isn't an error, because code means something with the variable shadowed, and it means something else when the variable isn't shadowed. Why should the compiler choose which is correct? That's the programmer's job.

But unused variables are what happens when you comment out *part* of something that you want to disable. Why stop at part? Just comment it all out.

Paul Borman

unread,
Dec 19, 2011, 10:06:11 AM12/19/11
to Norbert Roos, golan...@googlegroups.com
On Mon, Dec 19, 2011 at 5:52 AM, Norbert Roos <nr...@webware-experts.de> wrote:
This could be one way, but i can't see what is so bad about a warning switch in the compiler.

One of the goals of the standard Go compiler is speed.   As you add new checks of legal syntax that my offend some programmers ideas of good code you will start to erode that goal.

The gofmt program actually has to do the first phase of a compile (that is, parse the source) but that doesn't mean we should combine gofmt and the compiler.

There is also a program called govet which discovers common mistakes with Printf and company format strings.

In this spirit, I think what you are asking for is golint.

    -Paul

Paul Borman

unread,
Dec 19, 2011, 10:09:43 AM12/19/11
to golan...@googlegroups.com
On Mon, Dec 19, 2011 at 7:05 AM, John Asmuth <jas...@gmail.com> wrote:
But unused variables are what happens when you comment out *part* of something that you want to disable. Why stop at part? Just comment it all out.

I see the error most often from unused packages.  This frequently happens during debugging and development when you want fmt and/or reflect but only need it for debugging.  For those cases, as has been suggested, I use the _ = fmt.Printf trick while debugging/developing.

I just wanted to point out the error comes from other use cases as well but there is also a solution for that case. 

chris dollin

unread,
Dec 19, 2011, 10:11:44 AM12/19/11
to Paul Borman, Norbert Roos, golan...@googlegroups.com
On 19 December 2011 15:06, Paul Borman <bor...@google.com> wrote:

> One of the goals of the standard Go compiler is speed.   As you add new
> checks of legal syntax that my offend some programmers ideas of good code
> you will start to erode that goal.

Unless you're asking for pretty sophisticated checks I'd have thought
it unlikely that the compilation speed would be noticably affected.

Chris

--
Chris "allusive" Dollin

Paul Borman

unread,
Dec 19, 2011, 10:24:24 AM12/19/11
to chris dollin, Norbert Roos, golan...@googlegroups.com
Once the gates have been opened I would expect the checking would not only increase in complexity but also in number.  No one can eat just one...

    -Paul

Norbert Roos

unread,
Dec 19, 2011, 11:46:17 AM12/19/11
to golan...@googlegroups.com
On 12/19/2011 04:05 PM, John Asmuth wrote:

> Changing a variable to no longer be shadowed changes the semantics of the
> code.
>
> Changing an unused variable to no longer exist does not change the
> semantics of the code.

Sure, an unused variable differs from a shadowed variable.

> A shadowed variable can *sometimes* be a bug, but often it
> is intentional.

I can't prove it, but i doubt it is often intentional. I would rather
call it bad programming style, as it confuses the one (or even the
original programmer a year later) who is reading the code.

But i can indeed imagine that there may be cases where shadowed
variables make sense. It's not that i would want to forbid shadowed
variables at all.

> For instance, sometimes people will copy/paste code in from
> somewhere else and they want it to behave the same way without having to go
> through and check all the variable names (try doing this with python!).

This is of course done very easy, the resulting code is not very clean.
Still the outer variables can be renamed, the warnings could be accepted
or the warnings could be disabled.

And going through the copied text and renaming the variables there is
still faster than debugging for half an hour and finding out that a
variable was shadowed. (depends on the size of the copied text)

> But unused variables are what happens when you comment out *part* of
> something that you want to disable. Why stop at part? Just comment it all
> out.

I'm not against the errors with unused variables. This is annoying, but
it's ok.

Norbert


Norbert Roos

unread,
Dec 19, 2011, 11:49:20 AM12/19/11
to golan...@googlegroups.com
On 12/19/2011 04:06 PM, Paul Borman wrote:

> There is also a program called govet which discovers common mistakes with
> Printf and company format strings.
>
> In this spirit, I think what you are asking for is golint.

If those warnings could be detected with other programs, that would be a
compromise. I would still miss it in the compiler.

Norbert

Norbert Roos

unread,
Dec 19, 2011, 11:57:25 AM12/19/11
to golan...@googlegroups.com
On 12/19/2011 04:24 PM, Paul Borman wrote:

> Once the gates have been opened I would expect the checking would not only
> increase in complexity but also in number. No one can eat just one...

I don't think there are many warning sources possible. This ":=" thing
is so far the only situation where i'm always thinking "Why did the
compiler not tell me about it?". Other things like "if (a = b) {}" are
not possible in go, anyway..

Norbert

Krzysztof Kowalik

unread,
Dec 19, 2011, 11:26:18 AM12/19/11
to Paul Borman, chris dollin, Norbert Roos, golan...@googlegroups.com
I personally love that strict spirit of go in case of variables, source code formatting etc because it forces programmer to think about the algorithms and efficiency, not about the formatting. I'm ruby dev at work and in ruby community exists something like oneliner solution... all slackers want to write the most complex stuff in one line without care about efficiency, and i hate it! Also after hours i'm big c/cpp fan and I compile my stuff with pedantic-errors switch and issuing unused vars, which is what Go does by default - but it took me long time to lear work this way. I really regret that i didn't know about that switches when i was starting with c programming years ago. Like Sanjay mentioned, you could be pissed off at all the warnings, but you found it easy and intuitive to solve them, and what's more important they teach you good practices.

Cheers,
nu7

2011/12/19 Paul Borman <bor...@google.com>

Nickos Ventouras

unread,
Dec 19, 2011, 10:36:21 PM12/19/11
to golang-nuts
On Dec 19, 5:59 am, Kees Varekamp <k...@mroffice.org> wrote:

> +1 from me for making this a configurable compiler flag.  It's pretty much
> the only thing that I wish was different from the way it is.  When I'm
> prototyping some code or debugging it there are often variables or packages
> that sometimes I use, and sometimes I don't.

+1 from me too, for exactly the same reason: prototyping and
debugging.

Nickos Ventouras

unread,
Dec 19, 2011, 10:32:47 PM12/19/11
to golang-nuts
On Dec 19, 12:18 am, Christoffer Hallas <christoffer.hal...@gmail.com>
wrote:

> If you just want to print out "Yay!" three times, simply:
>
> package main
>
> func main() {
> println("Hello world")
> for _ = range [3]int{} {
> println("Yay")
>
> }
> }

This would probably be more typical (why use range()?)

for i:=0; i<3; i++ {
fmt.Println("yay")
}


> On a side note, I'd like to see an actual use for a program that does this.

Iterating with range() and discarding index/values, or generating and
printing some string N times?

Because I need something like the latter several times a year.

Christoffer Hallas

unread,
Dec 20, 2011, 7:36:27 AM12/20/11
to Nickos Ventouras, golang-nuts
Generating a string is one thing, but simply printing the constant is another, which is what I was refering to.

John Asmuth

unread,
Dec 20, 2011, 8:18:16 AM12/20/11
to golan...@googlegroups.com
Here's a trick I like to use for debugging. Has more benefits than not having to comment out the package name when I don't use it. I can also use it to print the messages only under certain conditions (set Debug=true when entering some state, reset to false when leaving).

import (
    "os"
    "fmt"
)

var Debug = false

func printf(format string, args ...string) {
    if !Debug { return }
    fmt.Fprintf(os.Stderr, format, args...)
}

Krzysztof Kowalik

unread,
Dec 20, 2011, 9:49:08 AM12/20/11
to golan...@googlegroups.com
@John Amuth, there why you're hacking custom funcs when you can use logger:

http://play.golang.org/p/1ec88JfWAr - here's example how to handle debug mode with custom log.Logger

Cheers,
nu7

2011/12/20 John Asmuth <jas...@gmail.com>

John Asmuth

unread,
Dec 20, 2011, 9:52:46 AM12/20/11
to golan...@googlegroups.com
Hard to turn that on for only portions of the code.

Also, I'd like to be able to leave my called to printf() in the code, change "var Debug = false" to "const Debug = false" and then have gc compile it away to nothing. Or at least have the potential to, one day :)

Jesse McNelis

unread,
Jun 1, 2013, 12:00:38 AM6/1/13
to ri...@mcgeer.com, golang-nuts
On Sat, Jun 1, 2013 at 1:32 PM, <ri...@mcgeer.com> wrote:
I'm getting the "variable declared but not used" error in the following function, and I  can't see why:

func Sqrt(x float64) float64 {
    var z float64 = 1.0
    for i := 0; i < 10; i++ {
        z := (z*z - x)/(2.0 * z)
    }
    return z
}

The error is in the line "z := (z*z - x)/(2.0 * z)".  But z certainly is used; it is returned immediately following the loop.  The only way this makes sense is if the z inside the loop is different from the z outside the loop, but that would be very odd...

Not odd at all. You declared a new variable called 'z' inside the scope of the loop.
Go lets you have variables of the same name in different scopes and ':=' declares and assigns 
to a new variable. 

This is one of the reasons this compile error is important to not ignore.
 

--
=====================
http://jessta.id.au

Dougx

unread,
Jun 1, 2013, 12:40:07 AM6/1/13
to golan...@googlegroups.com, ri...@mcgeer.com, jes...@jessta.id.au
...and why the := operator is weird.

This *should* be a duplicate variable declaration error, if the it wasn't for the := weirdness.

~
Doug.

Jsor

unread,
Jun 1, 2013, 2:02:35 AM6/1/13
to golan...@googlegroups.com, ri...@mcgeer.com, jes...@jessta.id.au
I only have issues with shadowed variables in one specific instance:

var i int
for i,err := SomeFunc(); err != nil || i >= someValue; i,err = SomeFunc() {
  // Code
}
return i

I can totally get behind variable shadowing, no problem. The issue I have is when you want one variable to have loop/branch scope (usually an error or a bool), and one with broader scope. You're forced into the dilemma of making the error have a wider scope that you'd like it to, or renaming the inner variable and doing something special to make sure you assign the value to the outer/return variable every iteration.

Of course, fixing this would probably require even MORE ways to declare a variable, and we already have a fairly silly number. So I live with it.

Jesse McNelis

unread,
Jun 1, 2013, 2:19:01 AM6/1/13
to Dougx, golang-nuts, ri...@mcgeer.com
On Sat, Jun 1, 2013 at 2:40 PM, Dougx <douglas...@gmail.com> wrote:
...and why the := operator is weird.

This *should* be a duplicate variable declaration error, if the it wasn't for the := weirdness.

In this case it's nothing to do with ':=' weirdness.
It's the result of block scoping
This code does the same thing.  

func Sqrt(x float64) float64 {
    var z float64 = 1.0
    for i := 0; i < 10; i++ {
        var z float64;
        z = (z*z - x)/(2.0 * z)
    }
    return z
}

The weirdness of ':=' only happens when there is more than one return value.
--
=====================
http://jessta.id.au

Rick McGeer

unread,
Jun 1, 2013, 11:44:49 AM6/1/13
to Jesse McNelis, Dougx, golang-nuts
Thanks, everybody.  It was simply that I didn't understand the semantics of := (figured it out).  I now know that foo := bar is shorthand for
var foo 
foo = bar

as in the last block of code that Jesse sent.  This makes perfect sense now; I simply didn't understand the shorthand.

Thanks
Rick

Rick McGeer

unread,
Jun 1, 2013, 11:53:50 AM6/1/13
to Jesse McNelis, Dougx, golang-nuts
And, BTW, my own fault for not reading the tour carefully; it's covered (briefly) in slide #12 of the Go tour.

peter...@transitpros.com

unread,
Dec 1, 2017, 1:45:47 PM12/1/17
to golang-nuts
Go will throw an error when a variable isnt 'used' ( which is often the case when developing ), but will not throw errors if the code has unnecessary loops, logical errors, or other more serious problems. This does not make the code better, nor the coder magically reflect on how their code can be improved. It just makes development more annoying when you have to go back and forward and comment and change code just to please a compiler. We can all agree that  a := 0 not being used at the moment is much less of a problem than slow sloppy code that Go deems as perfectly OK. If anything, a var not being used should give me a Warning so im aware of the problem. It almost seems as if Go was developed by non-developers.




Ian Lance Taylor

unread,
Dec 1, 2017, 6:29:04 PM12/1/17
to peter...@transitpros.com, golang-nuts
This has been discussed many times in the past. See the mailing list archives.

One reason for this error that you didn't mention is to cut down on
the number of times that people get confused by shadowing of variables
when using `:=`. See https://golang.org/issue/377.

Ian

Inanc Gumus

unread,
Dec 3, 2017, 11:33:40 AM12/3/17
to golang-nuts
Hey, btw, you don't need a blank-identifier there, simply type:

package main

func main() {
println("Hello world")
for range [3]int{} {
println("Yay")
}
}

On Monday, December 19, 2011 at 1:18:33 AM UTC+3, Christoffer Hallas wrote:
I have a hard time understand people who complain about this.

How can it bother you, and turn you off, that you have to write understandable and maintainable code?

If you just want to print out "Yay!" three times, simply:

package main

func main() {
println("Hello world")
for _ = range [3]int{} {
println("Yay")
}
}

On a side note, I'd like to see an actual use for a program that does this.

Newcomers to Go needs to see Go for what it is. For me it's a tool that helps me with a lot of things, including becoming somewhat a better programmer, at least it forces me to appreciate the pretty little details that makes me proud of what I do, like a carpenter would appreciate a beautifully crafted piece of wood.

And I don't think you're an idiot. :)

Best regards

On Sat, Dec 17, 2011 at 12:19 AM, Brett <bsla...@gmail.com> wrote:
Hey all,

I've been trying to learn and use Go more. I wanted to share with you the difficulty I found as a beginner with the specific error "declared and not used". I thought the best way to illustrate how this felt to me is by showing you a beginner's session from the Go playground.


Round 1: Run hello world

package main
import "fmt"
func main() {
  fmt.Printf("Hello World\n")
}

> Hello World


Round 2: Cool; now let me try a nice literal

package main
import "fmt"
func main() {
  fmt.Printf("Hello World\n") 
  foo := []int{1,2,3}
}
 
prog.go:5: foo declared and not used

Round 3: Doh; well, at least it compiled otherwise; I'll just use it in a loop, that should fix it

package main
import "fmt"
func main() {
  fmt.Printf("Hello World\n") 
  foo := []int{1,2,3}
  for i := range foo {
    fmt.Printf("Yay\n")
  }
}

prog.go:6: i declared and not used

Round 4: Doh again; searched around a bit and found mention of the blank identifier (http://golang.org/doc/effective_go.html#maps); I'll try that

package main
import "fmt"
func main() {
  fmt.Printf("Hello World\n") 
  foo := []int{1,2,3}
  for _ := range foo {
    fmt.Printf("Yay\n")
  }
}

prog.go:6: no new variables on left side of :=

Round 5: Doh thricely; I guess I need the other kind of equals sign or something

package main
import "fmt"
func main() {
  fmt.Printf("Hello World\n") 
  foo := []int{1,2,3}
  for _ = range foo {
    fmt.Printf("Yay\n")
  }
}

> Hello world
Yay
Yay
Yay

At last!


My first impression was that I was getting a lot of errors for such simple beginner code. This turned me off a lot. As I have continued writing more complex programs, I still find myself grappling with "declared and not used" frequently. I'm not sure why this is the case; maybe I'm a breadth-first coder and build scaffolding too early?

Either way, I'm concerned this kind of thing is hurting the adoption of Go. I expect people on this list to say "you're just an idiot". But seriously, I think this little thing may be important. So hypothetically, what minimal changes to Go (language, tools) could improve this experience for beginners?

Thanks,

-Brett


PS: If you agree with me but are embarrassed, feel free to reply privately and I'll keep your identity a secret!


Reply all
Reply to author
Forward
0 new messages