6 ms·
Adding an element to a nil slice works, but adding an element to a nil map panics. time.Time uses its own epoch incompatible with anything else. defers are func
by usrnm 2y ago
Adding an element to a nil slice works, but adding an element to a nil map panics. time.Time uses its own epoch incompatible with anything else. defers are function-scoped instead of block-scoped. The list goes on, these are just the first ones that came to my mind. And they are not some magical tradeoffs, they are just poor choices. I like go, but no, it is not well-designed
- mirekrusin 2y agoAlso missing null safety in modern language is weird.
- physicsguy 2y agoAnd enums.
- fullstackchris 2y agopackage main import "fmt" // Define an enumeration for status type Status int const ( Pending Status = iota InProgress Completed Failed ) func (s Status) String() string { return [...]string{"Pending", "InProgress", "Completed", "Failed"}[s] } func main() { var s Status = InProgress fmt.Println(s) // Output: InProgress }
- Svip 2y agoOK, but I can set s to 1000, and it still compiles.
- alkonaut 2y agoNext day I have this (added one entry). I forgot to update the string list elsewhere however. const ( Pending Status = iota InProgress Completed Cancelled Failed ) func (s Status) String() string { return [...]string{"Pending", "InProgress", "Completed", "Failed"}[s] } func main() { var s Status = Cancelled fmt.Println(s) // Output: ?? If the compiler - not some linter - protests that the list of names is different from the number of items in the enum, then I think this is at least a half-decent design of an enum type. Not a great one (because the author still had to repeat the names), but at least something that isn't a fundamentally broken design of an enum type. But if the compiler is silent, and the output of the Println(Cancelled) is "Failed" then I'm not angry, I'm disappointed. Edit: https://go.dev/play/p/MMPMh7_U81- https://go.dev/play/p/MMPMh7_U81-
- physicsguy 2y agoI see this suggested all the time as though it’s supposed to be a replacement. It isn’t sufficient, it’s a poor emulation of what enums can be used for and doesn’t offer the same protections, since Status can be set to any integer value without casting or any knowledge that it’s broken. In your suggested method it doesn’t even catch that case and provide an error if the value isn’t in the range.
- powerhugs 2y agoIt seems like none of the other comments here use or are even aware of `go generate`. Go has excellent code generation features [1]. I think parent should be using `stringer` [2] instead. 1: https://go.dev/blog/generate https://go.dev/blog/generate 2: https://pkg.go.dev/golang.org/x/tools/cmd/stringer https://pkg.go.dev/golang.org/x/tools/cmd/stringer
- physicsguy 2y agoI'm well aware of Stringer but I don't again think it's a good replacement of having enums built in!
- powerhugs 2y ago> I don't again think it's a good replacement of having enums built in! I didn't say anything along those lines, in fact I was commenting generally about this issue that you guys and the other commenters mentioned. I was just suggesting a solution to the the problem stated.
- fullstackchris 2y ago"We don't want a solution! We want to complain about what we are used to and dont have!"
- pjmlp 2y agoAlso known as design hack, workaround for what other languages support natively since 1970's. Only one step better than Assembly or Fortran.
- theoryofx 2y agoYou can point out flaws so it's not well designed? By this logic nothing is. And pointing out missing features in a programming language is just about the weakest criticism possible. Piling on lots of features is easy and fun. That's why almost all language designers do it. Most popular languages destroy themselves with features. Rust is in the process of gaining every single feature anyone can imagine. Following C++ right off the complexity cliff. Go is one of the very few languages to show incredible restraint in adding features because its designers understood the combinatorial complexity problem, among other things. Not having unnecessary features is one of the best features of Go.
- powerhugs 2y agoI very much agree. The fewer ways a programmer can become creative, the easier it is to fully understand their code. In a business environment, this is a obvious win.
- pjmlp 2y agoEspecially when programmers are seen as cogs in the business machine.
- physicsguy 2y agoThe issue with Enums is that the "unnecessary" feature means that people have to encode the behaviour with things that aren't suitable. E.g. creating a new type that's a thin wrapper over string or integer means it can be set as some non-valid value, even without some sort of explicit cast that says "I know I'm doing something that might fail". I don't see that that is an improvement over any other language. It's not simpler because, as people have shown by the examples trying to prove that you don't need it, they don't have all the (necessary) behaviour that enums do to prevent this sort of problem.
- theoryofx 2y agoThere are some useful features that Go really should add, and enums might be one of them, but lacking a useful feature doesn't mean its not well designed. The results are in for Go. It's already one of the most successful programming languages in history any way you measure it. Of course Go should continue to improve and add features where the value outweighs the increased complexity. That's how it eventually got generic functions and other features.
- roncesvalles 2y agoThe appeal of Go is that it has just the bare minimum feature set to be useful for modern backend engineering. It's a language that you can completely fit within your head within a few months of using it, as opposed to certain languages like C++ (or say C# to a lesser but increasing extent) that most will never know completely even after decades of working with it. It's basically the RISC of programming languages. And if I had to guess, it doesn't have enums so that it can remain flexible when serializing/deserializing enum-like types over the wire. Imagine you can't parse an incoming payload containing an enum field because your service is one version older than the one that extended the enum type (or the enum type is defined in a package dep... you get the idea). Enums are actually a terrible idea now that I think about it.
- theThree 2y agoThe appeal of Go is goroutine.
- za3faran 2y agoJava has virtual threads with better and safer ergonomics.
- anal_reactor 2y ago> The appeal of Go is that it has just the bare minimum feature set to be useful for modern backend engineering. It's a language that you can completely fit within your head within a few months of To me, golang symbolizes the shift of philosophy of Google as a company. It changed from "it's a smart nerd company for smart nerd people" to "golang will allow us to hire cheaper devs because golang will prevent them from making mistakes". I mean, this makes sense from business perspective, I won't deny this fact, but it's the programming equivalent of Ferrari making a SUV: tremendously profitable, but sad to see. BTW > golang doesn't support overloading because overloading is bad. Having said that, it's 'go', not 'golang', like the verb 'go', which already has a thousand meanings depending on the context I find that hilarious
- AnimalMuppet 2y ago
- xarope 2y agoI got caught with maps initially, and had to question why everything else was just "var x string", which also gives it a value, but maps needed a "var x = make(make[string]string)", otherwise on first assignment it panics. There's a good explanation somewhere, ah here it is: https://go.dev/blog/maps https://go.dev/blog/maps But you get used to it, and move on, especially with the sort of TDD workflow that go test encourages
- usrnm 2y agoI know why it works the way it works, it doesn't make it a good design, which is the point of this discussion
- deleted 2y ago[deleted]
- q3k 2y ago> time.Time uses its own epoch incompatible with anything else. Could you please elaborate?
- theoryofx 2y agotime.Time uses its own epoch internally but has methods like .Unix() which convert to Unix epoch time. Never seen this be a problem.
- usrnm 2y agoIt means that zero value time.Time when converted to unix time gives you a negative number corresponding to a date two thousand years ago. With the way go insists on using zero values for expressing optionality this is a rather common mistake. Interacting with anything outside the go ecosystem is done in terms of unix time and this makes it very error-prone. And I've seen this trip people off in real life. And yes, you can argue that this is programmer's fault, but this is exactly what makes it a bad design: it makes people's lives more difficult for no real purpose, just because somebody at Google wanted to feel smart that day.
- indulona 2y agoi think he means that internally, time objects simply use unix nano and the location dictates the offset. since it is internal thing, not sure why that is relevant.
- roncesvalles 2y agoI don't think that's weird. You can only append to a slice using the `append` built-in function. `append` may initialize and return a new slice at any call. It would be weird for it to not do so when passed a nil slice.
- usrnm 2y agoAdding elements to a map allocates memory and moves stuff all the time under the hood, it's no different from append. If panicking on nil is weird for append, it's just as weird for maps
- jitl 2y agoappend returns a new pointer in case the slice moved, map assignment does not return a new pointer. There’s no way for the operator to change the reference you hold from a nil to a pointer to the newly allocated value. When memory is allocated under the hood on assignment to a non-nil map, your reference to the object remains the same, but some internal pointers change. You can write a func Set[k, v](map map[k]v, k k, v v) map[k]v yourself that returns a map reference if you want this style of “maybe return a new pointer”.
- shakiXBT 2y agoIf language specific quirks lead to a language being "not well-designed", how many languages do you think are actually well-designed (if any)?
- oconnor663 2y ago> defers are function-scoped instead of block-scoped. I think this is a basic tradeoff with defer and not a problem per se. Are users more likely to need to clean up resources every time through a loop, or more likely to acquire resources that outlive the loop? And which is more confusing if you expected the other? I think it's a tough call. (I understand why a systems programming language would insist on block scoping to avoid allocating.)
- cle 2y agoWhy are they poor choices? What tradeoffs are they making? I can't really evaluate/judge them without understanding that first.