Should we be responding to "Go: a nice language with an annoying personality"

1,876 views
Skip to first unread message

pfitzsimons

unread,
Jan 18, 2013, 3:24:13 AM1/18/13
to golan...@googlegroups.com
I would agree they have a fair point, when you are starting with the language it would be easier to learn if you did not have to keep commenting import statements out just to get code to be fully checked..

post here http://corte.si/posts/code/go/go-rant.html
and responses on hacker news:http://news.ycombinator.com/item?id=5076461

Rémy Oudompheng

unread,
Jan 18, 2013, 4:05:51 AM1/18/13
to pfitzsimons, golan...@googlegroups.com
It only looks like the annoyance of applying a technique to a language
where it doesn't fit. There are many simple ways of solving the
problem:
* make your import used somewhere else, so you don't need to comment it
* don't use special packages for your debugging, write your debugging
tools in a separate file and call them
* use the "if false { ... }" trick

Rémy.

Dan Kortschak

unread,
Jan 18, 2013, 4:18:51 AM1/18/13
to Rémy Oudompheng, pfitzsimons, golan...@googlegroups.com
In addition to the techniques Rémy suggests, GoSublime makes adding and removing imports often as little as 6 key strokes away without any in file navigation.

pfitzsimons

unread,
Jan 18, 2013, 4:37:03 AM1/18/13
to golan...@googlegroups.com, pfitzsimons
is there a good reference that new devs can be pointed at that shows this kind of approach?

pfitzsimons

unread,
Jan 18, 2013, 4:38:03 AM1/18/13
to golan...@googlegroups.com, Rémy Oudompheng, pfitzsimons
well I'm using vim (but thanks!), I don't think we can answer questions like this with non-language approaches...

Dan Kortschak

unread,
Jan 18, 2013, 4:53:27 AM1/18/13
to pfitzsimons, golan...@googlegroups.com, Rémy Oudompheng, pfitzsimons
:Import and :Drop do the same thing in vim with the Go vim extensions. The techniques 'if false' and '_ = x' are two I commonly use when compartmentalisation is not possiblle.
--
 
 

Anssi Porttikivi

unread,
Jan 18, 2013, 6:20:30 AM1/18/13
to golan...@googlegroups.com, pfitzsimons, Rémy Oudompheng
Maybe it is delibarate user experience thing? Maybe the preferred way to insert "temporary" code is to iterate it towards robust code (error control or something else) and leave it there? Maybe Rob et al. did not want to encourage people to throw in temporary code, just to be removed and re-inserted and accidentally forgotten there, randomly ad infinitum?

Dave Cheney

unread,
Jan 18, 2013, 6:51:52 AM1/18/13
to Anssi Porttikivi, golan...@googlegroups.com, pfitzsimons, Rémy Oudompheng
It is a deliberate choice,
http://golang.org/doc/faq#unused_variables_and_imports.
> --
>
>

Nate Finch

unread,
Jan 18, 2013, 7:55:59 AM1/18/13
to golan...@googlegroups.com
I don't think it's a fair point at all. If you're adding/removing fmt too much, maybe you need more logging :)

Not only does this hardly ever happen to me, but I really love the compiler telling me about unused things. Every time I think "thanks, compiler!" and go fix it.

Maybe he's just too used to Python with its anything-goes style.  Coding in a new language takes a new style, which can be hard to figure out in your first week of coding, especially when you're in a time crunch.

I don't think this is a terribly damning article, so I wouldn't worry about it.

Aram Hăvărneanu

unread,
Jan 18, 2013, 7:59:52 AM1/18/13
to Nate Finch, golan...@googlegroups.com
If that's all they have to criticise about Go, then Go has succeeded.

--
Aram Hăvărneanu

Martin Angers

unread,
Jan 18, 2013, 8:23:16 AM1/18/13
to golan...@googlegroups.com
That's a critic he makes 5 days into the language, if I recall the article correctly. You shouldn't be allowed to judge a language before you've tried it for a few months, and its peculiarities have become standard to you. Every relevant language has some. Only then can you judge on valid grounds. That's a big meh to me, the fact that it makes the front page is more a reflection of the popularity of Go than anything to worry about (not long ago it was the same with node when it started gaining momentum, negative articles were pushed to the front page too). It hasn't been a big deal to me, some 6 months into the language.

andrey mirtchovski

unread,
Jan 18, 2013, 11:14:35 AM1/18/13
to golang-nuts
These are the sort of beginner questions/issues that will be best
answered by an authoritative book rather than a collection of FAQs and
Wiki articles. Something that can hold their attention longer.

Looking at the discussion on reddit's /r/programming (the author
posted there) it appears that they miss the point that it's only
supposed to hurt the first few times if you keep going at it.

wkharold

unread,
Jan 18, 2013, 11:46:39 AM1/18/13
to golan...@googlegroups.com
From Rob Pike's "Language Design in the Service of Software Engineering" talk (http://talks.golang.org/2012/splash.article):

"The first step to making Go scale, dependency-wise, is that the language defines that unused dependencies are a compile-time error (not a warning, an error). If the source file imports a package it does not use, the program will not compile. This guarantees by construction that the dependency tree for any Go program is precise, that it has no extraneous edges. That, in turn, guarantees that no extra code will be compiled when building the program, which minimizes compilation time"

Having dealt with dependency hell in C, C++, and Java this is all the reason I need to put up with the occasional toe-stubbing over unused imports.

Kevin Gillette

unread,
Jan 18, 2013, 12:28:29 PM1/18/13
to golan...@googlegroups.com, pfitzsimons
Tooling would also work: wrapping gc in a dev tool that first strips unused imports would work.

Russ Cox

unread,
Jan 18, 2013, 5:49:39 PM1/18/13
to Kevin Gillette, golang-nuts, pfitzsimons
What I took from the blog post is that we have not done a good job of explaining how to silence the errors using the blank identifier. The next version of Effective Go will contain a section something like the text below.

Russ

Blank identifier

Go defines a special identifier _, called the blank identifier. The blank identifier can be used in a declaration to avoid declaring a name, and it can be used in an assignment to discard a value. This definition makes it useful in a variety of contexts.

Multiple assignment

If an assignment requires multiple values on the left side, but one of the values will not be used by the program, using the blank identifier in the assignment avoids the need to create a dummy variable. We saw one example of this in the discussion of for loops above.

sum := 0
for _, value := range array {
    sum += value
}

Another common use is when calling a function that returns a value and an error, but only the error is important.

if _, err := os.Stat(path); os.IsNotExist(err) {
	fmt.Printf("%s does not exist\n", path)
}

A final use that is more common than it should be is to discard the error from a function that is not expected to fail. This is usually a mistake: when the function does fail, the code will continue on and probably panic dereferencing a nil pointer.

// Always check errors: this program crashes if path does not exist.
fi, _ := os.Stat(path)
fmt.Printf("%s is %d bytes\n", path, fi.Size())

Unused imports and variables

Go defines that it is an error to import a package without using it, or to declare a variable without using its value. Unused imports bloat a program and lengthen compiles unnecessarily; a variable that is initialized but not used is at least a wasted computation and perhaps indicative of a larger bug. Of course, both of these situations also arise in programs that are under active development, as you test and refine your code.

For example, in this program, there are two unused imports (fmt and io) and an unused variable (greeting).

package main

import (
    "fmt"
    "io"
)

func main() {
    greeting := "hello, world"
}

Top-level blank declarations referring to the packages will silence the unused import errors. By convention, these declarations should come immediately after the imports, as a reminder to clean things up later. Similarly, assigning greeting to a blank identifier will silence the unused variable error.

package main

import (
    "fmt"
    "io"
)

var _ = fmt.Printf
var _ io.Reader

func main() {
    greeting := "hello, world"
    _ = greeting
}

Import for side effect

An unused import like fmt or io in the last section should eventually be used or removed: blank assignments identify code as a work in progress. But sometimes it is useful to import a package only for its side effects, without any explicit use. For example, during its init function, the net/http/pprof package registers HTTP handlers that provide useful debugging information. It has an exported API too, but most clients need only the handler registration. In this situation, it is conventional to rename the package to the blank identifier:

import _ "net/http/pprof"

This form of import makes clear that the package is being imported for its side effects, because there is no other possible use of the package: in this file, it doesn't have a name.

Interface checks

As we saw in the discussion of interfaces above, Go does not require a type to declare explicitly that it implements an interface. It implements the interface by simply implementing the required methods. This makes Go programs more lightweight and flexible, and it can avoid unnecessary dependencies between packages. Most interface conversions are static, visible to the compiler, and therefore checked at compile time. For example, passing an *os.File to a function expecting an io.Reader will not compile unless *os.File implements the io.Reader interface.

However, some types that are used only to satisfy dynamic interface checks. For example, the encoding/json package defines a Marshaler interface. If the JSON encoder encounters a type implementing that interface, the encoder will let the type convert itself to JSON instead of using the standard conversion. This check is done only at runtime, with code like:

m, ok := val.(json.Marshaler)

If a type—for example, json.RawMessage—intends to customize its JSON representation, it should implement json.Marshaler, but there are no static conversions that would cause the compiler to verify this automatically. A declaration can be used to add such a check:

var _ json.Marshaler = (*MyMessage)(nil)

As part of type-checking this static assignment of a *RawMessage to a Marshaler, the Go compiler will require that *RawMessage implements Marshaler. Using the blank identifier here indicates that the declaration exists only for the type checking, not to create a variable. Conventionally, such declarations are used only when there are no static conversions already present in the code.

Rémy Oudompheng

unread,
Jan 18, 2013, 5:53:04 PM1/18/13
to Russ Cox, Kevin Gillette, golang-nuts, pfitzsimons
On 2013/1/18 Russ Cox <r...@golang.org> wrote:
> What I took from the blog post is that we have not done a good job of
> explaining how to silence the errors using the blank identifier. The next
> version of Effective Go will contain a section something like the text
> below.
>
> Russ

A few days ago I noticed the part of the spec about blank-named
methods: it is legal to say:

type T int
func (T) _() {}
func (T) _(int) {}
func (T) _() int {return 2}
func (T) _(x int) int { return x }

in the same program.
Is it there for consistency or did someone find an actual use of that?

Rémy.

Jan Mercl

unread,
Jan 18, 2013, 5:57:00 PM1/18/13
to Rémy Oudompheng, Russ Cox, Kevin Gillette, golang-nuts, pfitzsimons
On Fri, Jan 18, 2013 at 11:53 PM, Rémy Oudompheng
<remyoud...@gmail.com> wrote:
> A few days ago I noticed the part of the spec about blank-named
> methods: it is legal to say:
>
> type T int
> func (T) _() {}
> func (T) _(int) {}
> func (T) _() int {return 2}
> func (T) _(x int) int { return x }
>
> in the same program.
> Is it there for consistency or did someone find an actual use of that?

IMO it is allowed for the sake of reducing the number of explicitly
forbidden exceptions to the general "does not introduce a binding"
rule.

-j

Aiden

unread,
Jan 18, 2013, 5:58:49 PM1/18/13
to golan...@googlegroups.com
I agree with you. Having been using Go when I can for a few months, I see how you can feel that way after 5 days ... but as with most things that are good, they are a PITA at first then you realise how much you need them.
Hell, at this point most of the things I thought were annoying are just second nature now and keep my code clean. Win.

Dan Kortschak

unread,
Jan 18, 2013, 8:47:35 PM1/18/13
to Melvin T., golan...@googlegroups.com, Rémy Oudompheng, pfitzsimons
ctrl-. ctrl-p <enough sloppy matching letters from the package, e.g. fm for fmt> (confirm from menu) <enter>

Note that ctrl-. ctrl-p is three strokes since the ctrl chords.

On 19/01/2013, at 10:37 AM, "Melvin T." <mmte...@gmail.com> wrote:

Interesting. Which keystrokes do you use to do this in GoSublime?


On Friday, January 18, 2013 1:18:51 AM UTC-8, kortschak wrote:
In addition to the techniques Rémy suggests, GoSublime makes adding and removing imports often as little as 6 key strokes away without any in file navigation.

--
 
 

Hraban Luyat

unread,
Jan 19, 2013, 11:36:36 AM1/19/13
to golan...@googlegroups.com, pfitzsimons, Rémy Oudompheng
What... this is great. Thanks.

John Nagle

unread,
Jan 19, 2013, 1:11:27 PM1/19/13
to golan...@googlegroups.com
On 1/18/2013 5:37 AM, itmi...@gmail.com
wrote:
> "That looks great. Just one thing: get rid of the duck."
>
> Those are the findings of someone willing to give Go a spin.
>
> It boiled down to me in a positive review, with a pinch of salt in it. All
> it needs is a little missing ingredient. I suggesting adding a counter
> article summing up debug techniques in Go. Don't let it over boil. Enjoy.

It's at most a minor annoyance for new programmers. It can't cause
incorrect programs and crashes. It can impact language acceptance,
though. There's a whole generation of programmers who grew up with
Javascript and Perl, and get upset when a compiler tells them they're
doing it wrong. The HTML crowd doesn't even insist that tags be
closed properly. They're likely to see Go as painfully restrictive.

John Nagle



Jay Weisskopf

unread,
Jan 19, 2013, 5:40:42 PM1/19/13
to golan...@googlegroups.com
From http://golang.org/doc/faq#unused_variables_and_imports:

> The presence of an unused variable may indicate a bug, while unused imports just slow down compilation. Accumulate enough unused imports in your code tree and things can get very slow.

The same points could be made for unused functions or dead code blocks. Why are unused functions and dead code blocks allowed while unused imports and variables are not? It seems inconsistent.

> There are two reasons for having no warnings. First, if it's worth complaining about, it's worth fixing in the code.

Not every problem is worth fixing immediately.

> It's easy to address the situation, though. Use the blank identifier to let unused things persist while you're developing.

"unused foo" compilation errors become _silent_ "unused foo" coding or cleanliness errors. That seems like a dubious trade-off. Additionally, it seems like the programmer is not being trusted to cleanup unused imports and variables, yet is being trusted to cleanup any added blank identifier workarounds.

If the programmer can be trusted:
* Unused imports and variables will be cleaned up and removed later.
* Blank identifier workarounds will be cleaned up and removed later.

If the programmer cannot be trusted:
* Unused imports and variables will not be cleaned up. The solution is to treat them as a compilation errors.
* Blank identifier workarounds will not be cleaned up. Oh well! (See the inconsistency?)

Dan Kortschak

unread,
Jan 19, 2013, 6:08:06 PM1/19/13
to Jay Weisskopf, golan...@googlegroups.com
Also, I think it is not possible to guarantee at compile time that a method or function is not used, because of the possibility of a reflect.(*Value).Method*().Call*() on a method that is not statically called. The reflect-based call may furter implicate functions.

George Hartzell

unread,
Jan 19, 2013, 4:42:17 PM1/19/13
to John Nagle, golan...@googlegroups.com
John Nagle writes:
> [...] There's a whole generation of programmers who grew up with
> Javascript and Perl, and get upset when a compiler tells them they're
> doing it wrong. [...]

There's a whole community of Perl programmers who hate it when the
compiler DOES NOT tell them when they're doing it wrong and work in
ways that make strict-ness the default/standard behaviour.

To *us*, these aspects of Go seem pleasantly safe.

g.

Kevin Gillette

unread,
Jan 19, 2013, 6:59:46 PM1/19/13
to golan...@googlegroups.com
It's a matter of consistency: you can't expect importing "strings" just to use strings.Index should result in a few dozen errors along the lines of "unused function strings.Trim" and so on; making unused functions in package main create an error would require main to be special cased in a way that arguably has negligible benefit (since functions don't end up in the compiled binary if they're not anywhere in the potential call graph).  Also, it's not necessarily "wrong" to keep a set of utility functions in package main for use in development and debugging. Dead code could certainly be argued differently, though dead code, except in extremely trivial cases, is much harder to check than unused variables or imports -- even if the chief gophers agreed that dead code should in compilation errors, it would probably be a profoundly low priority item in the to-do list.

Blank identifier "workarounds" may also be hard to identify, since you'd have to tell if a given function call can possibly produce side effects anywhere in its execution path, which is really a hard form of dead-code detection. If such "workaround" cases were detected, and produced errors, it would likely be seen as a violation of the compiler's promise to the programmer: the compiler has certain rules, which are easy to adhere to, and _provides_ the blank identifier as an explicit workaround...

Neither the compiler, nor the Go community, seek to slap the programmer when they're not adhering to traditional draconian custom; the compiler, and the community, seek to prevent some of the sneakier potential bugs from going by unnoticed. However, when the blank identifier is used, the programmer is explicitly approving a certain behavior, and software should never betray its legitimate users.

Raul Mera

unread,
Jan 20, 2013, 5:08:00 AM1/20/13
to golan...@googlegroups.com
If you would deactivate the unused imports/variables, you would deactivate to all of them.
With the current technique you silence the compiler errors for the imports/variables you need to keep, and still get the compiler to catch your mistakes with other variables. This has saved me a few times.

Øyvind Teig

unread,
Jan 20, 2013, 6:20:38 AM1/20/13
to golan...@googlegroups.com, Kevin Gillette, pfitzsimons
kl. 23:49:39 UTC+1 fredag 18. januar 2013 skrev Russ Cox følgende:
What I took from the blog post is that we have not done a good job of explaining how to silence the errors using the blank identifier. The next version of Effective Go will contain a section something like the text below.
 
Russ, do you mean that the below is for the "next version" of http://golang.org/doc/effective_go.html?

/aclassifier 
Message has been deleted

Øyvind Teig

unread,
Jan 20, 2013, 2:46:48 PM1/20/13
to golan...@googlegroups.com, Kevin Gillette, pfitzsimons
(2.ed, spelling) Any language designer will try to make the language as suitable as possible. It should be easy to write (incrementally?), read and explain. It should map between cognitive and runnable matters.

But more importantly, the final result should be safe to use. If it runs in a breaking system, a fire detection system or is a text editor, the user must trust it. In the ISO 61508 world of safety critical systems they talk about risk, which is the product of probability and consequence. And back to the text edtor, you take a risk that a letter is not lost, and hope that a lost letter would have a small consequence. Not to talk about a programmer's editor!

Even if 61508 talks a lot about the programming languages and what they should have and not have, it's seen as what is safe for the user. How much the programmer feels he's trusted or not is not the question.

A statement like "The airplane crashed because the programming language trusted the programmers" would be a huge misunderstandning. If we, the programmers, have such a view of ourselves and what we're here for, I would not send my daughter with that airplane.

There may be matters with any language that would not suit this thinking (also for Go - even Ada needed the Ravenscar profile (see my blog note 035)), but I refuse the idea that on these matters it's an a offense not being trusted.

Disallowing pointer operations probably means that the language designers didn't trust that I always would do it correctly. Having channels between processes could mean that they didn't trust that I handled semaphores that correctly. Verifying part of a program or protocol could mean that I didn't trust myself to have coded (or designed) it correctly.

The best thing is if we designers could say "Trust me, it's safe" to our customers. It may be easier to say this if we some times may have felt not trusted by our language designers.

The above is a quote from a new blog I wrote, at http://www.teigfam.net/oyvind/home/technology/058-trust-me-its-safe/ (I'll update anything there)

/aclassifier

Russ Cox

unread,
Jan 22, 2013, 1:53:00 PM1/22/13
to Rémy Oudompheng, Kevin Gillette, golang-nuts, pfitzsimons
On Fri, Jan 18, 2013 at 5:53 PM, Rémy Oudompheng <remyoud...@gmail.com> wrote:
A few days ago I noticed the part of the spec about blank-named
methods: it is legal to say:

type T int
func (T) _() {}
func (T) _(int) {}
func (T) _() int {return 2}
func (T) _(x int) int { return x }

in the same program.
Is it there for consistency or did someone find an actual use of that?

The definition of the blank identifier is that it suppresses the usual declaration. The original intended use was _, err := foo(), but many other uses have turned up since then. They weren't planned, they just follow from the definition.

You might plausibly want to use the func(T) _() {} to assert that methods can be defined on T, although that's usually obvious. I have used func _() { ... } in tests to define code that I want type-checked but have no intention of running.

Russ

Russ Cox

unread,
Jan 22, 2013, 1:53:32 PM1/22/13
to Øyvind Teig, golang-nuts, Kevin Gillette, pfitzsimons
On Sun, Jan 20, 2013 at 6:20 AM, Øyvind Teig <oyvin...@teigfam.net> wrote:
Russ, do you mean that the below is for the "next version" of http://golang.org/doc/effective_go.html?

An edited version of that text will probably be in the Go 1.1 version of Effective Go. It might or might not appear on golang.org before that.

Russ

Aram Hăvărneanu

unread,
Jan 22, 2013, 2:03:18 PM1/22/13
to Jay Weisskopf, golan...@googlegroups.com
> The same points could be made for unused functions or dead code blocks. Why
> are unused functions and dead code blocks allowed while unused imports and
> variables are not? It seems inconsistent.

Unused functions in a package can be used by another package which
imports it, so disallowing unused functions makes no sense. By the
way, the linker does cull unused functions.

Detecting dead code in general is equivalent to the halting problem,
so disallowing dead code in general is not inconsistent, but
impossible. For particular cases it is possible to detect dead code,
but then because you can't do in in general *that* would be
inconsistent.

> Not every problem is worth fixing immediately.

The fact that there's not a single C program in existence that
compiles without warnings shows that any problem not worth fixing
immediately will never be fixed at all.

--
Aram Hăvărneanu

John Asmuth

unread,
Jan 22, 2013, 2:04:51 PM1/22/13
to golan...@googlegroups.com, Rémy Oudompheng, Kevin Gillette, pfitzsimons
Similarly, I will sometimes do "var _ InterfaceType = ConcreteType{}" to assert that things of ConcreteType will work wherever you need an InterfaceType.

Jan Mercl

unread,
Jan 22, 2013, 2:10:12 PM1/22/13
to Aram Hăvărneanu, Jay Weisskopf, golang-nuts
On Tue, Jan 22, 2013 at 8:03 PM, Aram Hăvărneanu <ara...@mgk.ro> wrote:
> Detecting dead code in general is equivalent to the halting problem,

Apologies for not being really serious: I'm tempted to declare that
interpreters as well as JIT compilers "solved" the halting problem
long ago ;-)

-j

John Asmuth

unread,
Jan 22, 2013, 2:26:30 PM1/22/13
to golan...@googlegroups.com, Aram Hăvărneanu, Jay Weisskopf
Approximations are always possible!

Jay Weisskopf

unread,
Jan 22, 2013, 3:00:36 PM1/22/13
to Aram Hăvărneanu, golan...@googlegroups.com
On Tue, Jan 22, 2013 at 1:03 PM, Aram Hăvărneanu <ara...@mgk.ro> wrote:
> Unused functions in a package can be used by another package which
> imports it, so disallowing unused functions makes no sense.

I should have been more specific. I meant unused _unexported_
functions. If a function is unexported and not used anywhere in the
package, it's sketchy for the same reason an unused variable is
sketchy.

> Detecting dead code in general is equivalent to the halting problem,
> so disallowing dead code in general is not inconsistent, but
> impossible

Many languages and static analysis tools will warn about conditions
that simplify down to "if false" at compile-time. Not every piece of
dead code conceivable needs to be detected, but there is some
low-hanging fruit.

> The fact that there's not a single C program in existence that
> compiles without warnings shows that any problem not worth fixing
> immediately will never be fixed at all.

Haha, I guess you haven't been hanging around the right projects or
programmers then. I worked at an avionics company for six years. -Wall
and -Werror were standard fare. You couldn't certify otherwise. Coming
from this background, I am glad that Go is strict by default.

That said, I think the criticality of unused <anything> is
context-sensitive. It would be "wrong" to have ingredients and
utensils sitting out on the counter if you're not cooking a meal, but
it's okay when you are. It would be "wrong" for building supplies and
tools to be sitting around the property of a finished home, but it's
perfectly reasonable to have them strewn about during construction. If
the carpenter has to drive back to his workshop each time he wants to
switch his active tool or get a new board, it'd add overhead and be
annoying. I think this was the point the ranting blogger was trying to
make.

Dan Kortschak

unread,
Jan 22, 2013, 3:28:02 PM1/22/13
to Jay Weisskopf, Aram Hăvărneanu, golan...@googlegroups.com
Static analysis won't get you where you want with certainty when there is runtime reflection:

http://play.golang.org/p/RvFVKpbQHp

You could argue that any method that belongs to any type that has at least one value declared would disprove that a called function within that method method, but that prevents a set of truly unused functions from being marked. This may be good enough for you.

Jay Weisskopf

unread,
Jan 22, 2013, 3:41:43 PM1/22/13
to Dan Kortschak, Aram Hăvărneanu, golan...@googlegroups.com
> http://play.golang.org/p/RvFVKpbQHp

Cool example. Bar.Foo is an exported method of an exported type
though. Anything it touches couldn't be considered unused.

If I change Foo to foo, a panic occurs. Is there a way to make this
reflection way work with an unexported method? If not, then it seems
like you could still reliably detect if a type's unexported method is
used or not.

Jan Mercl

unread,
Jan 22, 2013, 3:42:35 PM1/22/13
to Jay Weisskopf, Aram Hăvărneanu, golang-nuts
On Tue, Jan 22, 2013 at 9:00 PM, Jay Weisskopf <jays...@gmail.com> wrote:
> On Tue, Jan 22, 2013 at 1:03 PM, Aram Hăvărneanu <ara...@mgk.ro> wrote:
>> Unused functions in a package can be used by another package which
>> imports it, so disallowing unused functions makes no sense.
>
> I should have been more specific. I meant unused _unexported_
> functions. If a function is unexported and not used anywhere in the
> package, it's sketchy for the same reason an unused variable is
> sketchy.

That's IMO not correct. A scope of a function is compile-time static
(no preprocessing). A variable being unused is a final property of it.
But the package scope is not static. Some build system/tag, script,
code generator, ... can actually use the function which looks like
unused only at this time, only at this builder run, only at this
architecture/platform, ...

-j

Øyvind Teig

unread,
Jan 22, 2013, 4:01:25 PM1/22/13
to golan...@googlegroups.com, Aram Hăvărneanu
You are comparing physical tools with abstract tools, and driving back
to his workshop with (perhaps) pushing an abstract button. Isn't this
like all the abstract OO examples with physical fruit (apple, orange)?
For metaphors (which some times is all we have) it's ok. But perhaps
it boils down to being too simple. I want my daughter to go with that plane.
Not knowing about the -Wall -Werror for it. (And if so, at least knowing that 
the other, redundant systems in the plane did not lift the carpet with those)

But this thread certainly discusses interesting matters. Perhaps it boils
down to what/how to build in (for the sake of testing), and what/how to test the real
thing (without depending on context sensitive matters). 

In vivo vs. in vitro.

Five years ago I experienced a compiler generate different outputs, with one that 
failed, by adding an empty line in the source. The (debug) __LINE__ outputs were of
course changed after the empty line, and one of them was generated as an ASM
with a buried (immediate) constant, while for the OK system that number (one more
or less) did not fit into the immediate, but was allocated in a constant table. All
the jumps were changed etc, so the object file was hugely different. The
compiler generated code that failed during some internal DMA. I have a deep fear
of changing anything during testing. (But I do it every day...)

Jay Weisskopf

unread,
Jan 22, 2013, 5:12:04 PM1/22/13
to Jan Mercl, Aram Hăvărneanu, golang-nuts
On Tue, Jan 22, 2013 at 2:42 PM, Jan Mercl <0xj...@gmail.com> wrote:
> But the package scope is not static. Some build system/tag, script,
> code generator, ... can actually use the function which looks like
> unused only at this time, only at this builder run, only at this
> architecture/platform, ...

If the scope you're using at compile-time has unused unexported
functions, it could indicate that the function is defined in a
sub-optimal location / scope. For example, if func foo() lives in
bar.go, but is only called from somewhere in bar_windows.go, it'd be
better to move foo() out of bar.go and into bar_windows.go. I'm not
saying it should necessarily be treated as fatal at compile time, but
I think detection of such things would still be fairly useful.

> You are comparing physical tools with abstract tools

The principle is the same: the workflow is being disrupted to satisfy
an artificial constraint of cleanliness in a context which is
inappropriate. The code can still technically compile and execute with
the presence of an unused variable. The compiler is just designed to
be stubborn about it and treat it as fatal. In the middle of a hacking
session, this can be annoying. You have to resort to busy work like
wrapping things with if false { }, defining func useMyVar(v
interface{}), or replacing assignments with blank identifiers - and
then likely backing out those changes in a few minutes again anyway.

Use of a blank identifier seems to be the idiomatic method for
temporary squelching, but I think it creates an unfortunate false
dilemma: you can either be stopped and nagged, or you cannot be
stopped nor nagged. Warnings are useful in that they don't stop you,
but still nag at you.

> I want my daughter to go with that plane.

Somewhat unrelated tangent: I doubt Go will ever be used in a system
where safety is critical. Garbage collection and some of its intended
randomness (scheduling, map iteration, etc.) would basically
disqualify it.

Dan Kortschak

unread,
Jan 22, 2013, 5:16:17 PM1/22/13
to Jay Weisskopf, golan...@googlegroups.com
There is always a way. It will be unsafe.

If some package decides to use an unsafe reflect-like Call function
based on the code at [1], it could call unexported methods. All that's
needed is the pointer to the func which can be retrieved using unsafe.

[1]http://golang.org/src/pkg/runtime/asm_amd64.s#L202

Øyvind Teig

unread,
Jan 23, 2013, 5:13:32 AM1/23/13
to golan...@googlegroups.com, Jay Weisskopf
References are not necessary a problem. See [1], "Add MOBILE reference types, where only one process may hold the reference at a time." Don't know if this is relevant to the reflection you are referring to.

Øyvind Teig

unread,
Jan 23, 2013, 5:24:10 AM1/23/13
to golan...@googlegroups.com, Jan Mercl, Aram Hăvărneanu
In that line, perhaps also because of the "bad nondeterminsim" introduced by the scheduling queues at each channel end. Some CSP solutions wouldn't do it like that. I think we discussed this in https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/qa2p0PRY0WE

minux

unread,
Jan 23, 2013, 7:08:49 AM1/23/13
to Jay Weisskopf, Jan Mercl, Aram Hăvărneanu, golang-nuts
On Wed, Jan 23, 2013 at 6:12 AM, Jay Weisskopf <jays...@gmail.com> wrote:
On Tue, Jan 22, 2013 at 2:42 PM, Jan Mercl <0xj...@gmail.com> wrote:
> But the package scope is not static. Some build system/tag, script,
> code generator, ... can actually use the function which looks like
> unused only at this time, only at this builder run, only at this
> architecture/platform, ...

If the scope you're using at compile-time has unused unexported
functions, it could indicate that the function is defined in a
sub-optimal location / scope. For example, if func foo() lives in
bar.go, but is only called from somewhere in bar_windows.go, it'd be
better to move foo() out of bar.go and into bar_windows.go. I'm not
saying it should necessarily be treated as fatal at compile time, but
I think detection of such things would still be fairly useful.
maybe then the programmer write a bar_linux.go and makes use of foo().
these kind of things should not be enforced by compilers. 

Somewhat unrelated tangent: I doubt Go will ever be used in a system
where safety is critical. Garbage collection and some of its intended
randomness (scheduling, map iteration, etc.) would basically
disqualify it.
Why? Even Java is used in safety critical programs.
The spec just say the iteration order is not specified, but that doesn't exclude
an implementation that does make guarantee about the order.
Similar things apply to GC and goroutine scheduling, nothing prevent you from
writing a compliant implementation that provide deterministic GC and scheduling.
And these things have been done before (albeit not for Go).

Brendan Tracey

unread,
Feb 27, 2013, 5:08:40 PM2/27/13
to golan...@googlegroups.com, Jay Weisskopf, Jan Mercl, Aram Hăvărneanu
I would just like to pipe in that I think Russ's suggestion for editing effective go is a good one, and also that it's probably a good idea to say something about it in the tour of go. I remember when I first started to write in go, even simple programs were tough at first because there were a bunch of compile errors that were unexpected, mainly due to unused variables / imports

minux

unread,
Feb 28, 2013, 6:02:08 AM2/28/13
to Brendan Tracey, golan...@googlegroups.com, Jay Weisskopf, Jan Mercl, Aram Hăvărneanu
On Thu, Feb 28, 2013 at 6:08 AM, Brendan Tracey <tracey....@gmail.com> wrote:
I would just like to pipe in that I think Russ's suggestion for editing effective go is a good one, and also that it's probably a good idea to say something about it in the tour of go. I remember when I first started to write in go, even simple programs were tough at first because there were a bunch of compile errors that were unexpected, mainly due to unused variables / imports 
FYI, Russ' changes to effective go has already been committed and should appear in Go 1.1
and meanwhile, you can view it on golang.org/doc/effective_go.html#blank

Personally, i don't want to put that into the Go Tour.
Reply all
Reply to author
Forward
0 new messages