Skip to content

proposal: spec: language: make slices of constant strings constant if the indexes are constant #28591

Open

Description

@ainar-g

This will probably be assigned a Go2 label, although I think that it could be done during Go 1.

Consider multiline string constants:

const multiline = `
This is a long text
that spans multiple lines
and then ends.
`

If you feed this text to a parser and it finds a problem on the first line ("This is a long text"), it will actually report that the error is on the second line because of the leading newline. One might think that this is easily solved by slicing the string:

const multiline = `
This is a long text
that spans multiple lines
and then ends.
`[1:]

But this won't compile. The Spec currently says:

(…) For untyped string operands the result is a non-constant value of type string. (…)

Why not make it constant? After all, len(multiline) is constant.


There are other solutions to this. One could just use multiline[1:] everywhere where one doesn't want the leading newline. Or start "This is a long text" on the first line, but that hurts readability and "editability". Another solution is to make multiline a variable. The use case is pretty obscure and there isn't an immediate need for this, so this proposal is more about a question, why are slices (and indexing!) of constant strings not constant in the first place?

Activity

  1. added this to the Proposal milestone on Nov 4, 2018
  2. changed the title [-]proposal: make slices of constant strings constant if the indexes are constant[/-] [+]proposal: spec: make slices of constant strings constant if the indexes are constant[/+] on Nov 5, 2018
  3. changed the title [-]proposal: spec: make slices of constant strings constant if the indexes are constant[/-] [+]proposal: Go 2: language: make slices of constant strings constant if the indexes are constant[/+] on Nov 5, 2018
  4. ianlancetaylor commented on Nov 5, 2018

    @ianlancetaylor
    Contributor

    Marking as Go 2 because we've decided that all language changes are Go 2.

    I know that this has been discussed in the past but I don't remember why it wasn't changed. Maybe simply because it rarely comes up in practice.

  5. ianlancetaylor commented on Dec 11, 2018

    @ianlancetaylor
    Contributor

    We should also consider accepting

    const c = "abc"[1]
    
  6. added
    NeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.
    on Dec 11, 2018
  7. removed
    NeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.
    on Aug 16, 2019
  8. added
    NeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.
    on Sep 3, 2019
  9. griesemer commented on Jan 29, 2020

    @griesemer
    Contributor

    It turns out that this proposed change is not backward-compatible after all ...

    Consider "A"[0] : With the proposed change, this expression evaluates to the untyped byte constant 65. But if we try to negate this value, as in:

    var _ = -"A"[0]

    we will get an error: -"A"[0] (constant -65 of type byte) overflows byte . This is currently (without the change) valid code. Oops!

    For similar reasons, constant index expressions are not backwards-compatible either. The length of a constant slice expression len("abc"[0:2]) is an untyped integer constant (3), but if we negate it and try to assign it to a variable of uint type, we will get an error.

    var _ uint = -uint(len("abc"[0:2]))

    (Without the change, these values are not constant, and the compiler won't complain.)

    Fun times!

  10. griesemer commented on Jan 29, 2020

    @griesemer
    Contributor

    Related: #11370, #11368.

  11. jimmyfrasche commented on Jan 29, 2020

    @jimmyfrasche
    Member

    Would

    const (
      a = "abc"[iota]
      b
      c
    )
    

    be legal?

  12. griesemer commented on Jan 29, 2020

    @griesemer
    Contributor

    @jimmyfrasche Very nice! Indeed it would.

  13. 6 remaining items

  14. modified the milestones: Backlog, Proposal on Feb 6, 2020
  15. added and removed
    NeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.
    on Feb 6, 2020
  16. alandonovan commented on Feb 6, 2020

    @alandonovan
    Contributor

    The degree to which a strict reading of backward compatibility leaves little room to maneuver is constantly surprising.

  17. TapirLiu commented on Mar 22, 2020

    @TapirLiu
    Contributor

    One more case:

    _ = 1/len(""[:])

    Currently it compiles, but if len(""[:]) returns constant 0, it will not.

  18. rsc commented on May 6, 2020

    @rsc
    Contributor

    This was proposed for Go 1.15 (https://blog.golang.org/go1.15-proposals) but declined because it is not backwards compatible. Leaving open for some future breaking change (maybe).

  19. zigo101 commented on Sep 23, 2020

    @zigo101
    Contributor

    Another incompatible case:

    package main
    
    const s = "Go101.org"
    // len(s) == 9
    // 1 << 9 == 512
    // 512 / 128 == 4
    
    var a byte = 1 << len(s) / 128
    var b byte = 1 << len(s[:]) / 128
    
    func main() {
    	println(a, b) // 4 0
    }

    It will print 4 4 if this proposal is adpoted.

  20. alandonovan commented on Sep 23, 2020

    @alandonovan
    Contributor

    @go101 That's diabolical.

    Spoiler: the difference arises from the top-down effect of the enclosing type (byte) on the shift operator when its right operand is non-constant. Thus 1 << len(s[:]) is truncated to byte. The type rules for shifts are the most complex of all...

  21. adonovan commented on Jan 25, 2024

    @adonovan
    Member

    Given the new extended forward compatibility mechanism, this breaking change could be implemented in files that set a sufficiently high minimum Go version.

  22. changed the title [-]proposal: Go 2: language: make slices of constant strings constant if the indexes are constant[/-] [+]proposal: spec: language: make slices of constant strings constant if the indexes are constant[/+] on Aug 6, 2024
  23. added
    LanguageChangeReviewDiscussed by language change review committee
    and removed
    v2An incompatible library change
    on Aug 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions