Go: proposal: Go 2: reject (some) redundant expressions

Created on 20 Sep 2018  路  6Comments  路  Source: golang/go

Hi,

I love golang for simplicity and explicitness. But there are a few cases when a developer can write the same code in different ways. Why not restrict syntax (in Go2) only to one possible option.

package main

func main() {
    // compile error - negative buffer argument in make(chan error)
    _ = make(chan error, -1)
    // compile error - negative len argument in make([]error)
    _ = make([]error, -1)

    // Base on the above errors makes the language even more strict about syntax.

    // compile without error
    // should be an error -> zero len argument in make(chan error)
    _ = make(chan error, 0)

    // compile error -> missing len argument to make([]error)
    // should be no error here -> it's same as make([]error, 0) now.
        // NOTE: if we can make chan and map without giving the size why it's forbiden here?
    _ = make([]error)

        // compile without error
        // should be an error -> zero len argument in make([]error, 0)
        _ = make([]error, 0)

    // compile without error
    // should be an error -> zero cap argument in make([]error, 0, 0)
    _ = make([]error, 0, 0)

    // compile without error
    // should be an error -> zero size argument in  make(map[string]error)
        _ = make(map[string]error, 0)

    // compile without error
    // should be an error -> all constant comparisions like this have no meaning.
    _ = 1 == 2
        _ = 1 != 2.0
    _ = true == true
    _ = true != false

       // compile without error
       // should be an error -> all expression with 0 should be simplified
       i := 8
       _ = i >> 0
       _ = i << 0
       _ = i + 0
       _ = i - 0
       _ = i * 0


    // compile without error
    // should be an error -> don't use constant boolean in if statment (use !a/a instead)
    if a := true; a == true {
    }
}
FrozenDueToAge Go2 LanguageChange Proposal WaitingForInfo

Most helpful comment

  // compile without error
  // should be an error -> all expression with 0 should be simplified
  i := 8
  _ = i >> 0
  _ = i << 0
  _ = i + 0
  _ = i - 0

I disagree that these expressions should always be simplified. Stylistically, it can be helpful to include an explicit zero in some cases involving repetitive statements.

For example,

buf[i+0] = ...
buf[i+1] = ...
buf[i+2] = ...
...

All 6 comments

// compile without error
// should be an error -> all constant comparisions like this have no meaning.
_ = 1 == 2
_ = 1 != 2.0
_ = true == true
_ = true != false

I can agree with this one. I've always wondered why the compiler allows things like true == false. At the very least go vet should probably warn about it, as it's likely to be a bug.

  // compile without error
  // should be an error -> all expression with 0 should be simplified
  i := 8
  _ = i >> 0
  _ = i << 0
  _ = i + 0
  _ = i - 0

I disagree that these expressions should always be simplified. Stylistically, it can be helpful to include an explicit zero in some cases involving repetitive statements.

For example,

buf[i+0] = ...
buf[i+1] = ...
buf[i+2] = ...
...

I've always wondered why the compiler allows things like true == false.

  • Variations based on build constraints?
  • Generated code?
  • Manual debugging?

It's not always apparent which identifiers are constants, or which constants are constant across all architectures and tags.

As a proposal this needs more detail.

  • What is the motivation for this proposal?

    • What harm do these expressions cause today, and why is it worth the cost of churn for existing code?

  • What are the exact rules you propose for which expressions should be rejected?

    • How do those rules interact with build constraints, unsafe.Sizeof, and other variations in constants?

  • Can all existing code be fixed automatically?

i don't understand why most of these "should be" errors. i would absolutely use make([]foo, 0) if i wanted to have a non-nil thing but did not necessarily need it to have any contents, because "this is not nil" is itself data about the state of a thing. I can write code which distinguishes between a 0-length slice and a nil slice, therefore it's useful. Same for maps; why should I have to specify a non-zero size for a map?

I would tend to allow things like true == false because while they're unlikely to be reasonable in hand-written code, they might serve a useful function in machine-generated code, and the compiler can presumably optimize them effectively.

Per comments above, we aren't going to do this.

Was this page helpful?
0 / 5 - 0 ratings