You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Char::Reader#next_char raises when there are no more characters to read, so one must call #has_next? first, even though this check is already effectively the first thing #next_char calls. #previous_char is the same, whereas #current_char cannot distinguish between a null byte and the end of the string, and also needs #has_next? (#12279 is due to this). These frequent combined uses suggest that there should be a more ergonomic API that takes advantage of nilable types:
structChar::Readerdefcurrent_char? : Char?
has_next? ? current_char : nilend# note: returns `nil` instead of `'\0'` if `self` is at the last characterdefnext_char? : Char?
# not exception-free, but can be refactored to make it so@pos+@current_char_width<@string.bytesize ? next_char : nilenddefprevious_char? : Char?
# ditto
has_previous? ? previous_char : nilendend
Apart from ergonomics, #current_char? and #next_char? will never return the null terminator. IMO this makes code using them easier to reason about.
which is more readable, especially since the original used #next_char in an imperative manner where the return value was discarded and only its side effect was desired.
Going further, we could introduce one more method that combines #current_char and #next_char:
structChar::Readerdefshift? : Char?
# this `next_char` is also guaranteed not to raise
has_next? ? current_char.tap { next_char } : nilendend
This would allow a concise form of external iteration, albeit with a minor difference compared to #each:
reader =Char::Reader.new("abc")
reader.each do |char|
# `reader` is not advanced yet, so `char == reader.current_char`# (technically this is not documented, but is a reasonable assumption)end
reader =Char::Reader.new("abc")
while char = reader.shift?
# `reader` is advanced, so `reader.current_char?` may return `nil`end
The text was updated successfully, but these errors were encountered:
Char::Reader#next_char
raises when there are no more characters to read, so one must call#has_next?
first, even though this check is already effectively the first thing#next_char
calls.#previous_char
is the same, whereas#current_char
cannot distinguish between a null byte and the end of the string, and also needs#has_next?
(#12279 is due to this). These frequent combined uses suggest that there should be a more ergonomic API that takes advantage of nilable types:Apart from ergonomics,
#current_char?
and#next_char?
will never return the null terminator. IMO this makes code using them easier to reason about.As an example, this snippet:
crystal/src/path.cr
Lines 1222 to 1239 in f8fafc3
can be simplified to:
which is more readable, especially since the original used
#next_char
in an imperative manner where the return value was discarded and only its side effect was desired.Going further, we could introduce one more method that combines
#current_char
and#next_char
:This would allow a concise form of external iteration, albeit with a minor difference compared to
#each
:The text was updated successfully, but these errors were encountered: