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.
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.
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]
"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'."
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.
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.
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.
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.
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.
> 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.
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.
> 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.
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.
> 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.
> 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"?
> 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.
> 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.
> 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"?
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.
> 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.
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.
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.
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.
> 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.
$ 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?
$ 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;
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.
> 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)
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.
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.
[+] [-] denysvitali|2 years ago|reply
Use `go run .` instead - it's shorter and it works with multiple files
[+] [-] aeturnum|2 years ago|reply
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
[+] [-] SPBS|2 years ago|reply
> 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
[+] [-] lenkite|2 years ago|reply
[+] [-] 1vuio0pswjnm7|2 years ago|reply
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
[+] [-] breadchris|2 years ago|reply
[+] [-] lloeki|2 years ago|reply
(long time I didn't use Go, back then at least, using `.` instead of `./...` could cause subtle issues)
[+] [-] 38|2 years ago|reply
[+] [-] pizzafeelsright|2 years ago|reply
[+] [-] pizzafeelsright|2 years ago|reply
[+] [-] mqus|2 years ago|reply
[+] [-] bjackman|2 years ago|reply
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
- 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 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
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
[+] [-] lopkeny12ko|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.
> 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
[+] [-] badrequest|2 years ago|reply
It's not random code, it's code you've expressly used.
[+] [-] breadchris|2 years ago|reply
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
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
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"?
[+] [-] ilovejava|2 years ago|reply
[+] [-] 999900000999|2 years ago|reply
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
(It's only a subset of the JavaScript ecosystem, but you can import a lot of npms nowadays.)
[+] [-] GorsyGentle|2 years ago|reply
[+] [-] randomdata|2 years ago|reply
Although, with slight modification, you can `go run -C ~/that/project/over/there .`
[+] [-] unknown|2 years ago|reply
[deleted]
[+] [-] 38|2 years ago|reply
[+] [-] pusewicz|2 years ago|reply
[+] [-] newzisforsukas|2 years ago|reply
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
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
[+] [-] badrequest|2 years ago|reply
[+] [-] cxr|2 years ago|reply
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
[+] [-] parkcedar|2 years ago|reply
[+] [-] madeofpalk|2 years ago|reply
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
Not really.
It's pretty handy.[+] [-] alpaca128|2 years ago|reply
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
[+] [-] BillyTheKing|2 years ago|reply
import pkg from './helper.js'; const { sleep } = pkg;
'What is CommonJS?'
[+] [-] breadchris|2 years ago|reply
[+] [-] iansinnott|2 years ago|reply
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
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
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
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
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