6 ms·
A couple of responses: - I too dislike the lack of a ternary operator. Python has this problem too (you can create boolean expressions to sorta mimic it but it
by cletus 14y ago
A couple of responses:
- I too dislike the lack of a ternary operator. Python has this problem too (you can create boolean expressions to sorta mimic it but it doesn't tend to be considered "Pythonic"). And brevity is my reason too. I'm sure it's easier to parse without it but it can't be that hard.
- On the "damnable use requirement", I see his point. If anything, it means that Go will be better used with IDEs than text editors that'll do this for you automatically;
- On the "thread safe set", yeah he's Doing It Wrong [tm] (which I think he knows). You use channels to share state in Go rather than creating shared state directly.
- Unbuffered channels seem to be idomatic. Race conditions and deadlocks seem to often be the result of using buffered channels;
- On his channel reads issue ("violating time and space") I disagree: it's good to have blocking and non-blocking channel reads.
I basically agree with his conclusions, particularly in Go feeling like a "modern C", something I desperately hope succeeds.
- snogglethorpe 14y ago- They copied Pascal-style type declarations (good!) ... but then modified them to omit the colon (bad!). That one little simple change really makes type declarations less readable, for no apparent benefit. Using a colon makes the type clearly stand out, whereas without one, it sort of gets lost amid the variables. Pascal-style (Ada, etc, etc): var foo, bar : int = 1, 2 Go: var foo, bar int = 1, 2 The latter is uglier and harder to read, and doesn't save any appreciable space. p.s. One saving grace: they could probably add colons back into the type-declaration syntax as an option, without affecting existing programs....
- psykotic 14y agoIt's less of an issue with var declarations because of type inference. The bigger issue is with function signatures. Type signatures are mandatory there and you also have two levels of commas: func(a, b int, c, d bool). When it comes to syntax I generally prefer flat to nested (Python gets it right) but there is such a thing as too flat. A small saving grace is that exported identifiers in Go, including types, have to be capitalized, making them stand out in signatures.
- snogglethorpe 14y ago> exported identifiers in Go, including types, have to be capitalized Ugh... (notes another Go uglypoint)
- jff 14y agoTo some, explicitly placing keywords like "public", "private", "protected" all throughout your code is ugly. Go gives an explicitly defined coding style; all Go will look roughly similar, and it will never be ambiguous if an identifier is exported or not.
- snogglethorpe 14y ago> To some, explicitly placing keywords like "public", "private", "protected" all throughout your code is ugly. I dunno; maybe it's "ugly," but it's also explicit, and easy to see. Assigning meaning solely to subtle presentational differences can make code hard to read, and increase the likelihood of mistakes (as well as confusing beginners). [It's a similar problem to Python's significant whitespace.] Unfortunately it's all this sort of "cute idea" that makes Go seem rather half-baked. It's like they designed the language in a brainstorming session in a bar, mixing ideas from a bunch of people without strong editorial control, and then just released the result without actually understanding the repercussions of many of their decisions. [I'm not saying they're all bad, it just feels like there was a lot more brainstorming than vetting...]
- Jabbles 14y agoUnfortunately it's all this sort of "cute idea" that makes Go seem rather half-baked. It's like they designed the language in a brainstorming session in a bar, mixing ideas from a bunch of people without strong editorial control, and then just released the result without actually understanding the repercussions of many of their decisions. This is as far from the truth as I can imagine. Yes, "subtle presentational differences" can make code hard to read, but in this case it doesn't. When I reference another package I know that all exported variables begin with a capital letter. When I'm writing a package I know whether I'm calling a function that's "private" or "public" without having to look it up. It's one of some of the Go Authors' favourite ideas in use in Go, and I wish people would stop armchairing about the effect some language feature has without trying it. The likelihood of mistakes is not really increased, because they will be caught at compile time, or you'll end up with an exported function you didn't realise you wanted. A confused beginner should be able to understand this concept within seconds. And it's prominently mentioned in the Go tutorials.
- TazeTSchnitzel 14y agoI hate Pascal-style type declarations. Using AS3 has given me a great hatred of that colon.
- psykotic 14y ago> Python has this problem too Python has had conditional expressions since version 2.5. Dumb example: def count(xs, p): return sum(1 if p(x) else 0 for x in xs)
- bdr 14y agoSide note: you can simply use sum(p(x)) for x in xs), assuming p is a predicate. It's a neat trick, though a bit slower than your ternary version.
- bjourne 14y agoAnother way: len(filter(p, xs))
- daeken 14y agoWith the sum approach the data set never exists in memory, but is generated as needed; not a big deal for a small set, but it can add up.
- lclarkmichalek 14y agoAnd as in python3, filter returns a generator, not a list, the len call will fail altogether.
- bjourne 14y agoYes, I'm aware of that. But my philosophy is to always try to conserve keystrokes wherever possible. Premature optimization is the root of all evil and all that. :) For the same reason I prefer to use dict.items() over dict.iteritems() and range() over xrange() and so on.
- slurgfest 14y agoThis is a simple enough case that I'm not sure it matters, but I think the sum version is simpler to read. Generator expressions are quite powerful if you want to write Python which is more functional-flavored.
- Locke1689 14y ago- On the "damnable use requirement", I see his point. If anything, it means that Go will be better used with IDEs than text editors that'll do this for you automatically; The lack of partial/incremental/parallel compilation make this a lot less attractive. A lot of IDE technology (e.g., "intellisense," syntax errors, missing imports) are built off of rapid recompilation. In fact, doing it any other way seems pretty stupid. If your compiler doesn't offer that information then the IDE has to re-implement those codepaths just to provide that information.
- saljam 14y agoGo generally compiles so quickly, incremental compilation is unnecessary.
- sirclueless 14y agoActually, incremental compilation is the main reason Go compiles so quickly. Super-fast incremental compilation is the reason they never bothered with parallel compilation.
- luriel 14y agoGo does incremental compilation just fine. Nobody has bothered to add parallel compilation because building Go code is already so ridiculously fast.
- danieldk 14y ago...under the assumption that something does not depend on too many cgo packages.
- rogpeppe1 14y agoactually, the Go tool compiles packages in parallel by default.
- slurgfest 14y agoFast is relative to purpose. Maybe could afford to be faster in the context of an IDE checking your code on the fly, for a large project. I wouldn't know, since I have not attempted to write it.
- Evbn 14y agoWe need a preprocessor Come to add stub code for unused cars and imports.
- wapper 14y agoNo you don't import ( _ "fmt" ) Try it.
- ulber 14y agoOn the "violating time and space" issue, I don't think the problem was on there being both blocking and non-blocking channel reads. Instead the problem for him was that in his mind the channel read "happens first" and how the result from that read is used (i.e. what it is assigned to) shouldn't have any effect on the read anymore. I must say that I agree and would prefer to have a more clearly separate syntax for blocking and non-blocking reads.
- cmccabe 14y agoYeah, it's arbitrary that val, ok := <- ch does something different than val := <- ch, but any other convention for differentiating blocking from nonblocking would be just as arbitrary. I think it's something I would get used to after a while.
- Jabbles 14y agoIt certainly does, but they're both blocking. http://news.ycombinator.com/item?id=4569456 http://news.ycombinator.com/item?id=4569456
- cmccabe 14y agoThanks for the correction. Back when I first used go, they did different things. The change makes sense, I think-- we already have select for nonblocking I/O.
- ajanuary 14y agoIt's not so much arbitrary as an exception. "The RHS is evaluated and assigned to the LHS, except in this edge case". Using a different syntax would be just as arbitrary, but less of an exception e.g. val, ok := <- ch, val := <~ ch still follows the expected order of evaluation.
- deleted 14y ago[deleted]
- masklinn 14y ago> it's good to have blocking and non-blocking channel reads. That's not really his issue. His issue seems to be the overloading of the channel read to very different operations based on the number of return values. I don't think he'd have minded if blocking and non-blocking channel reads were different operators, but it's the same operator returning either one or two values. It's harder to read.
- neild 14y agoToo much can be made of the idea of sharing state via channels. If it's simpler to express a piece of code using a mutex, use a mutex. A thread-safe set is one such situation. Don't feel bad about doing so; there is nothing non-idiomatic about using locks in Go. When using channels, the choice between buffered and unbuffered depends on the situation. There are cases where a buffered channel is required to avoid deadlocks. For example, consider the case where you start N goroutines and use a channel to collect the results. If you return before collecting all results, the remaining goroutines will block forever trying to write to an unbuffered channel. Using a buffered channel with size N avoids this possibility.
- ralph 14y agoAgreed, Rob Pike, in his search engine example at Google's I/O 2012 IIRC, made the explicit point that mutexes are there and that channels are for joining large concurrent parts of the program together; guarding a data structure seems too small even though it's a common (toy?) example. http://www.youtube.com/watch?feature=player_embedded&v=f6kdp27TYZs http://www.youtube.com/watch?feature=player_embedded&v=f...
- Jabbles 14y agoGo doesn't have non-blocking receives anymore. value, ok := <- ch will block, always. Iff the channel is closed, ok will be false, allowing you to distinguish between a zero value sent on the channel, and the zero value you get back if you try to receive on a closed channel. Receiving from a nil channel always blocks. Select statements allow you to check if a channel has had a value sent on it. http://golang.org/ref/spec#Receive_operator http://golang.org/ref/spec#Receive_operator https://groups.google.com/d/msg/golang-nuts/Z63l4LDOlsI/54uTd4x9eiIJ https://groups.google.com/d/msg/golang-nuts/Z63l4LDOlsI/54uT... http://golang.org/ref/spec#Select_statements http://golang.org/ref/spec#Select_statements
- deleted 14y ago[deleted]
- crawshaw 14y agoFor those who didn't dive into the spec, the non-blocking recieve syntax has changed to use the select statement: func f(ch chan int) { select { case v := <-ch: fmt.Println("got", v) default: fmt.Println("did not block") } } http://play.golang.org/p/ql0qSUVXeX http://play.golang.org/p/ql0qSUVXeX
- slurgfest 14y agoFor information of readers, Python does have a ternary operator. I don't know or care whether it is considered Pythonic, since it is basic Python syntax and seems quite readable to me, e.g. x = (2 if y > 3 else 4)