views:

220

answers:

5

I was looking through some Rails source code and came across

# File vendor/rails/activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 129
129:     def target!
130:       @target * ''
131:     end

What does the * '' do? Is that multiplication by an empty string...? And why would you do that.

+10  A: 

This is a bizarre syntax. These are equivalent:

>> [1, 2, 3] * 'joiner'
=> "1joiner2joiner3"

>> [1, 2, 3].join 'joiner'
=> "1joiner2joiner3"

so in this case it joins all the entries of @target into one string, with nothing between the entries.

Note: if you do something like [1, 2, 3] * 3 (using an int instead of a str), you'll get three concatenated copies of the array instead.

Peter
Huh?! There's nothing "bizarre" about infix operator syntax (unless you are a Lisp or Forth fanatic). Pretty much *every* programming language on the planet has a `*` infix operator.
Jörg W Mittag
@Jörg: It's not the infix part that's bizarre, it's the fact that it's multiplying an array by a string...?
Chris Burt-Brown
I agree that the semantics are confusing and indeed bizarre, but what both Peter and crudson are complaining about is not the semantics, it's the *syntax*, and I am little stumped by that.
Jörg W Mittag
+5  A: 

It does the same thing as:

["foo","bar","baz"].join

http://ruby-doc.org/core/classes/Array.html#M002210

Per Z.E.D.'s suggestion, you would use it if you want to confuse people and make your code more error prone.

klochner
I'd probably word that differently. It results in the same thing as an [].join, but using the join() method is more obvious and more commonly used. I've seen several recommendations that we don't use the '*' operator with arrays because so few people use it that it is confusing. Compare the output of [1,2] * ',' with [1,2] * 2 for an example of why it doesn't play nice with our brains.
Greg
Are you arguing that it doesn't do the same thing? The RDoc says "equivalent to". Readability is orthogonal to implementation.
klochner
+3  A: 

Really cryptic code indeed.

After checking the source code, I realized that @target is actually an Array instance, I know you can do stuff like this

[5] * 5 # => [5,5,5,5,5]

I don't know where Array#* is defined (maybe in ActiveSupport), but what I can tell you is that, this is the behaviour when it gets multiplied by a String

[1,2,3] * 'comma' # => "1comma2comma3"
[1,2,3] * '' # => '123'

So I can infer it is concatanating all the elements of the array without any separators.

Roman Gonzalez
+1  A: 

Two comments:

  1. Having a ! end a method name implies that it's a mutating operation, which this example doesn't seem to be.

  2. As others have stated it's indeed cryptic. I would go for @target.to_s or @target.join

Additionally, this type of ruby code makes me sad because ruby is easy to read and idiomatically beautiful, and syntax like this gives me Perl flashbacks.
You are the second person on this question to complain about the infix operator syntax. I don't quite get it. With the exception of Lisp and Forth, pretty much *every* programming language on the planet has a `*` infix operator. There's nothing "bizarre" or "sad" about infix operators.
Jörg W Mittag
Of course, but this example makes one have to think briefly to get the line of code. Creating an empty string to concatenate an array is a little obscure use of *. I have absolutely nothing against the operator.
+2  A: 

Array#* with a String argument is equivalent to Array#join.

Jörg W Mittag