Skip to content

Add sugar v[a .. b] be sugar for vec.slice and str.slice #4160

Description

@erickt

** UPDATE by @nikomatsakis **

Closed in favor of this RFC repo issue: rust-lang/rfcs#13

** ORIGINAL **

@graydon said in irc today:

graydon: I would like foo[a..b] to work for slicing, tbh
graydon: I mean, if the square brackets (arguably some of the nicest symbols available in ascii) are stolen for vecs, we might as well use them as thoroughly as we can

Activity

  1. brendanzab commented on Dec 12, 2012

    @brendanzab
    Contributor

    What about having some sort of sugar for str.len()? D allows you to use $ in index and slice operators to specify the length of the arrays. Eg:

    // These expressions are equivalent:
    bar[]
    bar[0 .. 4]
    bar[0 .. $]
    bar[0 .. bar.length]
    

    Also (from this article):

    int[] c = a[$-2..$]; // c refers to the last two elements of a
                         // ($ stands for length inside a slice or index operation).
    

    D also allows you to overload the slice and slice assignment operators. The nice thing about being able to overload those operators would be that you'd be able to implement vector slicing in core, as opposed to it being some compiler magic.

  2. Dretch commented on Dec 13, 2012

    @Dretch
    Contributor

    How about copying the python syntax (http://stackoverflow.com/questions/509211/good-primer-for-python-slice-notation).

    I.e (in python):

    a[start:end] # items start through end-1
    a[start:]    # items start through the rest of the array
    a[:end]      # items from the beginning through end-1
    a[:]         # a copy of the whole array
    
  3. brendanzab commented on Dec 14, 2012

    @brendanzab
    Contributor

    That's a decent idea. So start and end would be new keywords? That's the only bummer.

  4. kud1ing commented on Dec 14, 2012

    @kud1ing

    start and end are just variable names in the Python example. I think the suggestion is that if you don't give an index, it either stands for 0 or length() - 1.

  5. brendanzab commented on Dec 14, 2012

    @brendanzab
    Contributor

    Oh, silly me. Yeah I see. That seems like an elegant solution.

  6. jruderman commented on Jan 10, 2013

    @jruderman
    Contributor

    +1 for copying the Python syntax.

  7. jruderman commented on Jan 27, 2013

    @jruderman
    Contributor

    Special interpretation of negative numbers scares me. It sounds both slow (requiring a branch) and dangerous (you expected a crash, but instead you got the last element of the array). I prefer D's approach.

  8. mneumann commented on Jan 28, 2013

    @mneumann
    Contributor

    I also prefer the D syntax using ... This is also the same syntax as in match range patterns. I don't think leaving off the first component (like in Python arr[:9]) makes much sense, as it can be simply written as a 0. Using $ as the length also makes absolute sense to me. I am thinking of it as in a regular expression. Python uses a : because it has an additional step element, and I think Python always copies slices because of this.

  9. brendanzab commented on Jan 28, 2013

    @brendanzab
    Contributor

    The issue with using $ is that it conflicts with macros.

  10. sanxiyn commented on Jan 28, 2013

    @sanxiyn
    Contributor

    Does # work?

  11. mneumann commented on Jan 28, 2013

    @mneumann
    Contributor

    For the rare case that we would need $ in a macro, couldn't it be escaped in some way? What about this:

    a[0:]     vec::view(a, 0, a.len())
    a[0:3]    vec::view(a, 0, 3)
    a[0:^1]   vec::view(a, 0, a.len()-1)
    

    Here ^1 would mean without one element at the end. This has the advantage that we don't have to do the minus as in $-1 ourself and as such might prevent some casting issues (the end index could become negative). Similarily one could apply the same for the beginning a[^1:] would means "without the first element". The only advantage I would see here over plain a[1:] is that of non-zero indexed arrays (which we don't have of course).

  12. fabiand commented on Mar 11, 2013

    @fabiand
    Contributor

    I also favor the python syntax, it comes very handy. Including using negative numbres to specify the offset from the end of an array. Does it really need a branch?

  13. graydon commented on Mar 11, 2013

    @graydon
    Contributor

    Prefer not to add $ or ^ support, nor a syntax different from ".." for ranges (which is currently supported in expression and pattern grammars, and may be worth using in type grammar rather than the current "* N"). 0 and foo.len() are ok for the explicit ends. Think simplicity and symmetry.

    Keep in mind we now support restructuring vector patterns, which soaks up some of this feature.

  14. jruderman commented on Mar 11, 2013

    @jruderman
    Contributor

    I don't like using foo.len() for the end because it's easy to mess up, and because foo might be a complicated expression I don't want to repeat.

  15. 10 remaining items

  16. nikomatsakis commented on Nov 20, 2013

    @nikomatsakis
    Contributor

    Just for the record, I favor this strongly, and this is my preferred form.

    1. Add a Slice trait (see below).
    2. Add a slice operator expr[a..b] where a and b are optional.
      • The operator autoderefences, like indexing.
      • For fixed-length vectors, its effect is built-in.
      • For other types, it is translated to a call to the appropriate trait method:
        • expr[..] => expr.as_slice()
        • expr[a..] => expr.slice_from(a)
        • expr[..b] => expr.slice_to(b)
        • expr[a..b] => expr.slice(a, b)
    3. Do we have something for mutable slices? Perhaps expr[mut a..b]? These come up less frequently but nonetheless it seems useful, particularly for fixed-length vectors since otherwise there remains no explicit syntax for slicing one that does not rely on coercion.

    Note there is no special syntax for length. That eliminates some use cases. Oh well. There is also no accommodation for negative indices. Oh well. These things are not that important: the main use is a[..-1] to lop off the last thing in the list, and we have head() for that.

        trait Slice<T> {
            fn as_slice<'a>(&'a self) -> &'a [T];
            ...
        }
    
        trait MutSlice<T> { ... }
    
  17. pzol commented on Jan 26, 2014

    @pzol

    I like @nikomatsakis proposal.

    However, I think negative indices should be used like in Ruby, -1 would be the last element, so [-5..-1] would give the last 5 elements.

  18. flaper87 commented on Jan 26, 2014

    @flaper87
    Contributor

    cc me

    I like this proposal!

  19. mneumann commented on Jan 26, 2014

    @mneumann
    Contributor

    Hm, most of the time I am either dropping off elements from the front of a vector or from the tail of it, or more seldom from both sides at the same time. Without using negative indices, the slice operator is missing a common use-case (dropping off elements from the end). BUT, I don't like the use of negative numbers for counting backwards. Something like expr.init() is IMHO much more verbose than expr[..-2] and much less prone to errors, except that I would prefer expr.without_last or expr.excluding_last to be easier to understand, especially when it comes to initn which is completely misleading IMHO as it does not return the initial n elements, NO, it excludes the last n elements.

    So my suggestion would be to not include the slice operator at all, but provide more understandable methods like firstn, lastn, excluding_last, excluding_lastn etc.

  20. glaebhoerl commented on Jan 26, 2014

    @glaebhoerl
    Contributor

    Extending indexing from elements arr[i] to slices arr[i..j] is straightforward and easy to grok. I agree about providing dedicated methods instead for the remaining use cases.

  21. bstrie commented on Feb 13, 2014

    @bstrie
    Contributor

    +1 to nmatsakis' proposal verbatim. No comma, no syntax for length, no negative indices. Clean and simple.

  22. jakerr commented on Feb 13, 2014

    @jakerr
    Contributor

    Another +1 to nikomatsakis' proposal.
    It's intuitive and doesn't preclude adding negative indexes in the future if there is a huge demand for them.

  23. Valloric commented on Feb 14, 2014

    @Valloric
    Contributor

    Another +1 for Niko's proposal. It's well thought-out.

  24. huonw commented on Feb 14, 2014

    @huonw
    Contributor

    The one problem with @nikomatsakis's proposal is it requires contiguous storage, so e.g. doesn't work with rope types, or vectors with strides.

  25. molysgaard commented on Feb 15, 2014

    @molysgaard

    One more +1 for Niko's proposal.

  26. emberian commented on Mar 15, 2014

    @emberian
    Contributor

    I don't think the complexity is worth it really.

  27. liigo commented on Mar 16, 2014

    @liigo
    Contributor

    +1
    2013年11月21日 上午1:21于 "Niko Matsakis" notifications@github.com写道:

    Just for the record, I favor this strongly, and this is my preferred form.

    1. Add a Slice trait (see below).

    2. Add a slice operator expr[a..b] where a and b are optional.

      • The operator autoderefences, like indexing.
      • For fixed-length vectors, its effect is built-in.
      • For other types, it is translated to a call to the appropriate
        trait method:
       - expr[..] => expr.as_slice()
       - expr[a..] => expr.slice_from(a)
       - expr[..b] => expr.slice_to(b)
       - expr[a..b] => expr.slice(a, b)
      3. Do we have something for mutable slices? Perhaps expr[mut a..b]?
      

      These come up less frequently but nonetheless it seems useful, particularly
      for fixed-length vectors since otherwise there remains no explicit syntax
      for slicing one that does not rely on coercion.

    Note there is no special syntax for length. That eliminates some use
    cases. Oh well. There is also no accommodation for negative indices. Oh
    well. These things are not that important: the main use is a[..-1] to lop
    off the last thing in the list, and we have head() for that.

    trait Slice<T> {
        fn as_slice<'a>(&'a self) -> &'a [T];
        ...
    }
    
    trait MutSlice<T> { ... }
    

    —
    Reply to this email directly or view it on GitHubhttps://github.com//issues/4160#issuecomment-28909198
    .

  28. nikomatsakis commented on Mar 17, 2014

    @nikomatsakis
    Contributor

    Clearly this is RFC material. I'm going to close this issue and open one on the rfcs repo :)

  29. added a commit that references this issue on Feb 2, 2025
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

    C-enhancementCategory: An issue proposing an enhancement or a PR with one.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions