Arc Forumnew | comments | leaders | submitlogin
Cut and Index - Arc and Ruby Side By Side
13 points by mdemare 6126 days ago | 23 comments
Let's list all cases, first Ruby(1.9), second Arc (2nd release).

The i'th item of s

    s[i]
    (s i)
The i'th item of s from the end

    s[-i]
    (s (- (len s) i))
The first x items of s

    s[0,x]
    (cut s 0 x)
The last x items of s

    s[-x..-1]
    (cut s (- (len s) x))
The items from position i to the end

    s[i .. -1]
    (cut s i)
The items from position i to position j (inclusive)

    s[i .. j]
    (cut s i (+ 1 j))
The items from position i to position j (exclusive)

    s[i ... j]
    (cut s i j)
i items beginning at position j.

    s[j,i]
    (cut s j (+ i j))
The items from position i to the end minus the last j items

    s[i ... -j]
    (cut s i (- -1 j))
i items beginning at the j'th position from the end

    s[-j,i]
    (cut s (- (len s) j) (+ (- (len s) j) i))


6 points by bogomipz 6126 days ago | link

Surprisingly, nobody in this thread has suggested that lists/strings in functional position could accept two arguments. This would replace the current cut function. Additionally, negative numbers should mean index from the end, and 0 as second argument could mean "to the end". Here's Python, Ruby, arc1, and lastly my suggested semantics:

The i'th item of s

    s[i]
    s[i]
    (s i)
    (s i)
The i'th item of s from the end

    s[-i]
    s[-i]
    (s (- (len s) i))
    (s (- i))
The first x items of s

    s[:x]
    s[0,x]
    (cut s 0 x)
    (s 0 x)
The last x items of s

    s[-x:]
    s[-x..-1]
    (cut s (- (len s) x))
    (s (- x) 0)
The items from position i to the end

    s[i:]
    s[i .. -1]
    (cut s i)
    (s i 0)
The items from position i to position j (inclusive)

    s[i:j+1]
    s[i .. j]
    (cut s i (+ 1 j))
    (s i (+ 1 j))
The items from position i to position j (exclusive)

    s[i:j]
    s[i ... j]
    (cut s i j)
    (s i j)
i items beginning at position j.

    s[j:j+i]
    s[j,i]
    (cut s j (+ i j))
    (s j (+ i j))
The items from position i to the end minus the last j items

    s[i:-j]
    s[i ... -j]
    (cut s i (- -1 j))
    (s i (- j))
i items beginning at the j'th position from the end

    s[-j:-j+i]
    s[-j,i]
    (cut s (- (len s) j) (+ (- (len s) j) i))
    (s (- j) (+ i (- j)))

-----

0 points by pg 6126 days ago | link

http://arclanguage.org/item?id=2257

-----

4 points by bogomipz 6126 days ago | link

I'm honored by you replying to my comment, Paul, but that link points to this thread?

-----

5 points by pg 6126 days ago | link

Sorry, meant http://arclanguage.org/item?id=2301

-----

1 point by jc 6118 days ago | link

I second this. It seems easier to ape Python's syntax for slicing. For example, given s as "abcde,"

  s[1:4]
  (s 1 4)
gives "bcd,"

  s[1:-2]
  (s 1 (- 2))
gives "bc,"

  s[-4:]
  (s (- 4) nil)
gives "bcde," and

  s[:]
  (s nil nil)
gives "abcde."

-----

7 points by mdemare 6126 days ago | link

To sum up, Arc wins once, draws three times and loses six times (counting tokens, not characters).

I think the goal for Arc should be to be powerful enough to express all these cases without resorting to expressions (+ - len).

Most obvious improvement - allow negative indices for the second argument. Then you could say:

    (cut s -x)
for

    s[-x .. -1]
Right now, Ruby just has more syntax to express this, e.g. four different forms:

    s[x] ; s[i,j] ; s[i .. j] ; s[i ... j]
Arc only has three:

    (s x) ; (cut s x) ; (cut s i j)

-----

7 points by steadicat 6126 days ago | link

Python only has two forms (s[x] ; s[i:j]), yet it can express the same things more succinctly: see below.

I find Python's model vastly superior. Less syntax to learn, yet more powerful.

Here is the comparison with Python added in as the first one:

The i'th item of s

    s[i]
    s[i]
    (s i)
The i'th item of s from the end

    s[-i]
    s[-i]
    (s (- (len s) i))
The first x items of s

    s[:x]
    s[0,x]
    (cut s 0 x)
The last x items of s

    s[-x:]
    s[-x..-1]
    (cut s (- (len s) x))
The items from position i to the end

    s[i:]
    s[i .. -1]
    (cut s i)
The items from position i to position j (inclusive)

    s[i:j+1]
    s[i .. j]
    (cut s i (+ 1 j))
The items from position i to position j (exclusive)

    s[i:j]
    s[i ... j]
    (cut s i j)
i items beginning at position j.

    s[j:j+i]
    s[j,i]
    (cut s j (+ i j))
The items from position i to the end minus the last j items

    s[i:-j]
    s[i ... -j]
    (cut s i (- -1 j))
i items beginning at the j'th position from the end

    s[-j:-j+i]
    s[-j,i]
    (cut s (- (len s) j) (+ (- (len s) j) i))

-----

2 points by vrk 6126 days ago | link

For reference, here's how you can do it in Perl 5:

The ith item of s:

  $s[i]
The ith item of s from the end:

  $s[-i]
The first x items of s:

  @s[0 .. x-1]
The last x items of s:

  @s[-x .. -1]
The items from position i to the end:

  @s[i .. $#s]
The items from position i to position j (exclusive):

  @s[i .. j-1]
i items beginning at position j:

  @s[j .. j+i]
The items from position i to the end minus the last j items:

  @s[i .. $#s-j]
  # Alternative:
  (@s[i .. $#s])[0 .. j-1]
i items beginning at the jth position from the end:

  @s[-j .. -j-i]
  # Alternative:
  (@s[-j .. -1])[0 .. i-1]
Legend:

  $s[i]  # A scalar at index i
  @s[<something complex>]  # An array slice (i.e. multiple values)
  $#s  # The last index of the array s
  a .. b  # In list context, a list of numbers or letters from a to b, inclusive (can be used outside array indexing)

-----

4 points by pg 6126 days ago | link

If you're comparing for length, at least use dot notation.

-----

6 points by steadicat 6126 days ago | link

I think the key point is that Ruby's power can be achieved with less syntax forms without compromises.

The fact that Python's way also happens to be shorter is not the main point, just an added plus.

-----

2 points by jules 6126 days ago | link

Are you aware that x..y and x...y notation is a Range literal in Ruby? I like Pythons syntax better but range notation isn't special syntax for slices.

obj[a,b,...] is sugar for a method call in Ruby (you can define a [] method for your own classes). So there's really only two syntactic forms here, and arguably no special syntax for slices.

-----

1 point by mdemare 6126 days ago | link

I'm counting each occurrence of i,j and x, each occurrence of 1, and each occurrence of len, + and (binary) -.

That yields the following scores: Python : 1 1 1 1 1 4 2 4 2 4 => 21 Ruby : 1 1 2 2 2 2 2 2 2 2 => 18 Arc : 1 3 2 3 1 4 2 4 4 8 => 32

15 is the best possible score. This is meant as succinctness benchmark for the index and slice/cut operations, which are extremely common.

-----

1 point by jc 6118 days ago | link

I think there's a reccuring mistake in the arc snippet for "The items from position i to the end minus the last j items."

I think it should be

  (cut s i -j)
... but I know I could be missing something

(thanks for the help, cadaver)

-----

1 point by cadaver 6118 days ago | link

Have a look at the little "help" next to the "about" box in your profile.

Also, I noticed that some people use a single ' to quote a function name on its own within a sentence (just like in Arc).

-----

5 points by jgrahamc 6126 days ago | link

I find the use of . ugly here. It might be nice for structure access, but cut.s.i.j looks ugly to me. Why not (cut s i j)?

-----

3 points by mdemare 6126 days ago | link

I wanted to make Arc's examples as short as possible, but you're right - I've changed it now.

-----

3 points by nex3 6126 days ago | link

Your "items from position 1 to the end minus the last 2 items" can actually be achieved in a nicer manner in Arc:

  (cut s 1 -2)
(Note that that's using the Anarki negative-end semantics, which PG has said are better; in arc1.tar, that would be (cut s 1 -3). See http://arclanguage.org/item?id=2225)

-----

1 point by mdemare 6126 days ago | link

Good point, I've changed it, but am still using arc1 as reference.

-----

2 points by mdemare 6126 days ago | link

Maybe there should be another version of cut that takes a length instead of an index as argument. Together with allowing negative second arguments, that should reduce the last example from:

    (cut s (- (len s) j) (+ (- (len s) j) i))
to

    (cutl s -j i)

-----

1 point by nex3 6126 days ago | link

It seems a little weird that the second parameter switches meaning from "end" to "length" if the first parameter is negative, but I suppose it's more useful than the alternative...

-----

3 points by mdemare 6126 days ago | link

No, it's another function. cutl instead of cut.

-----

1 point by nex3 6126 days ago | link

Gotta stop trying to read code at four in the morning...

-----

2 points by bOR_ 6126 days ago | link

A possibility (although not immediately intuitive) is a - modifier in front of a list that reverses it :

  (-s i)  "i'th item of s from the end"

  (cut -s 0 x)  "the last x items of s"

  (cut -s j x)  "The items from position i to the end minus the last j items"
The only trouble being that you get your answer in reverse ;).

-----