New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] Change inclusive/exclusive range operator #13675
Comments
What's the use case/reasoning? |
@Blacksmoke16 While it is "too late" to change it in Crystal, and I do not agree with changing it now - even for 2.x - I can explain my own frustrations with it:
Other languages have made the difference very distinct: Essentially: I couldn't tell you how often (every few months?) but some issue arises with this (prod bug or otherwise) and it wastes our time a bit. Crystal is the only language I make this mistake in. |
@Silentdoer I took the liberty of editing your issue to make it more descriptive, hope you don't mind! |
Ruby is the same (that's where Crystal inherited it from). |
It could be an option to consider |
The following is a patch that seems to work for those interested in carrying it forward / using it in their own code; From 855dfd29980252549401c4696959355193265248 Mon Sep 17 00:00:00 2001
From: Zac Nowicki <zachnowicki@gmail.com>
Date: Tue, 18 Jul 2023 14:48:49 -0400
Subject: [PATCH] Add ..< for exclusive ranges and ..= for inclusive
---
src/compiler/crystal/syntax/lexer.cr | 4 ++++
src/compiler/crystal/syntax/parser.cr | 17 +++++++++++++----
src/compiler/crystal/syntax/token.cr | 2 ++
3 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/src/compiler/crystal/syntax/lexer.cr b/src/compiler/crystal/syntax/lexer.cr
index 33f991c5f..d82c65c60 100644
--- a/src/compiler/crystal/syntax/lexer.cr
+++ b/src/compiler/crystal/syntax/lexer.cr
@@ -414,6 +414,10 @@ module Crystal
case next_char
when '.'
next_char :OP_PERIOD_PERIOD_PERIOD
+ when '<'
+ next_char :OP_PERIOD_PERIOD_LT
+ when '='
+ next_char :OP_PERIOD_PERIOD_EQ
else
@token.type = :OP_PERIOD_PERIOD
end
diff --git a/src/compiler/crystal/syntax/parser.cr b/src/compiler/crystal/syntax/parser.cr
index 016d3d7e3..93b1ac4bb 100644
--- a/src/compiler/crystal/syntax/parser.cr
+++ b/src/compiler/crystal/syntax/parser.cr
@@ -511,7 +511,11 @@ module Crystal
def parse_range
location = @token.location
- if @token.type.op_period_period? || @token.type.op_period_period_period?
+ case @token.type
+ when .op_period_period?,
+ .op_period_period_period?,
+ .op_period_period_lt?,
+ .op_period_period_eq?
exp = Nop.new
else
exp = parse_or
@@ -519,9 +523,11 @@ module Crystal
while true
case @token.type
- when .op_period_period?
+ when .op_period_period?,
+ .op_period_period_eq?
exp = new_range(exp, location, false)
- when .op_period_period_period?
+ when .op_period_period_period?,
+ .op_period_period_lt?
exp = new_range(exp, location, true)
else
return exp
@@ -4674,7 +4680,10 @@ module Crystal
if current_char.ascii_whitespace?
return nil
end
- when .op_period_period?, .op_period_period_period?
+ when .op_period_period?,
+ .op_period_period_period?,
+ .op_period_period_lt?,
+ .op_period_period_eq?
return nil unless allow_beginless_range
else
return nil
diff --git a/src/compiler/crystal/syntax/token.cr b/src/compiler/crystal/syntax/token.cr
index 125ec14ee..5ba4a29b5 100644
--- a/src/compiler/crystal/syntax/token.cr
+++ b/src/compiler/crystal/syntax/token.cr
@@ -158,6 +158,8 @@ module Crystal
OP_PERIOD # .
OP_PERIOD_PERIOD # ..
OP_PERIOD_PERIOD_PERIOD # ...
+ OP_PERIOD_PERIOD_LT # ..<
+ OP_PERIOD_PERIOD_EQ # ..=
OP_SLASH # /
OP_SLASH_SLASH # //
OP_SLASH_SLASH_EQ # //=
--
2.41.0 a = [1, 2, 3]
# starting index
b = a[0..<2]
c = a[0..=2]
p(b)
p(c)
# begin-less
b = a[..<2]
c = a[..=2]
p(b)
p(c)
|
I can't remember who, but someone told me that between |
IMO It looks like a highly subjective matter, neither option is objectively better than the other. |
Yes, the ruby usage of I propose add new operator ..= ..<, as described in #13675 (comment), it make sense, but never change/drop old behavior. |
One nice "feature" of the three-dot operator is that code like |
I think this change should be (re)considered, as IMO it's clearer which is which from a cursory glance, especially for those new to the language. I can create a PR with @z64's patch if it would be accepted. |
I wouldn't oppose eventually to have something like straight-shoota said, but there're two issues to consider:
At this point I'm leaning towards adopting 2, but for 2.0. |
I never misunderstood Yes, we just inherited from ruby, there is no more thinking when design Crystal, but, that not so bad anyway, is Ruby is discussing replace it to use new syntax too? Maybe, we need add some document,for users come other land, how to remember, sure, for me, it not necessary, because i familiar with it, but for the new guys, you can try remember like this: for Clear enough? |
I've been using Crystal since 2017 - I fully understand the difference, but for me it is just too visually subtle to not miss in reviews, with mistakes made both by myself and peers of varying level of Crystal experience. Sometimes it is just a typo, other times its a misunderstanding. Then I see some people do In other languages that use different syntax (like (on top of the fact that |
Yes, this is the point, the opposite of other languages, so we should consider add new syntax which compatible to other languages, but, leave old behavior works forever. |
I'm surprised by this statement. In which languages does |
Nim has the syntax |
This is what I mean; the expression of ExamplesCrystal:
The rest:
Next ones I don't think they have a range/slice operator, but the equivalent functions:
Its "fine" if you exclusively work in Crystal, but after swapping between other langs for extended periods of time, I have to be careful that I remember the difference in Crystal's semantics / that I need to use the other |
@z64 That just seems like.. you could ban all usages of |
@z64 Python and Odin are not actually a I found this comparison across multiple languages: http://rigaux.org/language-study/syntax-across-languages/VrsDatTps.html#VrsDatTpsRng And I really think that makes the most sense for I think Rust and Zig made a very bad choice with I don't know what the reasons are for their syntax decisions. Maybe they have good reasons. But I can't really see any right now. IMO the opposite mapping would've been more intutive and congruent with previous works. Interestingly, Zig has these two range syntaxes but they are used in completely different contexts: Anyway, I'm not saying that the semantics Crystal inherited from Ruby ( Footnotes
|
Because i knew the reverse usage of |
should use .. and ..= (see #13675 (comment) below)
The text was updated successfully, but these errors were encountered: