top | item 39460409

Go run

199 points| breadchris | 2 years ago |breadchris.com | reply

168 comments

order
[+] denysvitali|2 years ago|reply
`go run main.go` breaks if your `main` module is divided into multiple files.

Use `go run .` instead - it's shorter and it works with multiple files

[+] aeturnum|2 years ago|reply
This is a good tip! It also captures what has been frustrating about golang for me. The language feels a bit stuck between simple default cases and allowing complexity.

I feel like there are two relatively distinct populations of go developer: those who love how easy it is to start (true!) and those who are frustrated by the compromises the language has made to allow for more complex cases (required!). There's also a hidden third population of people who no longer sing the praises of golang as a simple, straightforward language but accept its compromises and write productive code with it. Those people, I think, write fewer viral blog posts.

[+] IggleSniggle|2 years ago|reply
Yup. This was the main thing that bit me when I was first getting into Go. File names are kind of like classes, and directories are kind of like modules. The encapsulation sits at a slightly different layer than you might expect.
[+] SPBS|2 years ago|reply
Fun fact: `go run .` was retrofitted on after `go run main.go` because go run was initially designed to only accept explicit filenames as an argument [1]. I can't imagine how people used to use `go run` without the ability to specify whole packages (globs don't work well because it includes test files as well).

> Potential design based on discussion with proposal review:

> go run [go flags] [single-package-or-*.go-list] [subprocess flags]

before that it was just

> go run [go flags] [*.go-list] [subprocess flags]

[1] https://github.com/golang/go/issues/22726

[+] 1vuio0pswjnm7|2 years ago|reply
This is not a tip. It comes straight from

   go help run
"usage: go run [build flags] [-exec xprog] package [arguments...]

Run compiles and runs the named main Go package. Typically the package is specified as a list of .go source files from a single directory, but it may also be an import path, file system path, or pattern matching a single known package, as in 'go run .' or 'go run my/cmd'."

Nothing is said about go run main.go.

[+] devjam|2 years ago|reply
And if your main.go is in a sub-directory, e.g. cmd/pathto/cli/main.go:

    $ go run ./cmd/pathto/cli
[+] breadchris|2 years ago|reply
great point, this is the one thing that I wish was more intuitive. You don't have to do this if main.go is the only file in the main package and all other code is referenced by a package.
[+] lloeki|2 years ago|reply
Isn't it supposed to be `go run ./...`?

(long time I didn't use Go, back then at least, using `.` instead of `./...` could cause subtle issues)

[+] 38|2 years ago|reply
you can also do `go run hello.go world.go`, but yeah `go run .` is probably better
[+] mqus|2 years ago|reply
I don't think it's simple. Just `go run` would be far more simple. Right now I first have to figure out if its `go run .` or `go run cmd/main.go` or some other thing.
[+] bjackman|2 years ago|reply
It's not really a Go thing but a build system thing. It's useful to have your build system know what is an "executable target" and how to run it.

Bazel does this for _all_ languages. I'm sure most other modern generic build systems do too.

AFAIK "go run" is trivial and for single-file scripts it's fine. But for more complex cases (like the NPM equivalent thing) I actually think it's a bit of a shame that it's even needed. I don't really know why we have per-ecosystem build systems (Maven, Go, cargo, whatever the hell you're supposed to do in Python these days, the nebula of web front-end tooling, etc etc).

Admittedly I do not really know the ins and outs of any of these systems in detail. I'm sure there are some good reasons why they exist under the hood.

[+] IggleSniggle|2 years ago|reply
I'm not sure there really is a good technical reason they exist. It's cultural. It basically goes like this:

- the inventor of new language 'coolang' has a way that they make their project

- it's kinda messy, so they clean it up into a tidy script with a few clear and straightforward commands and/or flags, and give you "cool build," "cool install" for making sure all the necessary dependencies are present, etc

- a community builds around coolang organically

- everybody is so used to running "cool build" that that's just how it's done. New features get added around these conventions

It's cultural, that's all it is. But like all small tight knit communities, it's important to understand the culture of the community in order to engage with it on its own terms. Its just humans being humans.

[+] reactordev|2 years ago|reply
The build system should come with it. Even if it requires me to follow conventions, it’s magnitudes better than rolling my own. I can add to it if I need to.

The worst offenders are C and C++ projects. Make? CMake? You’re on your own. During development, it’s so good to be able to just runtime run source like in go and bun.

[+] randomdata|2 years ago|reply
> I'm sure there are some good reasons why they exist under the hood.

User expectation's, mainly. In fact, Google didn't even use the go tool internally, which I expect hasn't changed, using Google's build system à la Bazel instead. It was created only for the wider audience.

[+] breadchris|2 years ago|reply
bazel is pretty cool, I have seen it work at Uber for the go monorepo at impressive scale (and of course it works for google). When I need to scale up the build process this will be the tool i reach for, but for starting out it is another technology that someone would have to learn.
[+] lopkeny12ko|2 years ago|reply
> Yeah, and then what happens if you want to use modern syntax like esmodule, or maybe you want to use types with typescript? You are going to have to use npm.

I don't understand what the problem is here? Every installation of Node comes bundled with npm. If it doesn't, that is a package maintenance problem.

> Fun fact: One of the understated features go run is that it will automatically download any dependencies the code references; how cool is that!

This feels like a massive antipattern. Why is this lauded as a "feature"? Why do I want my build system to automatically reach out to the Internet and download random code, without an explicit request to do so like "npm install"?

This is even more antipattern-ish when you consider that Go dependencies are literally just repos on Github (or possibly on some random git server), instead of a centralized and moderated registry like npmjs.org.

> amazing, for js we not only have npm, yarn, pnpm, and bower (am I missing any?) but we also have completely new runtimes bun and deno.

So it's now considered bad to have multiple implementations of an open standard, compared to the exclusively-Google-developed Go runtime? This sounds akin to arguing in favor of a monopoly over a competitive market with consumer choice.

[+] asp_hornet|2 years ago|reply
Everyone who clones a node project will call npm install before the call npm run. Having a seperate install command doesnt make it more secure, it just makes 1 more thing for newbies to learn and another thing to go wrong when you pull master and someone added a package and you called run without installing again.
[+] badrequest|2 years ago|reply
> This feels like a massive antipattern. Why is this lauded as a "feature"? Why do I want my build system to automatically reach out to the Internet and download random code, without an explicit request to do so like "npm install"?

It's not random code, it's code you've expressly used.

[+] breadchris|2 years ago|reply
> I don't understand what the problem is here. Every installation of Node comes bundled with npm. If it doesn't, that is a package maintenance problem.

Node and npm are two commands, and when you go to find packages, you will see people telling you to use pnpm, yarn, or npm. I would expect one tool to do this for me, especially for the most popular language in the world.

> This feels like a massive antipattern. Why is this lauded as a "feature"? Why do I want my build system to automatically reach out to the Internet and download random code without an explicit request, like "npm install"?

https://chat.openai.com/share/8bd82c15-c939-4e82-aad8-086995...

> This is even more antipattern-ish when you consider that Go dependencies are just repoed on GitHub (or possibly on some random git server) instead of a centralized and moderated registry like npmjs.org.

I find this to lend itself to a more decentralized future. I see notable projects owning their code and distributing it positively. You still need the source code for something to run at the end of the day. If you are worried about the code continuing to be there, that is the purpose of a proxy cache, which makes it very easy: https://proxy.golang.org/. Also, the code is distributed on github. So, if github working is a concern, we probably have much bigger problems.

> So it's now considered harmful to have multiple implementations of an open standard, compared to the exclusively Google-developed Go runtime? This sounds akin to arguing for a monopoly over a competitive market with consumer choice.

A hammer looks like a hammer because that is the most effective way to hit a nail. Since I am "building" code, I want my tools to feel as reliable as a hammer. I will not argue that Go is the best language ever invented; I see it as the most accessible language to make things happen fast and reliably until a better one emerges. When that happens, AI-generated refactoring tools will be so good, and Go code is so quickly parseable that I will let it loose in my Go code bases to refactor them into that language.

[+] duped|2 years ago|reply
> So it's now considered bad to have multiple implementations of an open standard

Seeing how many CPU cycles have been wasted on autoconf generating code and testing for various ancient/obsolete C compilers and configurations has taught me that yes, it's not a good thing to have multiple slightly incompatible implementations.

[+] kunley|2 years ago|reply
> Every installation of Node comes bundled with npm. If it doesn't, that is a package maintenance problem.

Not really.

Ubuntu's node comes without npm, and to install the latter it wants to get about a hundred of dependencies. Mind you, this is still one of the most popular distros. Would you call their approach "a problem"?

[+] 999900000999|2 years ago|reply
Golang is such a elegant language.

But comparing it to JavaScript isn't fair. JavaScript has paid my bills for years, but it's held together by collective hope.

The only thing missing is a decent mobile framework. I'm using Fyne, but it just looks dated. At least for my current app it's functional though.

[+] skybrian|2 years ago|reply
For TypeScript, "deno run" seems much the same?

(It's only a subset of the JavaScript ecosystem, but you can import a lot of npms nowadays.)

[+] GorsyGentle|2 years ago|reply
Except I cannot `go run ~/that/project/over/there` as the use of go modules means I have to change directory to be inside the package first. I'm not sure why that is exactly, but it's always been a nit I've found frustrating.
[+] randomdata|2 years ago|reply
Especially when you can `go run that/project/over/there@latest`

Although, with slight modification, you can `go run -C ~/that/project/over/there .`

[+] 38|2 years ago|reply
thats mostly true. you need to at least be at the top level of the module to do go run. any higher and you get a missing go.mod error.
[+] pusewicz|2 years ago|reply
I totally clicked the link thinking I'd read about some benefits of... running. Yes, as in doing sports.
[+] newzisforsukas|2 years ago|reply
> But I can run node main.js? Yeah, and then what happens if you want to use modern syntax like esmodule, or maybe you want to use types with typescript? You are going to have to use npm

No, you do not. You can just use .mjs extensions for esm. You can also run typescript to transpile your code and then run it with node. You can even use loaders, etc.

Saying you are going to have to use the included package manager in node is probably the weakest argument for using go over node.

Can you run some language superset over go magically without some transpilation? No, you cannot.

You cannot build a argument comparing js to ts vs go, it doesn't follow.

[+] shpx|2 years ago|reply
Clicking is my favorite part of JavaScript. I just move my mouse onto some blue text and click and the software that I want to use is installed/updated and runs, usually in under a second.

In the 50+ year history of software development I haven't heard of any other software stack has been able to realize this is important. go run is close but it's still 10 times slower, maybe even 100 times slower, depending on if you want to count the git clone and how good you are at typing.

[+] ivanjermakov|2 years ago|reply
What blue text has to do with JavaScript? You can create such straughtforward tool for any language, and it's running shell commands under the hood in all cases.
[+] badrequest|2 years ago|reply
None of this is part of Javascript, Goland does most of what you describe.
[+] cxr|2 years ago|reply
> One of the understated features go run is that it will automatically download any dependencies the code references; how cool is that!

All this plus talk about non-standard JS runtimes like Node, but no mention that this is how browsers have worked almost forever.

[+] JBorrow|2 years ago|reply
This isn't a benefit of go, but rather a drawback of the counter-example of typescript... All tools generally designed to work for creating small utilities ({ba,z,...}sh, python, perl, go, swift, ...) have this feature.
[+] parkcedar|2 years ago|reply
Most of these examples don’t automatically fetch the dependencies. Having come from Python, Go’s tools are notably simple.
[+] madeofpalk|2 years ago|reply
> Yeah, and then what happens if you want to use modern syntax like esmodule [...] You are going to have to use npm.

Why? Node's had built-in support for ES Modules for eons now.

Everything's easy when you stick to default tooling, duh, like `node run.js` or `go run.go`. You'll loose that `go run.go` the moment you need code generation.

[+] floating-io|2 years ago|reply
> You'll loose that `go run.go` the moment you need code generation.

Not really.

  //go:generate ...
It's pretty handy.
[+] alpaca128|2 years ago|reply
> even rust you need a cargo file

And a look at Github shows me Go has a go.mod file. I don't see the point the author wants to make, neither of them affect the build/run command.

[+] pkilgore|2 years ago|reply

    $ cat helper.mjs
    export const sleep = (dur) => new Promise(resolve => setTimeout(resolve, dur))

    $ cat main.mjs
    import { sleep } from './helper.mjs'
    await sleep(1000)
    console.log("Go is great; but weird throwing node under a bus here?")

    $ node main.mjs
    Go is great; but weird throwing node under a bus here?
[+] BillyTheKing|2 years ago|reply
$ cat helper.mjs export const sleep = (dur) => new Promise(resolve => setTimeout(resolve, dur))

  $ cat main.mjs
  import { sleep } from './helper.js'
  await sleep(1000)
  console.log("Go is great; but weird throwing node under a bus here?")

  $ node main.mjs
file://main.mjs:1 import { sleep } from './helper.js' ^^^^^ SyntaxError: Named export 'sleep' not found. The requested module './helper.js' is a CommonJS module, which may not support all module.exports as named exports. CommonJS modules can always be imported via the default export, for example using:

import pkg from './helper.js'; const { sleep } = pkg;

'What is CommonJS?'

[+] breadchris|2 years ago|reply
if I were a beginner developer, I now have to have the tribal knowledge of the difference between .js and .mjs. I don't see anyone widely using .mjs to write their code either.
[+] iansinnott|2 years ago|reply
> what happens if you want to use modern syntax like esmodule, or maybe you want to use types with typescript? You are going to have to use npm.

Shout out out to Bun (and Deno too?) for allowing you to treat typescript as an interpreted language. Great for scripting with all the bells and whistles.

(Go is great, just pointing out that running TS does not actually require NPM anymore)

[+] dwrodri|2 years ago|reply
Tangentially related: I am currently scoping out an idea for how language models could be used to augment decompilers like Ghidra.

At a surface level, this was partially an intellectually interesting project because it is similar to a language translation project, however instead of parallel sentence pairs, I will probably probably be creating a parallel corpus of "decompiled" C code which will have to be aligned to the original source C code that produced the binary/object file.

Then I realized, the only way I could reasonably build this corpus would be by having some sort automated flow for building arbitrary open source C projects...

Perhaps I will attempt this project with a Go corpus instead.

[+] gumby|2 years ago|reply
You can build the equivalent simple c++ program by just calling `make` with no arguments.

Though TBF then you have to type ./a.out, and so then you want to do `make && ./a.out` and then...

[+] todd3834|2 years ago|reply
Sadly I haven’t been able to write any production Go for a few years now after switching companies. However, I got bit by the seemingly innocent _platform.go “feature”. I had a file that organized a bunch of windows for a cross platform GUI app. Well it turns out something like file_windows.go only compiles on windows. Our CI environment was compiling all the code but suddenly all platforms except windows started failing.

Was funny when it was diagnosed but not so funny for the time where I was deeply confused why things broke.

[+] WuxiFingerHold|2 years ago|reply
Go is neat to write tools, no doubt. But I think the author is not up to date with the javascript / typescript ecosystems.

npx, tsx, deno, *.mjs and bun make it convenient to run typescript tools.

Bun has recently added a very interesting feature, bun shell: https://bun.sh/blog/the-bun-shell