www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Datatypes I miss

reply Fredrik Olsson <peylow treyst.se> writes:
Ranges and sets :).

This is me more or less having a fantasy. Ranges and sets are without 
competition the two data types I use the most. They make writing solid 
code so much easy, helps finding range errors while debugging and 
reduces code size in general.

Both fits quite nicely into existing functionality in D, as well as into 
the paradigm of making usable functionality part of the core language 
(as for complex numbers and strings). Ranges are semi there when slicing 
arrays, and sets can be emulates with associative arrays with somewhat 
awkward syntax.

Anyway, if my x-mas wish comes true then :);

RangeDeclaration:
	range [Identifier] [: RangeBaseType] [RangeBody]
RangeBaseType:
	IntegerType
RangeBody:
	RangeMember
RangeMember:
	AssignExpression .. AssignExpression

For example:
	range minute 0..59;  // Static range
	minute = 61;  // Exception if compiling with range checks

	range slice: uint; // Dynamic range;
	int[12] foo;
	slice = 2..foo.length-2;
	int[] bar = foo[slice];

Range properties would be
.min, .max, .length and naturally .sizeof

Constant ranges are written with the .. operator just as one writes 
slices now. One minor hitch here, as slicing for arrays has the upper 
bound not including and having the upper bound not including for proper 
ranges would be awkward. But then again I have more often tried using 
foo[$] to get the last element of an array and failed, then I have ever 
used foo[2..$] to get the last elements.

Naturally the operator in should be able to work with ranges so that one 
could do for example:
	if (mychar in 'a'..'z') { ... }
	while (somenumber in 1..42) { ... }

And then sets:

SetDeclaration:
	set [Identifier] SetBody
SetBaseType:
	IntegerType
SetBody:
	IntegerType
	EnumType
	RangeType
	{ SetMembers }
SetMembers
	SetMember [, SetMembers]
SetMember:
	AssignExpression
	RangeMember
	SetType		// To expand existing sets

For example:
	set alfa {'A'..'Z', 'a'..'z'};
	set alfanum { alfa, '0'-'9' };

	enum weekday { MON, TUE, WED, THU, FRI, SAT, SUN };
	set weekdays weekday;
	weekdays freedays = [TUE..THU, SAT];
	if (selectedday in freedays) { ... }

I mean how many of us have not written:
	if (tolower(ch) >= 'a' && tolower(ch) <= 'z' &&
	    ch >= '0' && ch <= '9') { ... }
And even longer when writing for non English. This is much nicer:
	if (toupper(ch) in ['A'..'Z', '0'..'9']) { ... }
And a compiler can optimize easy to just test bits.
Dec 07 2005
next sibling parent Tom <Tom_member pathlink.com> writes:
I don't know about set or about the syntax but the range idea is also something
I had wished for so long. It's very common to use integers just in a specified
range, it'd make code much more nicer. Also the string enum would be very nice
(or maybe something more general). I don't think all this could be implemented
from a day to another but who knows in some future :D

In article <dn6re3$ckq$1 digitaldaemon.com>, Fredrik Olsson says...
Ranges and sets :).

This is me more or less having a fantasy. Ranges and sets are without 
competition the two data types I use the most. They make writing solid 
code so much easy, helps finding range errors while debugging and 
reduces code size in general.

Both fits quite nicely into existing functionality in D, as well as into 
the paradigm of making usable functionality part of the core language 
(as for complex numbers and strings). Ranges are semi there when slicing 
arrays, and sets can be emulates with associative arrays with somewhat 
awkward syntax.

Anyway, if my x-mas wish comes true then :);

RangeDeclaration:
	range [Identifier] [: RangeBaseType] [RangeBody]
RangeBaseType:
	IntegerType
RangeBody:
	RangeMember
RangeMember:
	AssignExpression .. AssignExpression

For example:
	range minute 0..59;  // Static range
	minute = 61;  // Exception if compiling with range checks

	range slice: uint; // Dynamic range;
	int[12] foo;
	slice = 2..foo.length-2;
	int[] bar = foo[slice];

Range properties would be
.min, .max, .length and naturally .sizeof

Constant ranges are written with the .. operator just as one writes 
slices now. One minor hitch here, as slicing for arrays has the upper 
bound not including and having the upper bound not including for proper 
ranges would be awkward. But then again I have more often tried using 
foo[$] to get the last element of an array and failed, then I have ever 
used foo[2..$] to get the last elements.

Naturally the operator in should be able to work with ranges so that one 
could do for example:
	if (mychar in 'a'..'z') { ... }
	while (somenumber in 1..42) { ... }

And then sets:

SetDeclaration:
	set [Identifier] SetBody
SetBaseType:
	IntegerType
SetBody:
	IntegerType
	EnumType
	RangeType
	{ SetMembers }
SetMembers
	SetMember [, SetMembers]
SetMember:
	AssignExpression
	RangeMember
	SetType		// To expand existing sets

For example:
	set alfa {'A'..'Z', 'a'..'z'};
	set alfanum { alfa, '0'-'9' };

	enum weekday { MON, TUE, WED, THU, FRI, SAT, SUN };
	set weekdays weekday;
	weekdays freedays = [TUE..THU, SAT];
	if (selectedday in freedays) { ... }

I mean how many of us have not written:
	if (tolower(ch) >= 'a' && tolower(ch) <= 'z' &&
	    ch >= '0' && ch <= '9') { ... }
And even longer when writing for non English. This is much nicer:
	if (toupper(ch) in ['A'..'Z', '0'..'9']) { ... }
And a compiler can optimize easy to just test bits.
Tom
Dec 07 2005
prev sibling next sibling parent reply James Dunne <james.jdunne gmail.com> writes:
Fredrik Olsson wrote:
 Ranges and sets :).
 
 This is me more or less having a fantasy. Ranges and sets are without 
 competition the two data types I use the most. They make writing solid 
 code so much easy, helps finding range errors while debugging and 
 reduces code size in general.
 
 Both fits quite nicely into existing functionality in D, as well as into 
 the paradigm of making usable functionality part of the core language 
 (as for complex numbers and strings). Ranges are semi there when slicing 
 arrays, and sets can be emulates with associative arrays with somewhat 
 awkward syntax.
 
 Anyway, if my x-mas wish comes true then :);
 
 RangeDeclaration:
     range [Identifier] [: RangeBaseType] [RangeBody]
 RangeBaseType:
     IntegerType
 RangeBody:
     RangeMember
 RangeMember:
     AssignExpression .. AssignExpression
 
 For example:
     range minute 0..59;  // Static range
     minute = 61;  // Exception if compiling with range checks
 
     range slice: uint; // Dynamic range;
     int[12] foo;
     slice = 2..foo.length-2;
     int[] bar = foo[slice];
 
 Range properties would be
 .min, .max, .length and naturally .sizeof
 
 Constant ranges are written with the .. operator just as one writes 
 slices now. One minor hitch here, as slicing for arrays has the upper 
 bound not including and having the upper bound not including for proper 
 ranges would be awkward. But then again I have more often tried using 
 foo[$] to get the last element of an array and failed, then I have ever 
 used foo[2..$] to get the last elements.
 
 Naturally the operator in should be able to work with ranges so that one 
 could do for example:
     if (mychar in 'a'..'z') { ... }
     while (somenumber in 1..42) { ... }
 
Very nice. Well thought out.
 And then sets:
 
 SetDeclaration:
     set [Identifier] SetBody
 SetBaseType:
     IntegerType
 SetBody:
     IntegerType
     EnumType
     RangeType
     { SetMembers }
 SetMembers
     SetMember [, SetMembers]
 SetMember:
     AssignExpression
     RangeMember
     SetType        // To expand existing sets
 
 For example:
     set alfa {'A'..'Z', 'a'..'z'};
     set alfanum { alfa, '0'-'9' };
 
     enum weekday { MON, TUE, WED, THU, FRI, SAT, SUN };
     set weekdays weekday;
     weekdays freedays = [TUE..THU, SAT];
     if (selectedday in freedays) { ... }
 
 I mean how many of us have not written:
     if (tolower(ch) >= 'a' && tolower(ch) <= 'z' &&
         ch >= '0' && ch <= '9') { ... }
 And even longer when writing for non English. This is much nicer:
     if (toupper(ch) in ['A'..'Z', '0'..'9']) { ... }
 And a compiler can optimize easy to just test bits.
The only potential problem I can see in this is a conflict with static array literal syntax. Most notably your last line there: if (toupper(ch) in ['A'..'Z', '0'..'9']) { ... } You and I both know that you meant a set type for ['A'..'Z', '0'..'9'], but the compiler might think that ['A'..'Z', '0'..'9'] is a static array literal and will get confused on your use of ranges there. And then what would happen if your ['A'..'Z', '0'..'9'] looked like a real array literal with no ranges in it, but you meant it as a set? Silent bug. Something like ['I', 'V', 'X', 'C', 'L', 'M']? Is that a char[6] or a set? Hope that wasn't too obtuse. I do like your idea though!
Dec 07 2005
parent Fredrik Olsson <peylow treyst.se> writes:
James Dunne skrev:
 Fredrik Olsson wrote:
 Ranges and sets :).
<snip>
 The only potential problem I can see in this is a conflict with static 
 array literal syntax.  Most notably your last line there:
 
 if (toupper(ch) in ['A'..'Z', '0'..'9']) { ... }
 
 You and I both know that you meant a set type for ['A'..'Z', '0'..'9'], 
 but the compiler might think that ['A'..'Z', '0'..'9'] is a static array 
 literal and will get confused on your use of ranges there.  And then 
 what would happen if your ['A'..'Z', '0'..'9'] looked like a real array 
 literal with no ranges in it, but you meant it as a set?  Silent bug. 
 Something like ['I', 'V', 'X', 'C', 'L', 'M']?  Is that a char[6] or a set?
 
 Hope that wasn't too obtuse.  I do like your idea though!
Yes, it is a quite huge problem I guess as well. I remember reading in several places Walter stating that static arrays have been on for "v2.0", simply because of the problem of getting the type bottom up. I think the same problem applies here. And then using [] for both static arrays and static sets is a problem as well, as you say. Both for the programmer and definitely for the compiler. Unfortunately {} is already set aside for static structs, using () is not an option, and then we sort of ran out of parenthesis like character pairs :/. Perhaps <> can work. if (ch in <'a'..'z'>) { ... } Not too bad. But then again I think the syntax is the smallest obstacle :).
Dec 08 2005
prev sibling next sibling parent reply Don Clugston <dac nospam.com.au> writes:
Fredrik Olsson wrote:
 Ranges and sets :).
 For example:
     range minute 0..59;  // Static range
     minute = 61;  // Exception if compiling with range checks
 
     range slice: uint; // Dynamic range;
     int[12] foo;
     slice = 2..foo.length-2;
     int[] bar = foo[slice];
 
 Range properties would be
 .min, .max, .length and naturally .sizeof
I think there are TWO things going on here. (1) syntactic sugar for a built-in pair structure. struct range { int max; int min; }; This could be passed to opSlice. I don't see any need for it to be restricted to integral types; real numbers would make sense, too. Actually, this type would be almost identical to auto myrange = [1, 5]; except that the syntax is auto myrange = 1..5; (2) ability to apply a class invariant to a built-in type. This could be allowing a contracts to be applied to a typedef.
     range minute 0..59;  // Static range
     minute = 61;  // Exception if compiling with range checks
is the same as something like: typedef int invariant { assert(this>=0 && this<=59); } Minute; // this assertion is checked every time there's // an assignment to a Minute variable. Minute minute; minute = 61; But you could also have more complex invariants, such typedef int invariant{ assert(this&1==0); } OddInt; to create an integer which must be odd. Except for the redefinition of 'this', it seems to be a natural extension of class invariants.
Dec 08 2005
next sibling parent BCS <BCS_member pathlink.com> writes:
In article <dn8vjc$17fo$1 digitaldaemon.com>, Don Clugston says...

..

(2) ability to apply a class invariant to a built-in type. This could be 
allowing a contracts to be applied to a typedef.

     range minute 0..59;  // Static range
     minute = 61;  // Exception if compiling with range checks
is the same as something like: typedef int invariant { assert(this>=0 && this<=59); } Minute; // this assertion is checked every time there's // an assignment to a Minute variable. Minute minute; minute = 61; But you could also have more complex invariants, such typedef int invariant{ assert(this&1==0); } OddInt; to create an integer which must be odd. Except for the redefinition of 'this', it seems to be a natural extension of class invariants.
Sweet! This would be great!
Dec 08 2005
prev sibling parent reply Bruno Medeiros <daiphoenixNO SPAMlycos.com> writes:
Don Clugston wrote:
 Fredrik Olsson wrote:
 
 Ranges and sets :).
 For example:
     range minute 0..59;  // Static range
     minute = 61;  // Exception if compiling with range checks

     range slice: uint; // Dynamic range;
     int[12] foo;
     slice = 2..foo.length-2;
     int[] bar = foo[slice];

 Range properties would be
 .min, .max, .length and naturally .sizeof
I think there are TWO things going on here. (1) syntactic sugar for a built-in pair structure. struct range { int max; int min; }; This could be passed to opSlice. I don't see any need for it to be restricted to integral types; real numbers would make sense, too. Actually, this type would be almost identical to auto myrange = [1, 5]; except that the syntax is auto myrange = 1..5; (2) ability to apply a class invariant to a built-in type. This could be allowing a contracts to be applied to a typedef. > range minute 0..59; // Static range > minute = 61; // Exception if compiling with range checks is the same as something like: typedef int invariant { assert(this>=0 && this<=59); } Minute; // this assertion is checked every time there's // an assignment to a Minute variable. Minute minute; minute = 61; But you could also have more complex invariants, such typedef int invariant{ assert(this&1==0); } OddInt; to create an integer which must be odd. Except for the redefinition of 'this', it seems to be a natural extension of class invariants.
That invariant in the middle of the typedef declaration seems a bit out of place. What if typedefs had a body, where you could put many invariants, unittests (not sure about the usefulness of this one) and even methods! Like: enum weekday_enum { MON, TUE, WED, THU, FRI, SAT, SUN }; typedef weekday_enum weekday { invariant { assert(this >= MON && this <= SUN); } bool isWeekDay() { return (this >= MON && this <= FRI); } char[] toString() { ... // returns "Monday", "Tuesday", etc. } } ... weekday wday; wday = weekday.MON; writefln( wday.toString() ); -- Bruno Medeiros - CS/E student "Certain aspects of D are a pathway to many abilities some consider to be... unnatural."
Dec 09 2005
next sibling parent reply Bruno Medeiros <daiphoenixNO SPAMlycos.com> writes:
Bruno Medeiros wrote:
 
 That invariant in the middle of the typedef declaration seems a bit out 
 of place. What if typedefs had a body, where you could put many 
 invariants, unittests (not sure about the usefulness of this one) and 
 even methods!
 Like:
 
   enum weekday_enum { MON, TUE, WED, THU, FRI, SAT, SUN };
   typedef weekday_enum weekday
   {
     invariant { assert(this >= MON && this <= SUN); }
     bool isWeekDay() { return (this >= MON && this <= FRI); }
     char[] toString() { ... // returns "Monday", "Tuesday", etc. }
   }
 
And yes, the similarity to structs is something worth to note. Hum.. -- Bruno Medeiros - CS/E student "Certain aspects of D are a pathway to many abilities some consider to be... unnatural."
Dec 09 2005
parent "Lionello Lunesu" <lio remove.lunesu.com> writes:
 Bruno Medeiros wrote:
 And yes, the similarity to structs is something worth to note. Hum..
Right, it's like a struct that inherits from a basic type, isn't it? struct weekday : weekday_enum { //... } or the same could be achieved by an anonimous member, or perhaps like with templates: member with the same name. struct weekday { weekday_enum weekday; } which would make a weekday implicitely castable to a weekday_enum? L.
Dec 12 2005
prev sibling parent BCS <BCS_member pathlink.com> writes:
In article <dnc9qi$23js$1 digitaldaemon.com>, Bruno Medeiros says...

<SNIP>
That invariant in the middle of the typedef declaration seems a bit out 
of place. What if typedefs had a body, where you could put many 
invariants, unittests (not sure about the usefulness of this one) and 
even methods!
Like:

   enum weekday_enum { MON, TUE, WED, THU, FRI, SAT, SUN };
   typedef weekday_enum weekday
   {
     invariant { assert(this >= MON && this <= SUN); }
     bool isWeekDay() { return (this >= MON && this <= FRI); }
     char[] toString() { ... // returns "Monday", "Tuesday", etc. }
   }

   ...

   weekday wday;
   wday = weekday.MON;
   writefln( wday.toString() );


-- 
Bruno Medeiros - CS/E student
"Certain aspects of D are a pathway to many abilities some consider to 
be... unnatural."
I like the idea. It has my vote. For trivial types that need math ops it's lots better than structs.
Dec 09 2005
prev sibling next sibling parent reply David Medlock <noone nowhere.com> writes:
Fredrik Olsson wrote:

 Ranges and sets :).
 
 This is me more or less having a fantasy. Ranges and sets are without 
 competition the two data types I use the most. They make writing solid 
 code so much easy, helps finding range errors while debugging and 
 reduces code size in general.
 
 Both fits quite nicely into existing functionality in D, as well as into 
 the paradigm of making usable functionality part of the core language 
 (as for complex numbers and strings). Ranges are semi there when slicing 
 arrays, and sets can be emulates with associative arrays with somewhat 
 awkward syntax.
 
 Anyway, if my x-mas wish comes true then :);
 
 RangeDeclaration:
     range [Identifier] [: RangeBaseType] [RangeBody]
 RangeBaseType:
     IntegerType
 RangeBody:
     RangeMember
 RangeMember:
     AssignExpression .. AssignExpression
 
 For example:
     range minute 0..59;  // Static range
     minute = 61;  // Exception if compiling with range checks
 
     range slice: uint; // Dynamic range;
     int[12] foo;
     slice = 2..foo.length-2;
     int[] bar = foo[slice];
 
 Range properties would be
 .min, .max, .length and naturally .sizeof
 
 Constant ranges are written with the .. operator just as one writes 
 slices now. One minor hitch here, as slicing for arrays has the upper 
 bound not including and having the upper bound not including for proper 
 ranges would be awkward. But then again I have more often tried using 
 foo[$] to get the last element of an array and failed, then I have ever 
 used foo[2..$] to get the last elements.
 
 Naturally the operator in should be able to work with ranges so that one 
 could do for example:
     if (mychar in 'a'..'z') { ... }
     while (somenumber in 1..42) { ... }
 
 And then sets:
 
 SetDeclaration:
     set [Identifier] SetBody
 SetBaseType:
     IntegerType
 SetBody:
     IntegerType
     EnumType
     RangeType
     { SetMembers }
 SetMembers
     SetMember [, SetMembers]
 SetMember:
     AssignExpression
     RangeMember
     SetType        // To expand existing sets
 
 For example:
     set alfa {'A'..'Z', 'a'..'z'};
     set alfanum { alfa, '0'-'9' };
 
     enum weekday { MON, TUE, WED, THU, FRI, SAT, SUN };
     set weekdays weekday;
     weekdays freedays = [TUE..THU, SAT];
     if (selectedday in freedays) { ... }
 
 I mean how many of us have not written:
     if (tolower(ch) >= 'a' && tolower(ch) <= 'z' &&
         ch >= '0' && ch <= '9') { ... }
 And even longer when writing for non English. This is much nicer:
     if (toupper(ch) in ['A'..'Z', '0'..'9']) { ... }
 And a compiler can optimize easy to just test bits.
Do you mean you miss them from Pascal? Your examples match Pascal pretty closely: type Weekday = ( MON, TUE, WED, THU, FRI, SAT, SUN ); WeekdaySet = Set of Weekday; Charset = Set of Char; DayOfWeek : 1..7 ; var weekdays : WeekdaySet; characters : Charset; This is no slight on you, but its amusing to see programmers wish for features available on a language developed in 1970.. hee hee. (A Pascal fan) -DavidM
Dec 09 2005
parent reply Fredrik Olsson <peylow treyst.se> writes:
David Medlock skrev:
 Fredrik Olsson wrote:
 
 Ranges and sets :).
<snip>
 This is no slight on you, but its amusing to see programmers wish for 
 features available on a language developed in 1970.. hee hee.
 
 (A Pascal fan)
 -DavidM
 
No coincident at all :). I am a Pascal fan as well, and Lisp fan, and Ruby fan and sql fan, and etc. I am simply choose what I feel is the best tool for the task at hand. For the general case Pascal tended to be it, before I found D. So naturally I want D to fill the few gaps I miss //Fredrik
Dec 09 2005
parent reply James Dunne <james.jdunne gmail.com> writes:
Fredrik Olsson wrote:
 David Medlock skrev:
 
 Fredrik Olsson wrote:

 Ranges and sets :).
<snip>
 This is no slight on you, but its amusing to see programmers wish for 
 features available on a language developed in 1970.. hee hee.

 (A Pascal fan)
 -DavidM
No coincident at all :). I am a Pascal fan as well, and Lisp fan, and Ruby fan and sql fan, and etc. I am simply choose what I feel is the best tool for the task at hand. For the general case Pascal tended to be it, before I found D. So naturally I want D to fill the few gaps I miss //Fredrik
You actually /LIKE/ SQL? http://orlyowl.com/omg.jpg
Dec 09 2005
parent reply David Medlock <noone nowhere.com> writes:
James Dunne wrote:
 Fredrik Olsson wrote:
 
 David Medlock skrev:

 Fredrik Olsson wrote:

 Ranges and sets :).
<snip>
 This is no slight on you, but its amusing to see programmers wish for 
 features available on a language developed in 1970.. hee hee.

 (A Pascal fan)
 -DavidM
No coincident at all :). I am a Pascal fan as well, and Lisp fan, and Ruby fan and sql fan, and etc. I am simply choose what I feel is the best tool for the task at hand. For the general case Pascal tended to be it, before I found D. So naturally I want D to fill the few gaps I //Fredrik
You actually /LIKE/ SQL? http://orlyowl.com/omg.jpg
SQL is reasonably laid out, and can be readily optimized since it is a declarative language, but its predecessor I like quite a lot more: http://en.wikipedia.org/wiki/IBM_BS12 -DavidM
Dec 09 2005
parent Fredrik Olsson <peylow treyst.se> writes:
David Medlock skrev:
 James Dunne wrote:
 Fredrik Olsson wrote:

 David Medlock skrev:

 Fredrik Olsson wrote:

 Ranges and sets :).
<snip>

 You actually /LIKE/ SQL?

 http://orlyowl.com/omg.jpg
SQL is reasonably laid out, and can be readily optimized since it is a declarative language, but its predecessor I like quite a lot more: http://en.wikipedia.org/wiki/IBM_BS12
SQL appeals to me because of it's small set of functionally that allows for so much to be done. I can not help it, but sometimes I chuckle for minutes after completing a particularly ingenious query :). Combine with pl/SQL or PostgreSQL's pl/pgSQL and you pretty much have what you need. My company's current project is pretty much an server written in "PostgreSQL" with a dummy web GUI in PHP. // Fredrik
Dec 14 2005
prev sibling parent Glen Perkins <Glen_member pathlink.com> writes:
In article <dn6re3$ckq$1 digitaldaemon.com>, Fredrik Olsson says...
Ranges and sets :).

This is me more or less having a fantasy. Ranges and sets are without 
competition the two data types I use the most...
I find ranges and sets and tuples and other such Lispy datatypes extremely useful, too. Many popular recent languages include them and I'd like to see them in D to the extent possible.
For example:
	range minute 0..59;  // Static range
	minute = 61;  // Exception if compiling with range checks

	range slice: uint; // Dynamic range;
	int[12] foo;
	slice = 2..foo.length-2;
	int[] bar = foo[slice];
Naturally the operator in should be able to work with ranges so that one 
could do for example:
	if (mychar in 'a'..'z') { ... }
	while (somenumber in 1..42) { ... }
And let's not forget: for (int i: 0..9) { ... } I think that's a lot nicer than: for (int i=0; i<9; i++) { ... } and the compiler could easily generate the same code for both.
And then sets:
For example:
	set alfa {'A'..'Z', 'a'..'z'};
	set alfanum { alfa, '0'-'9' };

	enum weekday { MON, TUE, WED, THU, FRI, SAT, SUN };
	set weekdays weekday;
	weekdays freedays = [TUE..THU, SAT];
	if (selectedday in freedays) { ... }

I mean how many of us have not written:
	if (tolower(ch) >= 'a' && tolower(ch) <= 'z' &&
	    ch >= '0' && ch <= '9') { ... }
And even longer when writing for non English. This is much nicer:
	if (toupper(ch) in ['A'..'Z', '0'..'9']) { ... }
And a compiler can optimize easy to just test bits.
and again, something like: for ( Day day : [MON..THU, SAT] ) { ... } Python ran into some trouble with the concept of ranges because it was calculating all of the members first before using any of them. It then added the "xrange" feature, which is related to "generators" or "continuations". Each element in an xrange is calculated on a just-in-time basis rather than all up front. You can then use infinite sets (such as all prime numbers) the same way you use small finite sets. You could then have something roughly like: int generator primes = primeGenerator(); for (int i : primes) { ... } primeGenerator would be a "generator" function that acted like a set of int's but would stay active on the stack between calls generating successive values (not "returning" values and leaving the stack between calls like a regular function, but staying loaded and "yielding" the next value each time it was called). After writing the generator function "primeGenerator()", the programmer could then simply think of "primes" as the set of all prime numbers and use it like any other set.
Dec 10 2005