Confusing results from string multiplication

Hi,

I actually registered here to ask a different question, but after
checking the core docs for 1.8.7 I realized that the behavior has
apparently changed, but as part of the registration process I was asked
to enter the result of:

puts ((11.to_s * 2).to_i/2)

I don’t know Ruby very well, but this one seemed pretty
straight-forward, in that it was supposed to convert the number (object)
11 to a string, double it (‘1111’) then convert it back to an integer
and divide by two. Since these are integers the answer would be: 555.

But here’s where it gets strange. Since I’m new to Ruby I thought I’d
play with it a bit, and since I thought that whitespace wasn’t supposed
to matter, I did:

11.to_s * 2
=> “1111”

11.to_s *2
=> “1011”

11.to_s*2
=> “1111”

I thought, maybe this is a problem with irb, so I wrote a little
program:

#!/usr/bin/env ruby

puts (11.to_s * 2)
puts (11.to_s 2)
puts (11.to_s
2)

And when I run it, I see:

1111
1011
1111

Can anyone explain why the ‘11.to_s *2’ gave me 1011? Is this a 1.8.7
problem? The Ruby version on my Mac OS X Lion system is: ruby 1.8.7
(2010-01-10 patchlevel 249) [universal-darwin11.0].

Thanks,

Rob

On Thu, Dec 8, 2011 at 5:16 PM, Rob M. [email protected]
wrote:

straight-forward, in that it was supposed to convert the number (object)
=> “1011”
puts (11.to_s*2)

And when I run it, I see:

1111
1011
1111

Can anyone explain why the ‘11.to_s *2’ gave me 1011? Is this a 1.8.7
problem? The Ruby version on my Mac OS X Lion system is: ruby 1.8.7
(2010-01-10 patchlevel 249) [universal-darwin11.0].

Congratulations, you really hit a strange corner case in the syntax!

irb(main):003:0> 11.to_s *2
=> “1011”
irb(main):004:0> 11.to_s(*2)
=> “1011”
irb(main):005:0> 11.to_s(2)
=> “1011”

The variant with a single space before the star and no space after is
actually the splash operator as in:

irb(main):011:0> def f(*a) p a end
=> nil
irb(main):012:0> args = [1,2,3]
=> [1, 2, 3]
irb(main):013:0> f(args)
[[1, 2, 3]]
=> [[1, 2, 3]]
irb(main):014:0> f(*args)
[1, 2, 3]
=> [1, 2, 3]
irb(main):015:0> f(args, 77, 88)
[[1, 2, 3], 77, 88]
=> [[1, 2, 3], 77, 88]
irb(main):016:0> f(*args, 77, 88)
[1, 2, 3, 77, 88]
=> [1, 2, 3, 77, 88]

In your case:

irb(main):017:0> def f(a) p a end
=> nil
irb(main):018:0> f(2)
2
=> 2
irb(main):019:0> f(*2)
2
=> 2

And 11.to_s(2) ist just the conversion to binary:

irb(main):021:0> 11.to_s 2
=> “1011”
irb(main):022:0> 11.to_s 10
=> “11”
irb(main):023:0> 11.to_s 16
=> “b”

Kind regards

robert

The difference is down to the optional argument for Fixnum#to_s, the
base for the string representation of the number:

irb(main):026:0> 11.to_s(10)
=> “11”
irb(main):027:0> 11.to_s(16)
=> “b”
irb(main):028:0> 11.to_s(2)
=> “1011”

Note the last one. Your ‘11.to_s *2’ is being parsed as ‘11.to_s(2)’

In the other two cases, Ruby is parsing the input as: ‘(11.to_s) * 2’ to
duplicate the string.

“11” * 2
yields the same result, however you place the spaces.

Since I’m new to Ruby I thought I’d play with it a bit, and since I
thought that whitespace wasn’t supposed to matter

You have to be a little careful: whitespace matters in some cases to
help separate tokens. For instance, you need a space or bracket before
the argument to a method, else the method name cannot be separated from
its argument:

11.to_s10
NoMethodError: undefined method to_s10' for 11:Fixnum from (irb):38 from /usr/local/bin/irb:12:in
irb(main):039:0> 11.to_s 10
=> “11”

The confusion here is that ’ *2’ has a special meaning as a token when
used as the argument to a method, and this meaning does not arise in
other ‘multiplication’ settings. Robert has just posted a nice
explanation of that meaning.

On 08.12.2011 17:16, Rob M. wrote:

1111
1011
1111

but it works correctly for other numbers. try

puts (10.to_s *2)

:wink:

Well, it appears that “*2” becomes an argument to to_s, so your second
line of code is interpreted as

puts (11.to_s(*2))

and this strange looking argument to to_s is actually interpreted as a
splat operator and becomes converted to the Fixnum 2, so what you’re
actually requesting is a string containing the binary representation. 11
as decimal is 0xb in hex or, as you see it, 1011 in binary.

There is quite some magic to splat operator’s behavior in some cases.
For example, the splat cannot stand on its own like a normal expression.
So the following is invalid:

*[1,2]
*x
*2

but this is valid:

x=*[1,2]
y=*x
z=*2

Another magic – from my POV – is happening when assigning arrays to
multiple variables. Splat doesn’t seem to play a big role here, and
sometimes it is hard to judge how such an assignment will end,
considering differing data types on the RHS.

                   # actual              # expected

a=[1,2,3] # a=[1,2,3]
b=[1,2,3] # b=[1,2,3] # b=1
c,d=[1,2,3] # c=1, d=2 # c=[1,2,3], d=nil
e,f=
[1,2,3] # e=1, f=2
g,h=a # g=1, h=2 # g=[1,2,3], h=nil
a=2
i,j=a # i=1, j=2

Can anyone explain why the ‘11.to_s *2’ gave me 1011? Is this a 1.8.7
problem? The Ruby version on my Mac OS X Lion system is: ruby 1.8.7
(2010-01-10 patchlevel 249) [universal-darwin11.0].

Same here with 1.9.3-p0 Linux 64bit.

– Matthias

Oh, and just for clarification, I guess it’s the “splat” operator, not
the “splash” operator. :slight_smile:

Hi Robert,

Well, for someone who is new to Ruby, how would I, or anyone for that
matter, know that doing: '11.to_s 2’ converts the number 11 to binary
when ‘11.to_s * 2’ and 11.to_s
2 both do string multiplication as
expected. Especially since whitespace isn’t supposed to matter.

Sorry, seems very confusing to me…Not that I think something like this
happens all that often, but it would be a potentially hard bug to track
down. I could probably look at it all day and not know why the math
wasn’t working. For example:

((11.to_s *2).to_i/2)
=> 505

There’s no way that 11 in binary (1011) converted back to an integer
should ever give me 505 when divided by 2! And I realize that that’s not
actually what’s happening here, because what’s happening is that 11 is
being converted to binary and then to a string, which means that the
precedence is either wrong or confusing. Because the only way I get to
1011 is if the ‘*2’ happens BEFORE the .to_s. Which means that the
precedence seems to be (in this case, and potentially in this case only)
to do the *2 BEFORE converting 11 to a string, which is just wrong, in
my opinion.

And if x is really: “splash x”, i.e. split the list x into it’s
individual components, why does '11.to_s
2’ do the string multiplication
as expected? Shouldn’t it also convert 11 to binary?

Does this still happen on 1.9.3?

Rob

On Thu, Dec 8, 2011 at 17:17, Adam P. [email protected] wrote:

“1011”.to_i is actually equivalent to “1101”.to_i(10)

Typo! That should be 1011, of course. It doesn’t affect the point I was
making.

On Thu, Dec 8, 2011 at 17:09, Rob M. [email protected]
wrote:

((11.to_s *2).to_i/2)
=> 505

There’s no way that 11 in binary (1011) converted back to an integer
should ever give me 505 when divided by 2!

11.to_s(2) gives you “1011”. This is a string, and it doesn’t actually
know
that it’s a number for the base-2 representation of the decimal number
11.
“1011”.to_i is actually equivalent to “1101”.to_i(10), where 10 is the
base. So you convert 11_10 to 1011_2 and then take those digits of the
base-2 representation and treat them as decimal, giving you 1011. Divide
that by 2 and you get 505.

I think what you were actually talking about here refers to the notion
that
11.to_s(2) should know that it’s in base 2, and that to_i should then
give
back 11. For that you’d need 11.to_s(2).to_i(2), which is indeed 11, and
then /2 gives you 5.

Well, I do, at least to some degree, understand what’s happening. I
still find it a bit confusing that, in this case, ‘11.to_s 2’ means:
convert 11 to binary and then to a string, when: '11.to_s
2’ means:
convert 11 to a string and then multiply the string times two. To be
consistent, they should both do the same thing.

Especially since ‘11.to_s(2)’ seems “clearer” in that I’m saying the
base of the string needs to be ‘2’, whereas having ‘*2’ do the same
thing, but less “clearly”, seems odd to me.

Not that any of this really matters. It just threw me off. :slight_smile:

Rob

On Thu, Dec 8, 2011 at 9:09 AM, Rob M. [email protected]
wrote:

Hi Robert,

Well, for someone who is new to Ruby, how would I, or anyone for that
matter, know that doing: '11.to_s 2’ converts the number 11 to binary
when ‘11.to_s * 2’ and 11.to_s
2 both do string multiplication as
expected. Especially since whitespace isn’t supposed to matter.

FWIW, ruby will warn you about ambiguous syntax if you run it with
warnings
turned on.

This code:

puts 11.to_s *
2
puts 11.to_s
2
puts 11.to_s
2

Outputs:

$ ruby -w test_warnings.rb
test_warnings.rb:2: warning: `*’ interpreted as argument prefix
1111
1011
1111

pete

On Dec 8, 12:09pm, Rob M. [email protected] wrote:

I could probably look at it all day and not know why the math
wasn’t working.

Possibly, but I’d hope not. At some point you should think about
breaking the problem up into smaller bits and you’d see that it all
works as intended except for the number → string conversion, and then
you’d end up understanding the problem.

what’s happening is that 11 is
being converted to binary and then to a string, which means that the
precedence is either wrong or confusing. Because the only way I get to
1011 is if the ‘*2’ happens BEFORE the .to_s. Which means that the
precedence seems to be (in this case, and potentially in this case only)
to do the *2 BEFORE converting 11 to a string, which is just wrong, in
my opinion.

In your opinion, methods can’t have arguments, then. Of course the
‘*2’ happens before the .to_s, since to_s needs the 2 before it can do
anything. 11 is being converted to binary and then to a string because
that’s how to_s manages to give string representations in other bases.

Well at least I started a lively discussion :slight_smile:

And after some thought, I guess this all does make sense in that *obj
means: “splat-obj”, which means: split obj into its individual
components. As pointed out by Robert earlier, *2 (or splat-2) results in
a simple ‘2’. So the syntax:

11.to_s *2

Is really ‘11.to_s splat-2’, or: ‘11.to_s 2’ which does base conversion.
It all makes sense now. But, coming from other languages where that’s
not the behavior, it takes some getting used to.

And, Yossef, yes I agree that it probably wouldn’t take me all day to
figure it out, it’s actually pretty obvious with a little help from the
forum :-). And, no, my opinion is NOT that methods can’t have arguments,
it’s just that (unless I do what Pete suggested, i.e. run it with
warnings turned on) I would not have thought of this particular syntax
as ambiguous, especially coming from another language where ‘* 2’ and
‘*2’ both mean: multiply by 2.

And, by the way, I still find that, if ‘11.to_s 2’ does base conversion
first and then converts the number to a string, then '11.to_s
2’, to be
consistent, should do that as well.

Thanks,

Rob

On Thu, Dec 8, 2011 at 11:09 AM, Rob M. [email protected]
wrote:

Hi Robert,

Well, for someone who is new to Ruby, how would I, or anyone for that
matter, know that doing: '11.to_s 2’ converts the number 11 to binary
when ‘11.to_s * 2’ and 11.to_s
2 both do string multiplication as
expected. Especially since whitespace isn’t supposed to matter.

Wherever you heard whitespace doesn’t matter, forget it; it’s not true.

This same issue happens in some cases with unary operators too. Observe:

puts -1 # -1
puts 1-1 # 0
puts 1 -1 # 0
puts 1- 1 # 0
puts 1 - 1 # 0

x = 1
puts x -1 # 0
puts x- 1 # 0
puts x - 1 # 0

def y
2
end

puts y -1 # ArgumentError: wrong number of arguments (1 for 0)
puts y- 1 # 1
puts y - 1 # 1

i.e. whitespace is ignored in all cases except when a method name is
to the immediate left of a minus sign leaning directly against another
object; in those cases, the minus sign is interpreted as a unary
operator. (The same goes for unary plus, which I’m guessing is
provided for consistency’s sake.)

Oh, and by the way, I do know why ‘11.to_s*2’ works “correctly”, in the
sense that it multiplies the string by two rather than returning the
base 2 of the number as a string. It’s because of the way the
interpreter is parsing the line into tokens. But it’s still confusing
:slight_smile:

Rob

2011/12/8 Matthias W. [email protected]

:wink:

lol, evil evil evil!

If I was trying to figure out what was going on, using these numbers,
I’d
be so exasperated. Poor guy got stuck with 11 as his number, how
confusing

.<

On Thu, Dec 8, 2011 at 11:09 AM, Rob M. [email protected]
wrote:

Sorry, seems very confusing to me…Not that I think something like this
happens all that often, but it would be a potentially hard bug to track
down. I could probably look at it all day and not know why the math
wasn’t working. For example:

Oh, it is. Just, as Robert said, it’s “a strange corner case”.

Does this still happen on 1.9.3?

Yeah, it’s not a bug, it’s just that the particular numbers you were
using
really obfuscated the problem. If you’d had like 123456789.to_s *2, it
would have been a lot more obvious.

On Thu, Dec 8, 2011 at 11:32 AM, Rob M. [email protected]
wrote:

Well, I do, at least to some degree, understand what’s happening. I
still find it a bit confusing that, in this case, ‘11.to_s 2’ means:
convert 11 to binary and then to a string, when: '11.to_s
2’ means:
convert 11 to a string and then multiply the string times two. To be
consistent, they should both do the same thing.

It will actually tell you if you run with warnings (I never do, b/c I
use
the splat operator w/o parens relatively frequently)

$ ruby -w -e ‘puts 11.to_s 2’
-e:1: warning: `
’ interpreted as argument prefix
1011

Just a note that this might happen not only with multiplication vs
splat operator.

Division vs regex definition can give similar troubles. (Please note
that the parsing is always deterministic, and the interpreter will try
its best guess, using spacing as hints. In Perl, a code like the one
below could parse differently depending on the number of arguments the
function takes.)

irb(main):001:0> def foo; 5; end
irb(main):002:0> foo/2 #/
=> 2
irb(main):003:0> foo / 2 #/
=> 2
irb(main):004:0> foo /2 #/
ArgumentError: wrong number of arguments (1 for 0)
from (irb):2:in foo' from (irb):4 from C:/Ruby192/bin/irb:12:in

Or with bitwise AND vs the unary to_proc operator:

irb(main):015:0> foo & 6
=> 4
irb(main):016:0> foo &6
TypeError: wrong argument type Fixnum (expected Proc)
from (irb):16
from C:/Ruby192/bin/irb:12:in `’

Just code reasonably: when you want to use something as a binary
operator, space equally on its both sides; when you want unary
operator, only space to the left. (Or just use the damn parentheses.)

– Matma R.

I assume you want explanation what happened?

2012/7/6 Sonu J. [email protected]:

Checking for Python…Unable to build libv8: Python not found!

Have you even tried looking at the error log? It clearly says you need
Python to install.

– Matma R.

C:\blog>bundle install
Fetching source index for https://rubygems.org/
Using rake (0.9.2.2)
Using i18n (0.6.0)
Using multi_json (1.3.6)
Using activesupport (3.2.1)
Using builder (3.0.0)
Using activemodel (3.2.1)
Using erubis (2.7.0)
Using journey (1.0.4)
Using rack (1.4.1)
Using rack-cache (1.2)
Using rack-test (0.6.1)
Using hike (1.2.1)
Using tilt (1.3.3)
Using sprockets (2.1.3)
Using actionpack (3.2.1)
Using mime-types (1.19)
Using polyglot (0.3.3)
Using treetop (1.4.10)
Using mail (2.4.4)
Using actionmailer (3.2.1)
Using arel (3.0.2)
Using tzinfo (0.3.33)
Using activerecord (3.2.1)
Using activeresource (3.2.1)
Using bundler (1.0.22)
Using coffee-script-source (1.3.3)
Using execjs (1.4.0)
Using coffee-script (2.2.0)
Using rack-ssl (1.3.2)
Using json (1.7.3)
Using rdoc (3.12)
Using thor (0.14.6)
Using railties (3.2.1)
Using coffee-rails (3.2.2)
Using jquery-rails (2.0.2)
Installing libv8 (3.3.10.4) with native extensions
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native
extension.

    D:/RailsInstaller/Ruby1.9.3/bin/ruby.exe extconf.rb

*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers. Check the mkmf.log file for more
details. You may need configuration options.

Provided configuration options:
–with-opt-dir
–without-opt-dir
–with-opt-include
–without-opt-include=${opt-dir}/include
–with-opt-lib
–without-opt-lib=${opt-dir}/lib
–with-make-prog
–without-make-prog
–srcdir=.
–curdir
–ruby=D:/RailsInstaller/Ruby1.9.3/bin/ruby
Checking for Python…Unable to build libv8: Python not found!

Gem files will remain installed in
D:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/libv8-3.3.10.4 for
inspection.
Results logged to
D:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/libv8-3.3.10.4/ext/libv8/gem_make.out
An error occured while installing libv8 (3.3.10.4), and Bundler cannot
continue.
Make sure that gem install libv8 -v '3.3.10.4' succeeds before
bundling.

Eric C. wrote in post #1035785:

Wherever you heard whitespace doesn’t matter, forget it; it’s not true.

Absolutely right - whitespace is very significant in ruby. Here’s
another corker:

puts (-3).abs # 3
puts(-3).abs # NoMethodError: undefined method `abs’ for nil:NilClass

This is the price you pay for perl’s “poetry mode”, that is, being able
to call methods without parentheses around arguments.