With this simple program:
package main
import (
"fmt"
)
func main() {
branch := "master"
fmt.Println(branch)
}
Breaking on the branch := master line gives the following output:
$ dlv debug .
Type 'help' for list of commands.
(dlv) break a.go:8
Breakpoint 1 set at 0x49c1af for main.main() ./a.go:8
(dlv) c
> main.main() ./a.go:8 (hits goroutine(1):1 total:1) (PC: 0x49c1af)
3: import (
4: "fmt"
5: )
6:
7: func main() {
=> 8: branch := "master"
9: fmt.Println(branch)
10: }
(dlv) locals
branch = "H锟紻$8锟紽H锟紻$(H锟斤拷锟絓x00\x00\x00H锟絓f$锟紾_\x03\x00H锟紻$\bH锟紻$8H锟絃$(H莵锟絓x00\x00\x00\x00\x00\x00\x00H锟絓f$H锟紻$\b\x03...+842350542940 more"
(dlv) step
> main.main() ./a.go:9 (PC: 0x49c1c4)
4: "fmt"
5: )
6:
7: func main() {
8: branch := "master"
=> 9: fmt.Println(branch)
10: }
(dlv) locals
branch = "master"
Similar output occurs with other variable types; for example branch := 42 is branch = 842350543032 on locals.
I understand that this happens because the branch variable isn't assigned a value yet, but printing seemingly random information doesn't strike me as a good user experience, and something that might confuse people a lot. I think it would be better to print something like <uninitialized> or the type's zero value.
$ dlv version
Delve Debugger
Version: 1.0.0
Build: $Id: c98a142125d0b17bb11ec0513bde346229b5f533 $
$ go version
go version go1.10 linux/amd64
$ uname -a
Linux arch.arp242.net 4.15.2-2-ARCH #1 SMP PREEMPT Thu Feb 8 18:54:52 UTC 2018 x86_64 GNU/Linux
This is essentially by design. We only know the declaration line of a variable and show the value of variables at or after the declaration line.
We could change it to only show the value of a variable after the declaration line which would fix this problem, but it would also mean that you couldn't see the value of for loop indices while on the for loop condition.
To really fix this problem the compiler would have to track the scope of each variable, which will make the compiler slower and the executable bigger. Go 1.11 is going to do this in some cases, so maybe it wouldn't be too bad, but IMHO the tradeoff isn't worth it.
I also find the current behavior confusing (see GO-6280).
In my opinion, if the for loop indices need special handling, they should get them. All other variables should only be shown when they are in scope.
This buggy behavior may also lead to unintended information disclosure. Luckily, in the original (dlv) locals command, the branch variable just pointed somewhere into the code segment, which can be identified by the many occurrences of the letter H. It could also have pointed to a secret key or half-way computed password hash or anything else.
Taking a screenshot during a debugging session should not provide the slightest chance of publishing this data unintendedly.

Messages like this one from GoLand are really confusing and make me think I did something wrong. I didn't. Delve should not throw these unnecessary and arbitrary errors at me.
I didn't try it, but I think this Delve behavior also has the chance of freezing the IDE because of an OutOfMemoryError. Just imagine if the application being debugged has allocated a huge memory block and the uninitialized variable happens to point to this memory block. Then the IDE will try to display it as a string.
For the behavior in GoLand, you can see this issue: https://youtrack.jetbrains.com/issue/GO-6989 Please comment there as to what you'd expect the behavior to be there.
Regarding the message itself, I think that Delve should keep it and the clients should be able to filter out such cases, if that's the desired behavior. I can see a case where I'm using the Delve CLI and when evaluating mkline.Line.Text, like in the screenshot, I would prefer to get that message than nothing as that would lead me to think that there's a different bug in Delve.
I didn't try it, but I think this Delve behavior also has the chance of freezing the IDE because of an OutOfMemoryError.
If you can think of such a case, please let us know on the issue tracker. I don't have a good idea to reproduce this scenario at the moment.
Also, cc-ing @nd on this one.
@dlsniper My point is that GoLand is only the presentation layer. The actual cause for the wrong display is in Delve itself. Debuggers in other languages, such as Java or Python or C or Delphi or pretty much any other language only show variables that are actually in scope, and that makes sense.
As @nd mentioned in the issue comment on GoLand's tracker, that variable seems to be a "watch" variable, not a normal one. So it's normal that the IDE will display that it can't read it if it hasn't reached the point where it's initialized (like in Java, don't know about Delphi).
@dlsniper I'm fine with the IDE showing "this variable is not in scope" or "cannot resolve symbol %s". I'm not fine with the IDE showing "this variable's value can only be partially read from memory", as that misses the point and is misleading.
I wonder which edge case I stumbled upon in the following screenshot:

I also managed to reproduce this using dlv.exe 569ccbd514fc47c8b4c521b142556867ec5e6917 directly.
The variable I pointed to is in frame 1, and in that frame it is initialized _after_ the current function call. Since that _current_ function call is not finished yet, there is no reason to show the uninitialized variable already.
@rillig it is bug in GoLand, please watch https://youtrack.jetbrains.com/issue/GO-8492.
@nd No, it isn't. As I wrote, I reproduced the very same error message using Delve alone. Therefore it's a bug in Delve.
Having a watch expression on an uninitialized variable makes Delve crash the process that is being debugged. This could not happen if Delve simply said "the variable mkline is not in scope yet", as it correctly does when I'm stepping one line above.

Note that while the screenshot comes from GoLand, it's pretty obvious how this UI translates to the Delve commands, and how Delve then calls a function on garbage memory. Luckily, there was no rm -rf around in the process image. The application that I'm debugging _does_ delete files sometimes, though, therefore there is a certain risk that having a simple watch expression erases my hard disk just because I'm debugging using Delve.
Oops: having a watch expression on an uninitialized variable makes Delve crash the process that is being debugged. This could not happen if Delve simply said "the variable mkline is not in scope yet", as it correctly does when I'm stepping one line above.
Can you replicate that from the command line? If not, that's a problem from GoLand's side.
Note that while the screenshot comes from GoLand, it's pretty obvious how this UI translates to the Delve commands, and how Delve then calls a function on garbage memory.
How can I reproduce this?
The application that I'm debugging does delete files sometimes, though, therefore there is a certain risk that having a simple watch expression erases my hard disk just because I'm debugging using Delve.
That would be the risk for doing the described operation regardless of how the debugger is named.
Please provide a way for us, GoLand team, to replicate your issue and we'll report back here if it's an issue from Delve/Go or from GoLand. Thank you.
See https://youtrack.jetbrains.com/issue/GO-8530 for the proof-of-concept code. In general, evaluating uninitialized variables is undefined behavior, and calling functions on these uninitialized variables is plain dangerous.
Yay, many thanks. It's great to be able to debug Go programs again without fearing undefined behavior.