SugarCpp
SugarCpp copied to clipboard
to vs .. ... ..<
Would you consider freeing up the 'to' keyword by copying 'Swift'/ 'rusts' style syntax for ranges
... is an operator creating an inclusive range e.g. 0...9
yields [0,1,2,3,4,5,6,7,8,9]
..< is an operator yielding a range until the last value, e.g. 0..<n
yields [0,1,2,3,4,... n-1]
(Swift used to use ..n for ..n-1, however I think they changed it to make it clearer.)
These could slot into a loop iterator protocol, or into your extended for loop sugar.
I realise this is highly subjective. There is a very good case for using 'to' as a keyword since it can create readable statements, and of course maybe 'to' itself could be an overloadable operator eg x to y
desugar as to(x,y)
and then you could actually implement it as a range constructor. to(x,y).begin()=x to(x,y).end()=y etc. I also realise ..< is more fidly to type than "
I'm not familiar with the specific sources of inspiration you are drawing from.
I am also trying to replace the keyword to
to just an operator, especially the keyword downto
.
Ps: x
to y
can be compiled to to(x,y)
, if we free up the to
keyword.
There are 4 different situations for ranges:
-
[a..b]
(eg. 1,2,3,4...) -
[b..a]
(eg. 10,9,8..) -
[a,b..c]
(eg. 1,3,5,7..) -
[c,b..a]
(eg. 11,9,7,5..) We can see there are two problems here: - How to determine
a < b
ora > b
(one is up-to, the other is down-to). - How to specify the step. Another problem is
- Including or excluding endpoints.
There are lots of syntax been invented. For example, CoffeeScript transpiler solve the problem 1 in this way:
(function() {
_results = [];
for (var _i = a; a <= b ? _i <= b : _i >= b; a <= b ? _i++ : _i--){ _results.push(_i); }
return _results;
}).apply(this);
However, this code is not human readable, also increase the time cost. I want to generate human readable code, so I'm trying to find a syntax which let compiler know which kind of situation we want.
- F#
- start..stop: means "start up-to stop"
- start .. step .. stop: we can use this syntax to implement "down-to" some like [10 .. -1 .. 1]
- LiveScript
-
to
andtil
here doesn't provide any information about the direction, so [a to b by c] will still need a dynamic check to determine whether c > 0.
- CoffeeScript
- [a..b] need dynamic check to determine whether a < b
- Haskell
- Swift/Rust: You mentioned.
Your ..<
idea looks good, but how to distinguish to
and downto
, here is my rough idea:
// to
1 .. 5 == [1,2,3,4,5]
1 ..<= 5 == [1,2,3,4,5]
1 ..< 5 == [1,2,3,4]
1 <.. 5 == [2,3,4,5]
1 <..< 5 == [2,3,4]
// downto
5 .. 1 == []
5 ..>= 1 == [5,4,3,2,1]
5 ..> 1 == [5,4,3,2]
5 >.. 1 == [4,3,2,1]
// step
1 .. 2 .. 7 == [1,3,5,7]
7 .. -2 .. 1 == []
7 .. -2 ..>= 1 == [7,5,3,1]
If we use to
and downto
, then we have to type more letters but can decrease the possibility of typing mistakes.
Do you have any ideas about distinguish to
and downto
?
interesting.
I like your ideas of swapping < for > to mean 'down to; ..<= ..>= ..< ..>
I'd be happy to use that.
more brainstorming on this subject - Imagine if we had currying for operators. there's a problem, many operators in C++ have different use for prefix.. so this is probably a bad idea. but imagine making a sequence constructor..
seq(init, test, increment)
... creates an iterator starting at 'x=init()', continuing while 'test(x)', stepping on with x=increment(x)
seq(a, <b, ++) eg seq(5, <10, ++) gives 5,6,7,8,9
seq(b,>a,--) eg seq(10, >5 --) gives 10,9,8,7,6
However, I'd guess making something more specific like ..< ..> would slot better into the system you already have, and once you said '<' , you know you want ++, and vica versa > implies --.
I like the [1..<5]
- it's much clearer than CS [1...5]
for til
operation. Also the reversal of comparators for downto is very obvious.
As for downto and stepping, in the literal cases much could be deduced, as per your examples but modified:
5 .. 1 == [5,4,3,2,1]
5 .. -1 .. 1 == [5,4,3,2,1]
5 ..>= 1 == [5,4,3,2,1]
5 ..> 1 == [5,4,3,2]
7 .. -2 .. 1 == [7,5,3,1]
7 .. -2 ..>= 1 == [7,5,3,1]
7 .. -2 ..> 1 == [7,5,3]