Skip to content
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

Allow leading '+' in number strings #5589

Merged

Conversation

Sija
Copy link
Contributor

@Sija Sija commented Jan 15, 2018

This PR allows + leading character in numeric strings passed to Big* class constructors, bringing coherence to the rest of the Number constructors and parity with Ruby:

Crystal:

require "big"

# WORKS
"+10".to_i  # => 10
"+10".to_u8 # => 10_u8
"+10".to_f  # => 10.0

# DOESN'T WORK
"+10".to_big_i # => Invalid BigInt: +10 (ArgumentError)
"+10".to_big_d # => Invalid BigDecimal: +10 (Unexpected '+' character) (InvalidBigDecimalException)
"+10".to_big_f # => 0_big_f

Ruby:

require "bigdecimal"
require "bigdecimal/util"

# WORKS
"+10".to_i # => 10
"+10".to_f # => 10.0

"+10".to_d # => 0.1e2
"+10".to_r # => (10/1)
"+10".to_c # => (10+0i)

@@ -13,6 +13,8 @@ struct BigFloat < Float
end

def initialize(str : String)
# Strip leading '+' char to smooth out cases with strings like "+123"
str = str.lchop('+')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be really simple to optimize this by simply adding 1 to the pointer if str.starts_with? '+'. I think this optimization is so easy it might be a good idea to do it now to avoid the string copy and extra garbage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, it's done in String#lchop.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sija What do you mean? lchop creates a new string. We should just ignore the first char if it's +, like what @RX14 says.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad indeed. str = str[1..-1] if str.starts_with?('+')?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be better to implement it directly in String#lchop instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not possible. All strings have 8 leading bytes: four bytes for the type_id, and four bytes for the string's size. So a substring must have this info too.

In any case, I consider this an optimization. We can merge this now and optimize it later.

Copy link
Contributor

@RX14 RX14 Jan 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's an optimization. However, we'll probably forget if this is merged as-is. This is a very simple optimization:

unsafe_str = str.to_unsafe
unsafe_str += 1 if str.starts_with?('+')

then use unsafe_str. If you don't want to implement it, that's fine, it's just simple enough that now is as good a time as any to do this.

Copy link
Contributor Author

@Sija Sija Jan 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to merge it as-is and leave this perf optimization to the most interested parties like yourself. Thank you.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I general I hate it that we need such unsafe code. We should maybe work with slices in most cases unless we can prove a big performance loss.

@asterite asterite merged commit 244da57 into crystal-lang:master Jan 16, 2018
@asterite asterite added this to the Next milestone Jan 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants