(no title)
vlads_ | 5 years ago
As for programming with types, that's partly what Go was trying to avoid: https://news.ycombinator.com/item?id=6821389 . And I agree with Pike on this one. The nice thing about Go for me is that I'm just writing code. Not defining a type hierarchy, not rewriting some things to get them just right, not defining getters, setters, move and copy constructors for every type :). Just telling the computer what to do and in what order. When I'm writing a library I'm defining an API, but that's about it; and you can usually steal whatever the standard library's patterns are there.
I disagree about nil as well; I think Go's zero value approach is useful, and basically impossible without nil (it wasn't necessary in my code, but I may want to instantiate an ApiResponse object without a data structure ready to be passed in).
A little bit of a rambly response from me, but, all in all, I think I'll be one of the stubborn ones which refuses to use generics in his code for a long time.
kelnos|5 years ago
> Sounds like Rob Pike doesn't understand type theory.
I'd be a bit more charitable; Pike is a smart dude, I'm sure he does understand type theory, but has decided he'd prefer to write imperative code. And he's actually good at writing imperative code correctly, so for him, that works. But most people are not very good at writing imperative code correctly, at least not the first time, and not without writing a large volume of tests (usually several times as much test code as program code) to verify that imperative code.
Or perhaps Pike was just assuming the person he was talking to was only talking about types in the OOP sense. If that's the case, I agree with him: taxonomies are boring, and inheritance often leads to leaky abstractions.
But types let you do so much more than that. I much prefer being able to encode behavior and constraints into the types I define over writing a bunch of tests to verify that the constraints I've expressed in code are correct. Why do the work that a compiler can do for you, and do it much better and more reliably than you?
swertyb|5 years ago
How are languages other than Go (like Rust, Swift etc.,) not imperative? They are nearly as much imperative as Go but have FP features like ADTs and pattern matching, but those don't make them "functional". This point might be valid if you are talking about Haskell, MLs and the likes.
> I much prefer being able to encode behavior and constraints > into the types I define over writing a bunch of tests to verify that the constraints > I've expressed in code are correct. Why do the work that a compiler can > do for you, and do it much better and more reliably than you?
IMO, this "types replacing tests" might be true when comparing dynamic vs static typing, but for already static typed languages, extra typing cannot be a substantial gain. Personally, I find type-level programming beyond a certain extent to be counter productive and it doesn't seem to have much impact on correctness (unless we bring in dependent types).
nemothekid|5 years ago
I like your solution to my imaginary problem, but I am going to counter this one. Now I'm salty because nil interface[1] actually bit me once and cost me. Go's zero value approach also exists in Rust, but is type safe. Basically every primitive type, and Option<T> have zero values. Any struct that is made up of those values can also safely have zero values. Then for those that don't, you can implement your own zero values. This is called Default in Rust. Go's zero value approach is perfectly possible, and arguable better without nil. And even then, the number of times I've seen a service crash because someone "forgot" to initialize a nullable type, and passed it to a function that then exploded isn't an issue I should deal with in 2020.
[1] https://medium.com/@glucn/golang-an-interface-holding-a-nil-...
vlads_|5 years ago
As for your proposal, there are some issues with it: not all structures have a sane default for all not optional, nilable parameters. What is the default underlying reader for a bufio.Reader? A reader which returns zero bytes? Certainly that would be more confusing to debug than a simple panic, which is what we have now [2]. There's also the fact that a zero value is just a value with all the bytes zeroed and allocating an object via language means (new) never allocates more than the size of the object and doesn't do computation.
But I guess the main point would be that I simply do not have a problem programming with nil-able types. Failing to initialize in Go means writing var a *T as opposed to a := &T{} or a := NewT(), which seems like an odd mistake to make - or forgetting to initialize a member of a struct in the NewT() function. Fundamentally, I do not want to spend hours of my life dealing with safeguards which are protecting me from a few minutes of debugging.
But hey, that's just me. Go isn't Rust and Rust isn't Go and that's a good thing.
[1]: https://play.golang.org/p/L7iy9YBC55c [2]: https://play.golang.org/p/Vgv73KhegKI
steveklabnik|5 years ago
rswail|5 years ago
It's designed to be simple, to be boilerplate, to be easily reviewable/checkable by coding teams.
Not sure why Go and Rust are always the compared languages. Go is designed to replace Java/RoR/Python in Enterprise-land, not to replace C/C++.
Rust is designed to replace C/C++ in system-land, embedded, kernel, thick app components (browsers are probably the most complex apps running these days on end user systems). The entire focus is zero-cost abstractions.
piva00|5 years ago
Rust can't cover the enterprise use-cases of Go the same way that Go won't ever cover what Rust can do on systems/embedded level but there is enough overlap in some cases to confuse people into trying to compare them directly.
entha_saava|5 years ago
I have seen average programmers who can write less dumbed down code than the most succinct code possible in Go.
I have seen below average programmers who understand how to use generic data structures / programs in C++ / Java / C# etc..
> It's designed to be simple, to be boilerplate, to be easily reviewable/checkable by coding teams.
Boilerplate and easily reviewable are at the odds. Unless Enterprise style java is the bar, it is hard for anyone to say that. Go is too much boilerplate than average programmer's python code, for example. Don't tell me python is dynamic. The average programmer doesn't do metaclass magic.
Being so much boilerplate and verbose `if err != nil` and no generics and no methods/functions for common operations like finding the index of an element in an array. All this leads to for-loop-inside-while-loop-inside-for-loop attrocities where it is harder to decipher what the intention is. Compare to python where you have methods on collections to carry out common manipulations, and list comprehension in python is so cleaner than 4 line imperative go code.
Go seems to miss why python/JS/ruby are so popular. It is because so much is built in that you can communicate __intent__ clearly without getting bogged down in details. Compared to any modern language that's not C and not mediaeval C++, Go is so much more verbose. Even java has enough shortcuts to do these common things.
And don't start telling me this leads to incomprehensible code. Coding standards are there. What's unreadable is 8 level indented imperative attrocity of blue collar language Go.
> Not sure why Go and Rust are always the compared languages.
They both emerged at same time and have some overlapping scope - eg static native compilation, memory safety etc.. but there similarities end. However, there is lack of a a popular, succinct natively compiled language which gets out of the way to write software. Everyone knows expressive languages need not be slow or difficult to deploy. Some people have to write Go in dayjob and the sibling rust, having quality-of-life improvements that anyone expects in a post-2000 language [0], seems to be a closer candidate to comparison (even though rust isn't the optimal language for the things Go is used for, given it is a systems language with static memory management) Others like D and Nim have a fraction of users. Of course there are also some vocal rust fanboys who think crab god is not popular because world is anti intellectual.
vlads_|5 years ago
Secondly, I don't think the fact that Go making the opposite trade-offs in terms of (let's say) programmer effort vs. CPU clock cycles means it is a "language for the average". Go is great for any number of interesting high-level server-side components where it being done in half the time is better than it being 15% faster.
kevincox|5 years ago
> to be easily reviewable/checkable by coding teams.
I strongly disagree with this. I find Go code to be incredibly difficult to read. This is because of two main reasons.
The first is that the lack of expressive power in the language means that many simple algorithms get inlined into the code instead of using an abstraction with a simple and understandable name. I find that the first pass of the code is me reading over the lines (each of which is very simple and understandable) and virtually abstracting it into what the code actually does. I find that the interesting business logic is lost in all of the boilerplate.
vs As I said, every line in the Go is simple (except maybe for append, but generics can help with that). However the actual business logic is lost in the boilerplate. In the second example (Rust with one existing and available helper function) the boilerplate is much less and each line basically expresses a point in the business logic. There are really two bits of boilerplate here `filter_ok` instead of `filter` to handle the errors from `fetch` and the `collect` to turn the iterator into a collection (although maybe you could improve the code by returning an iterator instead of a collection and simplify this function in the process).Secondly the "defaults are useful" idea is in my opinion the worst mistake the language made. They repeated The Billion Dollar Mistake from C. I have seen multiple expensive production issues as a result of it and it makes code review much harder because you need to check that something wasn't uninitialized or nil. It is absolutely amazing in Rust that I don't have to worry about this for most types (depends on your exact coding style, in the above example there is never a variable that isn't "complete").
So while Go may be quick to write. I think the understandably is deceiving. Yes, I can understand every line, but understanding the program/patch as a whole becomes much more difficult because of the lack of abstraction. Humans can only hold so much in our head, making abstraction a critical tool for understandable code. So while too much of the medicine can be worse that the disease I think Go aimed - and hit - far, far below the ideal abstraction level.
pjmlp|5 years ago
> We—Ken, Robert and myself—were C++ programmers when we designed a new language to solve the problems that we thought needed to be solved for the kind of software we wrote. It seems almost paradoxical that other C++ programmers don't seem to care.
https://commandcenter.blogspot.com/2012/06/less-is-exponenti...
dx034|5 years ago
If I understand it correctly, your code doesn't check when unmarshalling if the content of Data has the expected structure. Using interface{} it's always been possible to achieve something like you'd do with Generics but it's ugly and can't check types at compile time.