7 ms·
That is not the recommended way to work with slices. These are novelties, aka tricks. The following is more representative. Delete: copy(a[i:],a[i+1:])
by joshuak 8y ago
That is not the recommended way to work with slices. These are novelties, aka tricks. The following is more representative.
Delete:
copy(a[i:],a[i+1:])
a = a[:len(a)-1]
Copy:
b := make([]T, len(a))
copy(b,a)
Push:
a = append(a, x)
Pop:
x := a[len(a)-1]
a = a[:len(a)-1]
Enqueue:
a = append([]T{x}, a...)
Dequeue:
x := a[0]
a = a[1:]
Idiomatic Go would have you not put on one line what is more clear on two.
- jonahx 8y ago> Idiomatic Go would have you not put on one line what is more clear on two. This is the kind of silly aphorism that sounds enlightened until you think about it, and is emblematic of the bad parts of Go dogma. The problem is that excessive LOC actually correlates strongly with poor readability, and all the cleverness in the world won't change that.
- C1sc0cat 8y agoNo cramming code into one line is never a good thing when you can make it clearer and easier to read by using 2, 3 or 4 lines of shorter more readable code.
- networkimprov 8y agoThis. Code density matters! Excessively low or high density are equally injurious to readability.
- Barrin92 8y agoI disagree strongly, at least as far as my intuition is concerned. it's not code density that matters, it's "context density". Long drawn out functions are usually not hard to read because they are long, but because it's not clear what they are about. It's lack of conciseness on part of the programs logic that makes programmers lose focus, not code density. As an example, think of a few fairly long switch statements or pattern matching logic. It's non-dense code depending on your language, but not hard to understand even if long. In contrast, some convoluted Haskell syntax with weird operators you've never seen is almost mentally incomprehensible. On these terms it's true that Golang is not 'text dense' but it doesn't matter, it stops semantics from being overly complicated, and it encourages simple structures that don't go overboard on condensing information.
- Arnavion 8y agoIt's also not even true, given that `if foo, err := bar(); err != nil {` is considered idiomatic over writing that over two lines.
- joshuak 8y agoBoth are idiomatic. I use the two line version. I don't like this form both for legibility, and the fact that it closes over the return value.
- reddit_clone 8y agoThey are not the same though. I got bitten by this recently (Go beginner). In the single line form, both foo and err are scope restricted to the if block. Found that out the hard way.
- laumars 8y agoReducing lines of code is not a free exercise since you make up for it with the length of the line and there have been plenty of studies that have shown how longer lines in written text are harder to read then shorter lines. That said, I'm not going to argue that developer will find shorter lines easier to read than longer lines but I certainly do. However it's also not as black and white as "shorter lines are always easier for me to read" either because there are some examples where it makes more sense to have it run on as one line. for example if you're calling a function who's return is only used as the input for another function. eg fmt.Println(strings.TrimSpace(" some string ")) makes more sense (in my opinion) than s := strings.TrimSpace(" some string ") fmt.Println(s) This is why the Go idiom says "what is more clear on two," rather than "use multiple lines even when it doesn't make sense."
- apta 8y ago> studies that have shown how longer lines in written text are harder to read then shorter lines. As are studies showing that bugs are correlated with more lines of code. final var a = if foo() { bar() } else { baz() } is much more readable and strictly less error prone than var a int if foo() { a = bar() } else { a = baz() } > fmt.Println(strings.TrimSpace(" some string ")) makes more sense (in my opinion) than What makes more sense is " some string ".TrimSpace() as it allows for easier reading due to call chaining. Of course the golang standard lib decides something else just for the sake of being different, and without providing a proper reason.
- laumars 8y ago> As are studies showing that bugs are correlated with more lines of code. Sure but do those same studies look at code with the same character count (ie longer but fewer lines) or are they just subtracting characters via subtracting lines. The ones I've seen were the latter in that they basically just said "less code == fewer bugs" - which shouldn't be a surprise to anyone. > [single line code] is much more readable and strictly less error prone than [multi-line code] You know, had you said that 10 years ago I'd have completely agreed with you. But these days I've read so much Go code that I now find the multi-line equivalent more readable simply because that's what I'm more used to reading these days. But we're not really talking about significant margins in either case. I mean you'd expect any developer to parse either statements with ease. I will say that I have always hated reading the ternary operator - which is the preferred way of doing single line if statements in some languages. I'd take the multi-line approach over the :? syntax any day. However from a strictly artistic perspective, the single line version with bracketed blocks is the nicest looking. So I can completely understand why people would prefer that method. Honestly, if gofmt let me, I almost certainly would write code that way too. > What makes more sense is: " some string ".TrimSpace() Your now arguing the benefits of OOP over other paradigms and while I agree that Go's implementation of OOP is half-arsed at best(!!!) I still have no intention of entering into that kind of ideological debate. Sorry.
- apta 8y agoLOC also correlates with bugs. This has been shown in studies on more than one occasion.
- indemnity 8y agoI don’t see how that is clearer than giving operations a name. Convince me? I mean, I could decompose a lot of things into their more primitive representations from named functions, but when scanning a code review, I don’t want to miss a bug because someone transposed a colon in a slice operation. It’s elegant in a minimalist way that all these things can be implemented in terms of slice operations, but why force everyone to reimplement these whenever they need to do something common that in other languages you just use the stdlib for and forget about?
- joshuak 8y agoThere are pros and cons to be sure, but mainly I was just pointing out that the parent to my post was a bit of a straw man. Of course you can give these operations names if you like, it's all up to you. In the form given you can account for every operation. It is easy to understand where the allocations are and where O(n) operations. There are no hidden temporaries which are quite common in other grammers. I do often create stacks, dequeues, heaps, and other collections inline as needed. But I find this to be a lot cleaner then some other languages. It has the advantage of brevity and clarity. I can say I like this a million times over c++ template semantics, though I too am not a fan of boilerplate, so I can understand some people's resistance to this. var stack []T push := func(x T) { stack = append(stack, x) } pop := func() T { x := stack[len(stack)-1] stack = stack[:len(stack)-1] return x } push(value) // ... value = pop()
- laumars 8y agoIn fairness, my biggest day to day pain point of using Go isn't the oft discussed lack of generics nor it's unpopular error returns. What bothers me the most when writing Go regularly is that I'm constantly having to reimplement basic functions for working with slices. The lack of a push or pop. Even selecting the last element of the slice via the following really becomes bothersome when you start dealing with multi-dimensional arrays: slice[len(slice)-1] The lack of a push and pop is a small inconvenience but it still disrupts my flow - not to mention adds unnecessary burden on testing to ensure I haven't cocked up something that should be elementary (and those kinds of errors are often a pain in the arse debug too). The latter isn't so much a productivity problem - I just think it looks ugly as sin. Which is why I sometimes add a .Last() method to any slice types I define where I need to read the last item regularly.
- cauthon 8y ago> Idiomatic Go would have you not put on one line what is more clear on two. Each operation was just clearly described with a single word; I think it's possible to describe them clearly with a single line
- photon-torpedo 8y agoWhatever the "proper" implementation of these slice primitives is, for me the real problem is that, due to the lack of generics, one can't write a utility library that provides simple names for these primitives.
- asdfasdfasdfa 8y agothat's still not great.