9 ms·
Things I Love About Go
- koenigdavidmj 14y agoA lot of these are simply the Go people declaring certain conventions by fiat: gofmt, the go build tool, a large standard library, and the like. These are a lot of the benefits that Python had: everybody pretty much has to do things the same way (and there's PEP 8 that establishes non-enforced conventions), so I can start playing with a new codebase without having to figure out their conventions and build system too.
- drivebyacct2 14y agoIt's unbelievable how helpful it is. The Go article that was posted last week was lambasted for a lot of good reasons, but even as a Go fan I was annoyed at how hard it was for me to quickly scan the source because it didn't follow the conventions that I'm used to staring at quickly.
- acomjean 14y agoGo seems like a rehash of Ada, without the option to dynamically linked. Maybe an improved version of Ada. I liked some feature of Ada a lot, it was safe, input, output, in/out parameters for functions. Of course to make itself useful as a lower level language you need to be able to call OS functions, which in unix means C. So then you have to start wrapping... Some parts of Ada were terrible (string handling comes to mind.) I think its worth a look, but I'm still not sure what problem its trying to solve.
- Peaker 14y agoGo repeats the mistake of Boolean Blindness [1] so I think it disqualifies it from "safe", though. [1] http://existentialtype.wordpress.com/2011/03/15/boolean-blindness/ http://existentialtype.wordpress.com/2011/03/15/boolean-blin...
- drivebyacct2 14y agoYou posted this a few days ago, I didn't understand it and still don't understand after another read through. Can you give either a dumbed down summary or a scenario or an example of a language that doesn't do this?
- zemo 14y agothe last time he posted this was in response to me, so I'll join the discussion here to avoid duplication. This was his response when I asked for some clarification: >My problem with Go is that it does not have sum-types and pattern-matching. This means that branching (conditionals) in Go do not gain any type-information. And that means that programmers have to manually keep track of the invariants that hold true in each of their conditionals, and if they get them wrong, they get no help from the compiler.
- Peaker 14y agoBasically, the idea is that when you branch on a conditional, information is gained. This information may be represented in the type system and used by the compiler to verify safety, or it can be ignored. If it is ignored, the language is said to have "boolean blindness". Example: if (ptr == NULL) { ... a ... } else { ... b ... } In branch a and branch b, different invariants about ptr hold. But the language/compiler are not verifying any of these invariants. Instead, consider: data Maybe a = Nothing | Just a This defines a type "Maybe", parameterized by a type variable "a", and it defines two "data constructors" that can make a Maybe value: "Nothing" which contains nothing, and "Just" which contains a value of type "a" inside it. This is known as a "sum" type, because the possible values of the type are the sum of all data constructor values. We could still use this sum data-type in a boolean-blind way: if isJust mx then .. use fromJust mx .. -- UNSAFE! else .. can't use content of mx .. However, using pattern-matching, we can use it in a safe way. Assume "mx" is of type "Maybe a": case mx of Nothing -> ... There is no value of type "a" in our scope Just x -> ... "x" of type "a" is now available in our scope! So when we branch on the two possible cases for the "mx" type, we gain new type information that gets put into our scope. "Maybe" is of course a simple example, but this is also applicable for any sum type at all. If your language does branching without giving you back any new type information, it means you have to manually track the invariants and conditionals your program is in. If you get it wrong, your program will die at runtime. Instead, the language can almost always provide you some kind of proof that you can pass along of the conditional's truthness, which makes it safe to rely on it.
- ralph 14y agoSorry, but having had some dealings with Ada many years ago I'm sure Go is little like it. Go has CSP in its ancestry, what with channels and goroutines, and both are fundamental to it whereas Ada has nothing similar?
- pjmlp 14y agoGoroutines -> tasks channels -> rendezvous
- ralph 14y agoAda's tasks aren't defined to be greenlets; an implementation can make then OS threads or processes, limiting their number. And rendezvousing is more cumbersome than channels, e.g. passing a channel over a channel.
- pjmlp 14y agoI can be wrong, but as far as I know, Go language's specification also does not define how goroutines are to be implemented. Google's implementation makes use of greenlets, while gccgo is using OS threads. Further implementations might decide on others approaches. As for channels/rendezvous you might be correct, as I only played a bit with Ada.
- ralph 14y agoYou could be right about the spec. I think gccgo no longer does one OS thread per goroutine as of Go 1.0 but I've been unable to find a clear definition to point to.
- pjmlp 14y ago> Go seems like a rehash of Ada, without the option to dynamically linked. Maybe an improved version of Ada. Go has more in common with Oberon and Component Pascal than Ada
- Hominem 14y agoThere are some neat things about it. Being able to retroactively distill an interface from code you do not have the source to. Sometimes I wish I could do this in c# when I mock stuff up. Goroutines and channels are cool because they are simple to use. We have tasks in c# and I could construct channels in countless ways. But go makes them dirt simple. I don't like the terse c-like naming conventions but that is a manner of taste. Makes it feel more close to the metal and less enterprisey I guess. I wish there was go#
- rwj 14y agoI definitely agree with your comment about interfaces. This appears to be a concept that could be transplanted to C++, and would help quite a bit. Often in C++, people rely on template (compile-time polymorphism) because it is not possible to retroactively use interfaces (run-time polymorphism).
- deleted 14y ago[deleted]
- dsymonds 14y ago"less enterprisey" is a feature.
- Hominem 14y agoYeah I'm guessing that is why they went that direction. It really isn't any less enterprisey than anything else and we ended up with stuff like fmt.printf, who would have guessed printf is in something called fmt. Well I guess it stands for format, but is printf primarily a formatting function? It prints and the formatting is a convenience. If we are meant to use it for formatting, it is badly named.
- batista 14y agoNot really. Printf is all about "formatted printing". What you think the "f" at the end stands for and has stood for since C? If anything, its the opposite of what you say, ie the "fmt" package name is not measleading but redundant!
- jbert 14y agoI'm learning a bit of go at the moment, and liking it a lot. One thing which caused me a little head scratching was doing something like this: for _, item := range slice_of_obj { item.update() } where the 'update' method wrote to some member data in item. It seems that the 'item' is a copy of, rather than an alias to, the underlying object, so the mutating 'update' call is updating the copy, which is then discarded. (The 'right way' to do this to use the loop index and slice_of_obj[i], but that seems mildly barbaric) This seemed odd to me, particularly since no error was generated. Can anyone comment if I'm doing anything particularly dumb here? If Go had a concept of 'const', at least it could throw an error when you mutate the copy which is going to be discarded.
- densh 14y agoIMO The right way is to have a slice filled with pointers rather than bare structs: https://gist.github.com/2975397 https://gist.github.com/2975397 Btw code that uses range will always be faster than alternative with for loop and indexing (obj[i]) as range-based code can be optimized by Go compiler not to perform any bound checks.
- jbert 14y agoYes, that works nicely, thanks. But sometimes (rarely) you do want a contiguous bunch of objects, rather than have the indirection. I think ideally, it would work (as an alias) but if not, I think it should error. Or maybe this is a FAQ, with a good rationale, which I just haven't got to yet.
- drivebyacct2 14y agoI've been burnt by it as well, I didn't read the spec closely enough apparently. I would love to see it called out in an example.
- jgrahamc 14y agoThe effect you are seeing there is because the as it says in the documentation: "The iteration values are assigned to the respective iteration variables as in an assignment statement." So item is being assigned and because it's an obj and not a *obj you are getting a copy. Whereas slice_of_obj[i] is accessing the element within the slice without a copy. One solution to this problem would be to store pointers in your slice instead of objects.
- Nate75Sanders 14y agoStatically linked binaries (No dependencies hell, easy to deploy in production) Is this always this way? I'd be interested in a discussion on the pros/cons of this. Some are obvious, but I'm interested in a deep discussion.