Hacker News new | ask | show | jobs
by drvd 1910 days ago
Sorry to hurt your feelings, but it is not. The _compiler_ cannot know whether the code in a package might be used (e.g. because the package is just used to register some stuff; a common example being image file formats). Only the _linker_ can strip unused stuff. This has nothing to do with bad language design, most languages work that way.
1 comments

> Sorry to hurt your feelings, but it is not. The _compiler_ cannot know whether the code in a package might be used

I'm sorry to hurt your feelings, but compiler definitely can know whether some external module is used in the file it's compiling now.

See my other comment: https://news.ycombinator.com/item?id=26553401

I'm not sure I follow. How can the compiler know that the import is side-effect free, transitively?

Without opening more files and parsing them, how does it know that none of the transitive dependency tree has a `func init(){}` ?

Go forces you to add an underscore if you mean "I'm importing this for its side-effects, and am not using it directly".

If it doesn’t know whether it is used or not, how can it fail a compile?
It doesn't know what the author's intention is:

"import for the side-effects", or "oops, that was a mistake".

It's not that it fails, it's that it rejects.

This just adds to my impression that Go is a very poorly designed language.

So. The compiler knows that the package is not used. How can you tell the compiler that the package is imported for side-effects?

Oh, you have to explicitly tell it to the compiler by, you know, actually using the import, right. By doing something stupid like

  import (
    _ "github.com/lib/pq"
    _ "image/png"
    ...
  )
Oh. Look. Problem solved. You mark a package as "I imported this specifically for its side effects". So the compiler can go ahead and include it.

Why does it need to include any other unused module?

Programming is the practice of telling the computer your intentions as code.

Why are you upset that Go forces you to be explicit about your intentions, when it's ambiguous?

E.g. take C++ single-argument constructors. It's the reason we have guidelines like this: https://rules.sonarsource.com/cpp/RSPEC-1709

Go is opinionated on formatting and being explicit about unused imports. It's forcing you to do the right thing.

C++ and Python let cruft accumulate, in headers and imports, with extra tooling external to the compiler (iwyu) to detect when you made a mistake.

There are valid criticism of Go, and I have many, but this ain't one.

> Why does it need to include any other unused module?

Because without at the very least parse the entire dependency tree of the module (which could be huge) it cannot know if it's unused.

Hell, it probably NEVER is unused, because many modules will have "var ErrFoo = errors.New(...)". If it calls C code in these global variables or "func init()" then there isn't even in theory a way that the compiler can deduce that it's unused.

This is a solution to a real problem, where other languages take forever to build, and create bloated binaries.

> Why does it need to include any other unused module?

If you import it then it's not unused, and it's extremely common that that's a mistake. That's why.

Have you ever coded C++, and done a refactor? How many times do you just leave "#include <sys/types.h>" because you don't know exactly why you imported it?

Have you coded Python? Do you know that the previous author is not importing a given package for its side-effects?

I’m not familiar with go, but why on Earth can an import have side-effects? That’s ridiculous..

I was never a fan of Go, but this just takes the cake..

Many languages do.

A Python import will execute anything it imports (most of what's "executed" is "def" and "class"), but if there's code at the top level, it'll run.

C++ will run constructors for global variables before main().

Even C has side-effects from linking in!

    void __attribute__ ((constructor)) init() {}
So I don't mean side-effects at compile time (e.g. it's not like C macros), but importing / linking something even if you don't use it is very common that it has side effects.

Why would you do this? Commonly to "register a handler", to not have to both "import foo" and call "foo.init()"