Wednesday, January 20, 2010

Ruby Downcase Bang

I have some Ruby code that does the following:

type = Foo
limit = "num_allowed_#{type.downcase!}"

It's fairly straightforward code to tell me how many allowed widgets a given customer has, or frobbles ("limit" is the attribute that is the max allowed widgets or frobbles or whatever). There's some surprising behavior, though.

If the string I'm attempting to downcase is already entirely lowercase, then it becomes nil.

For example:
penitentes:src cpowell$ irb
>> type = "Foo"
=> "Foo"
>> quantity = "num_#{type.downcase!}"
=> "num_foo"
>>
?>
?> type = "foo"
=> "foo"
>> quantity = "num_#{type.downcase!}"
=> "num_"
>>

That's not what I expected. If you don't use the bang (just use "downcase"), then it works as expected. For example:
penitentes:src cpowell$ irb
>> type = "Foo"
=> "Foo"
>> quantity = "num_#{type.downcase}"
=> "num_foo"
>> type = "foo"
=> "foo"
>> quantity = "num_#{type.downcase}"
=> "num_foo"
>>

I'm not sure it's a bug, strictly, but it's certainly odd.


P.S. I've been coding a lot lately, so the posts are getting a bit technical. The pendulum will swing the other way at some point.


2 comments:

  1. Hello Catherine!

    This behavior is expected and documented in http://ruby-doc.org/core-1.8.7/classes/String.html#M000728.

    Essentially, #downcase! modifies the receiver, and returns nil to indicate changes or no. #downcase duplicates the string then downcases it, returning the duplicate instance.

    Hope that helps!

    ReplyDelete
  2. A bit of googling told me this behavior was as intended by the implementor (hence no bug report). That same googling also showed several people who'd had the same expectation I did (and were also surprised by the actual behavior). So I thought I'd write it up in case someone else runs into it.

    I don't agree with the implementation - I think it's unintuitive and doesn't provide any particular benefit - but I do recognize that it was the implementor's choice. I don't have to like it; I just have to understand it!

    ReplyDelete