Thirteen: don't try to sort, it's going to be painful if you do. http://golang.org/pkg/sort/ (See example 1 -- you have to write that for every concrete slice type you want to sort; it's not enough to write it once. And god help you if you also want to sort other collection types.)
Project Lombok for Go would be relative easy, and so nice.
Twelve Go Best Practices
91–100 of 153 posts
Re: Twelve Go Best Practices
#92Earlier quoted context omitted.
The very next slide cleans it up using a "utility type" which reminds me of the "monadic" Haskell solution.
No way, the next slide is the very definition of evil unmaintainable code . Go through what is happening quickly: bw := &binWriter{w: w} bw.Write(int32(len(g.Name))) bw.Write([]byte(g.Name)) bw.Write(g.Age) bw.Write(g.FurColor) return bw.err If an error happens on L2, we will still run writes L3-L5. Why is this bad? Because in the future, we might come in and add logic after the writes complete. We have to make sure…
err = Write(int32(len(g.Name)))
err |= Write([]byte(g.Name))
err |= Write(g.Age)
err |= Write(g.FurColor)
return err;
If err is of type int with 0 == noError, this will require some new syntax if you want to return the correct error code (which you should want to do). I would suggest introducing x ||= y x = x || y
In English: if x (still) equals its default, evaluate y and assign the result to x"One could even shortcut this to
err = Write(int32(len(g.Name)))
|| Write([]byte(g.Name))
|| Write(g.Age)
|| Write(g.FurColor)
return err;
Advantage: that's how the shell works, too. Disadvantage is that 'logical or' is not what one associates with "run items until first failure", but that can be learned.An alternative could be to have a language construct that takes a sequence of lambda's, executes them in sequence until the first one that fails (if any) and returns the index and the result code of the failing lambda. That would get you something like:
index,err = SEQ([
Write(int32(len(g.Name)))
, Write([]byte(g.Name))
, Write(g.Age)
, Write(g.FurColor)
]);
I like the first idiom better, though.Re: Twelve Go Best Practices
#93"Deploy one-off utility types for simpler code" can be called a monad or Optional. I wonder if the language developers will add more formal support for that; it looks impossible to add Optional as a library due to lack of user-configurable generics.
Go occupies an interesting space. In my mind, I see it as competing simultaneously with C and Python. I suppose that the developers didn't see a place for an Optional type within that realm. I have to admit, I think it's a shame; huge proponent of non-nullability here. Especially given that with Go's lightweight lambda syntax a functor type would be easy to work with, I'm disappointed with its exclusion.
I would assume that everything that hasn't been implemented in Go 1.1 is not implemented because the devleopers of Go "didn't see a place for" it.
Now, either not seeing it as more important than the theings that did make it in, or seeing it as trickier to implement and acceptable to do without in 1.x, that's quite valid.
Re: Twelve Go Best Practices
#94"Deploy one-off utility types for simpler code" can be called a monad or Optional. I wonder if the language developers will add more formal support for that; it looks impossible to add Optional as a library due to lack of user-configurable generics.
I'm sort of hoping someone forks Go to provide at least a few single-depth generics like Optional/Maybe, to match Map and Slice.
_, err := potentiallyErroringOperation()
// with idiomatic nil
if err != nil {...}
// with monadic Option
if err.isDefined() {....}
EDIT: fix typoRe: Twelve Go Best Practices
#95if err == nil { _, err := w.Write([]byte(g.Name)) if err == nil { err := binary.Write(w, binary.LittleEndian, g.Age) if err == nil { return binary.Write(w, binary.LittleEndian, g.FurColor) } return err } return err } Why does anyone have to tell people not to do this? How does it enter anyone's mind as a thing to do in the first place? I've been known to go too far to minimize nesting. I get twitchy at the second lev…
Short circuit returns are the devil - they make it much harder to factor out part of a function into a smaller function. A function should have one entry point and one exit point; that's the whole point of structured programming. If you're going to return from some random point in the middle of your function you might as well be using goto. (Of course, good programming languages provide a better solution than pyramid…
Re: Twelve Go Best Practices
#96"Deploy one-off utility types for simpler code" can be called a monad or Optional. I wonder if the language developers will add more formal support for that; it looks impossible to add Optional as a library due to lack of user-configurable generics.
I'm sort of hoping someone forks Go to provide at least a few single-depth generics like Optional/Maybe, to match Map and Slice.
Re: Twelve Go Best Practices
#97Earlier quoted context omitted.
Go occupies an interesting space. In my mind, I see it as competing simultaneously with C and Python. I suppose that the developers didn't see a place for an Optional type within that realm. I have to admit, I think it's a shame; huge proponent of non-nullability here. Especially given that with Go's lightweight lambda syntax a functor type would be easy to work with, I'm disappointed with its exclusion.
> Go occupies an interesting space. In my mind, I see it as competing simultaneously with C and Python. I suppose that the developers didn't see a place for an Optional type within that realm. I would assume that everything that hasn't been implemented in Go 1.1 is not implemented because the devleopers of Go "didn't see a place for" it. Now, either not seeing it as more important than the theings that did make it in…
Re: Twelve Go Best Practices
#98Re: Twelve Go Best Practices
#99The type cast as part of the switch is really cool, I hadn't seen that before. switch v := v.(type) { case string: w.Write(int32(len(v))) w.Write([]byte(v)) default: w.err = binary.Write(w.w, binary.LittleEndian, v) } Great way to alter control flow based on the type, without a ton of ugly casts cluttering things up.
Of all the code in there this part confused me. What exactly is being switched on? It looks like v is being reassigned to the type of v, then the type of v is written out (instead of the value).
v is not being reassigned, it is being declared (note := rather than =). But its a little complicated, because type switches are a special syntax construct that is similar to, but different than, regular expression switches. See, "Type switches" in the language reference [1]
[1] you'll have to scroll down a little within the section on Switch statements: http://golang.org/ref/spec#Switch_statements
Re: Twelve Go Best Practices
#100Earlier quoted context omitted.
Short circuit returns are the devil - they make it much harder to factor out part of a function into a smaller function. A function should have one entry point and one exit point; that's the whole point of structured programming. If you're going to return from some random point in the middle of your function you might as well be using goto. (Of course, good programming languages provide a better solution than pyramid…
Having trouble picturing a better solution that isn't also morally equivalent to goto. Would you mind providing an example of your preferred approach?
The solution I prefer is a monad with some light notation (Haskell do, scala for/yield). So it looks like:
def doSomething(): Validation[Whatever] =
for {
result1
The Is this goto-like? You could argue so - once one computation fails, the rest turn into noops and we pass immediately to the end. But to my mind this is like replacing an if/else with polymorphism - our validation context is an object with certain behaviours, and we're calling methods on it with our functions as parameters, which will behave differently depending on which subtype our context instance is.