6 ms·
Go always had hidden magic: - Lowercase symbols are private to the package they are declared at. - A function called "init" will get executed implicitly on st
by unscaled 2y ago
Go always had hidden magic:
- Lowercase symbols are private to the package they are declared at.
- A function called "init" will get executed implicitly on startup.
- You can have multiple functions called "init" in the same package or even in the same file.
- Files ending with "_unix.go", "_linux.go", "_windows.go" etc. will only be compiled when compiling for the specified platform. The exact list of platform is very hard to find in documentation.
- There are a handful of magical built-in function that have lowercase names.
- Some built-ins were generic long before generics were introduced to the language.
- The copy function is defined as "copy(dst, src []Type) int" (i.e. both src and dst have to be slices of the same type), but "As a special case, it also will copy bytes from a string to a slice of bytes".
There are many cases of magical behavior in classic, pre-Generic Go. Sure, if you read the documentation you can learn about these thing and you wouldn't be surprised (although good luck figuring out the order of calling init() or finding out what happened when Go introduces a new compilation target platform that happens to have the same name as the ending of one of your source files). The thing is, if you read the documentation about iterators and see that your iterating over the results of a function that returns a another function (rather than a slice, string, map or channel), you also wouldn't be surprised.
And unlike the old magic, the new magic is always transparent. You can always tell what an iterator function by looking at its source code. But you can't exactly tell what suffixes trigger platform-specific compilation without looking at the Go compiler source code, and knowing where to look.
- foobiekr 2y ago"Lowercase symbols are private to the package they are declared at" This isn't magic, it's just a clever convention.
- kortex 2y agoA sufficiently clever convention is indistinguishable from magic.
- onefiveone 2y agoexcept there's no smoke and mirrors for this character saving trick
- lifthrasiir 2y agoIt is a part of the language rules that you can't ever change if you don't want it. It is magic in that sense.
- mariusor 2y agoI always thought that lack of "magic" in a programming language means that when (as a human) you read through source code you are able to reach the end of the program. Opposite to that, in a language that has "magic" you reach a point where you don't know where execution will go next without the help of the compiler (or a heavy duty IDE that translates for you).
- lifthrasiir 2y agoThat's very subjective I guess, because it would also depend on your familiarity with the subject matter. I can for example easily read and understand a recursive descent parser in any language because I have implemented it multiple times and can catch a common pattern. Unless the language in question corrupts that pattern (highly unlikely unless it's an esolang :-), that definition of "magic" should be largely independent from the language itself.
- mariusor 2y agoIt's not about understanding the language, it's about how an element in the code can mean different things. Think how in Ruby you can get monkey patched behaviour that overwrites a method name for some type, or even the init() function in Go, that someone mentioned in the sibling comments that gets executed at module load, so when you encounter state that should be a zero value, it's actually not. If as a developer reading the code, there's no way to know if the compiler injects some behaviour in or around the thing that you're looking at, that's magic.
- yencabulator 2y agoYou also can't change the if statement, is that now magic too?
- kstenerud 2y agoIt's clever, right up until you come up against the fact that many languages don't have uppercase/lowercase (e.g. Japanese) - and now you have to add an extra hack to work around your original hack. Any time you add a clever hack that re-uses something you don't control directly (Unicode, file names, existing data formats, implicit behaviors of a system - or even explicit since you don't control who will change it later, etc), you're making a mistake that will come back to bite you eventually. In fact, I dare to say: Any time you think you're being clever, you're not. Most of the design mistakes of go were made under the assumption that all complexity can be reduced. There are certain kinds of complexity that can only be moved around, not reduced (e.g. init, os-specific compilation, packaging and such).
- aatd86 2y agoI wonder if users of other alphabets really use their alphabet to code in roman based languages. I mean, even the keywords are not transcribed, right? I guess they could probably prepend a v or V to their variable names? And especially if the code is to be shared with an international community? Wondering.
- mardifoufs 2y agoI've never seen that happen. English is my third language and the only time I've seen people talk about programming in other languages was either when referring to very old esoteric prog languages, or in English speaking forums ironically enough. It happens and I've seen code written in french for example but it's considered an anti pattern almost everywhere. I guess sometimes it makes sense for constants or context dependent variable names but again, still very rare.
- pjmlp 2y agoI was once brought into a PowerBuilder project, during the discovery phase due to my French skills more than anything else, and naturally was cheaper than getting an external translator. Everything except API calls was in French. I also have seen enough code during my lifetime with comments, and occasionally code as well, in Portuguese, Spanish, Italian, German.
- papichulo2023 2y agoIt is not clever, especially for serialisation
- 38 2y agonot at all - you ever tried to export or unexport an identifier module wide? its a huge fucking pain in the ass - versus a one line change with other languages
- eru 2y agoThe attitude of 'generics for me, but no generics for thee' that the language designers had before they were introduced in the wider language is a particular pet peeve of mine. For comparison, C++ is one of my least favourite languages, but at least they try to put the user of the language on an even footing with the designers when that's possible.
- tptacek 2y agoI will never understand why anybody gave a shit about this "not for thee" thing. I get being irritated that the language didn't have generics! I didn't care, but the complaint made sense. But the language having a small, capped number of useful generics seems to me, as a normie, as a good thing. It was always weird that people personalized this.
- unscaled 2y agoI think this grievance mostly comes from the core language team being reluctant to introduce generics early on[1]. The core team was never entirely hostile to generics (although some vocal parts of the Go community were), but they were quite dismissive of their usefulness. I think the arguments about "generics for me but not for thee" came to demonstrate the hypocrisy, when debates got heated and the aforementioned vocal parts of the Go community rose up with their usual Luddite themes of "we don't even need generics or any language feature cooked up by academic eggheads after the 1970s". If we'll be fully honest, every language has irregularities that could be qualified as magic (and I've never claimed otherwise). For instance, Pascal has magical varargs for the builtin Write family of functions and most modern languages with generics (such as Pascal, C and Java pre-1.5) have generic arrays. Modern Java arrays are also reified and unboxed, while other generics are boxed and the type is erased in runtime. Go shouldn't be criticized for having exceptions for some language internals and other types of necessary "magic". My personal beef is with the claim that Go is unique by not having magic, while most other language have "hidden magic". I believe that's utterly and categorically false. My other issue is magic that is non-transparent and not well-documented (or hard to wrap your mind around), like the platform-specific source files in Go and multiple init() functions in the same package. I'm not looking forward to the time Go introduces a target platform that happens to be a common word and mysteriously breaks lots of programs... [1] To be exact, they didn't claim that generics are bad, but that they require expensive trade-offs and I remember one of them (perhaps Russ Cox?) saying that generics are mostly useful for custom collections and this is not a big-enough use case. This rubbed many of us as a little bit arrogant, since the "trade-offs" that were quoted only applied to Java and C++, two of the most atypical implementations of generics. None of the quoted issues applied even to ML and CLU which introduced generics decades before Java and C++ (back in 1970s). https://research.swtch.com/generic https://research.swtch.com/generic
- emmanueloga_ 2y agoI would love a program analyzer able to generate a list of magic behaviors: $ penn-and-teller ~/projects/go - init() is implicitly called on program start [link to explanation] - xyz_unix.go() will only be used when compiling to unix [link] - file.go:20:20 calls a bult-in function [link]
- neonsunset 2y agoThat's called disassembler and CPU architecture manual for a specific generation (because the way it is executed is magic too) :)
- allset_ 2y ago> - Files ending with "_unix.go", "_linux.go", "_windows.go" etc. will only be compiled when compiling for the specified platform. The exact list of platform is very hard to find in documentation. Sure, you won't find it in the Go 101 guides, but it is well documented in the "go build" CLI reference in the official Go docs site. See https://pkg.go.dev/cmd/go#hdr-Build_constraints https://pkg.go.dev/cmd/go#hdr-Build_constraints and https://pkg.go.dev/internal/platform https://pkg.go.dev/internal/platform.
- mook 2y agoAlso, frustratingly, ”_unix.go" doesn't work IIRC even though "unix" is a built-in build tag, because the ending thing only works with platform names. You need to manually do "//go:build +unix" in the file.
- ithkuil 2y agoGP made the point a few lines below. What if Go adds support for a new OS called "FoOS" and suddenly your files named "my_foos.go" stop being compiled anywhere else? They should have forbidden using _ in file names except for an allow-list of suffixes
- xyzzy_plugh 2y agoThis has in fact come up before, and you may be surprised to learn the approach they take is most reasonable.
- ithkuil 2y agoI'm the first to argue that Go is "most reasonable" all around. Even things which are technically wrong and _could_ have been done differently are still reasonable. First and foremost because sometimes the alternatives would have meant breaking backwards compatibility (or at the very least forcing people to hassle with migrating code with "editions", which are probably better left for more impacting problems than "what if a new OS comes around") That said, I think it's important to call out design mistakes when one sees them (as long as one engages constructively with them instead of just throwing a random "Go is magic/sucks/etc" without putting things into context, like how do other practical languages fare on all the metrics combined)
- ithkuil 2y agoFor me init is magic not because it's implicitly called. It's magic because unlike any other function it can appear in multiple files in the same package. And the order of execution depends on the names of the source files!