See also the discussion page.
For convenience (inspired by Python) and early-binding optimization opportunities, allow indexed access to string characters.
First, a special case left out of Edition 3:
var s : String = "hello" print(s) // prints 'o'
As proposed in bug fixes, this example shows indexed read access to string characters.
s is equivalent to
s.intrinsic::charAt(4), which allows for compile-time binding to the
intrinsic::charAt method of class
String. In such a trivial example, a good compiler could optimize the program to
print(’o’). Lacking a type annotation on the variable, or without a compilation step that analyzes types,
s would be evaluated using a run-time “get” of id
‘4’ from the object denoted by
String.prototype.slice to take an optional third parameter beyond
step. This parameter is converted using
ToInteger and the result must not be 0. Here is the revised
String.prototype.slice from ECMA-262 Edition 3 22.214.171.124:
1. Call ToString, giving it the this value as its argument. 2. Compute the number of characters in Result(1). 3. Call ToInteger(start). 4. If end is undefined, use Result(2); else use ToInteger(end). 5. If Result(3) is negative, use max(Result(2)+Result(3),0); else use min(Result(3),Result(2)). 6. If Result(4) is negative, use max(Result(2)+Result(4),0); else use min(Result(4),Result(2)). 7. If step is undefined, use 1; else use ToInteger(step). 8. If Result(7) is 0 throw a TypeError. 9. Let s be the empty string. 10. If Result(7) > 0 then 11. For (i = Result(5); i < Result(6); i += Result(7)) s += Result(1)[i]. 12. Else 13. For (i = Result(5); i > Result(6); i += Result(7)) s += Result(1)[i]. 14. Return s.
length property of both
slice methods is 3, not 2 as in ES3.
Third, building on indexed access to elements of strings and arrays, using
intrinsic::slice as a method on both
Array, support a Python-like syntax for slicing:
var s : String = "hello, world" print(s[3:5]) // prints 'lo' print(s[10:]) // prints 'ld' print(s[::-1]) // prints 'dlrow ,olleh' var a : Array = [0,1,2,3,4,5,6,7] var b = a[2:6]; print(b) // prints '2,3,4,5' var c = a[-6:-2]; print(c) // prints '2,3,4,5' var d = a[:2]; print(d) // prints '0,1' var e = a[::2]; print(e) // prints '0,2,4,6'
As in Python, a slice operator has the form
start is the starting index,
end is the fencepost – one greater than the last index to slice, and
step is the optional increment from
start if positive or decrement from
end if negative. If
start is not given,
0 is used. If
end is not given,
seq.length is used. If
end is negative,
seq.length is added to it. After this step, any value not in
[0, seq.length] is clamped to the nearest bound in that interval. If
step is undefined,
1 is used; else
ToInteger(step) must be non-zero. Any of
step may be omitted, and trailing colons may be omitted, but at least one colon is required to denote a “full” or “copying” slice:
Expression syntax based on the current grammar but using EBNF:
Brackets ::= "[" Expression? ":" Expression? (":" Expression?)? "]"
— Brendan Eich 2006/03/24 16:56
Did you mean:
Brackets ::= "[" Expression? ":" Expression? (":" Expression)? "]"
That is, that the
Expression after a second colon is not optional?
— Jeff Dyer 2006/11/21 12:45
No, I meant what I wrote . See Python’s behavior:
Python 2.5b3 (r25b3:51066, Aug 3 2006, 12:48:59) [GCC 4.0.1 (Apple Computer, Inc. build 5341)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> s = "hello" >>> s[::] 'hello'
— Brendan Eich 2006/11/21 16:39
No, I meant what I wrote .
I suspected you might have. Okay, let’s do what you said, and Python does.
— Jeff Dyer 2006/11/21 18:09