12

I am learning Ruby. My background is C++/Java/C#. Overall, I like the language, but I am a little confused about why there are so many different ways to accomplish the same thing, each with their own slightly different semantics.

Take string creation, for example. I can use '', "", q%, Q%, or just % to create strings. Some forms support interpolation. Other forms allow me to specify the string delimiters.

Why are there five ways to create string literals? Why would I ever use non-interpolated strings? What advantage does the % syntax have over quoted literals?

I know there must be value in the redundency in Ruby, but my untrained eyes are not clearly seeing it. Please enlighten me.

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
Ryan Michela
  • 8,284
  • 5
  • 33
  • 47
  • And 2 different ways to `puts` those strings. And 4 different ways to define functions. And 3 different.... – Roman Aug 29 '18 at 21:20

9 Answers9

15

Why would I ever use non-interpolated strings?

When you don't want the interpolation, of course. For example, perhaps you're outputting some documentation about string interpolation:

'Use #{x} to interpolate the value of x.'
=> "Use #{x} to interpolate the value of x."

What advantage does the % syntax have over quoted literals?

It lets you write strings more naturally, without the quotes, or when you don't want to escape a lot of things, analogous to C#'s string-literal prefix @.

%{The % syntax make strings look more "natural".}
=> "The % syntax makes strings look more \"natural\"."

%{<basket size="50">}
=> "<basket size=\"50\">"

There are many other %-notations:

%w{apple banana #{1}cucumber}   # [w]hitespace-separated array, no interpolation
=> ["apple", "banana", "\#{1}cucumber"]

%W{apple banana #{1}cucumber}   # [W]hitespace-separated array with interpolation
=> ["apple", "banana", "1cucumber"]

# [r]egular expression (finds all unary primes)
%r{^1?$|^(11+?)\1+$}
=> /^1?$|^(11+?)\1+$/

(1..30).to_a.select{ |i| ("1" * i) !~ %r{^1?$|^(11+?)\1+$} }
=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

%x{ruby --version} # [s]hell command
=> "ruby 1.9.1p129 (2009-05-12 revision 23412) [x86_64-linux]\n"

There's also %s (for symbols) and some others.

Why are there five ways to create string literals?

This isn't terribly unusual. Consider C#, for example, which has several different ways to generate strings: new String(); ""; @""; StringBuilder.ToString(), et cetera.

John Feminella
  • 303,634
  • 46
  • 339
  • 357
  • 2
    "natural" is highly subjective. "terribly unusual" is not a motivation for creating a language feature. – skrat Feb 07 '12 at 16:46
  • 1
    "natural" is highly subjective, but "fewer and more easily typed characters to say precisely the same thing" isn't, and is a pretty good motivation for creating a language feature. – John Feminella Feb 07 '12 at 18:34
3

I'm not a Ruby expert, but had you ever heard the term "syntactic sugar" ? Basically some programing languages offer different syntax to accomplish the same task. Some people could find one way easier than others due to his previous programing/syntax experience.

Andres
  • 3,324
  • 6
  • 27
  • 32
  • Indeed. Apparently, Ruby is using aliases / synonyms at more occasions. For example, the number of elements in an array can be retrieved with `count`, `length`, or `size`. Different words for the same attribute of an array, but by this, Ruby enables you to pick the most appropriate word for your code: do you want the _number_ of items you're collecting, the _length_ of an array, or the current _size_ of the structure. Essentially, they're all the same, but picking the right word might make your code easier to read, which is a nice property of the language. – Jochem Schulenklopper Oct 10 '16 at 18:59
3

The original question is why there are so many slightly different ways of doing things in Ruby.

Sometimes the different things are sensible: quoting is a good case where different behaviour requires different syntax - non/interpolating, alternate quoting characters, etc. - and historical accidence causes synonyms like %x() vs ``, much as in Perl.

The synonym issue - [].size [].length [].count - feels like an attempt to be helpful in a world where the language is too random for IDEs to be able to help: monkey-patching and the weird combination of strict but dynamic typing together make runtime errors an inevitable and frustrating part of the coding, so folks try to reduce the issue by supplying synonyms. Unfortunately, they end up confusing programmers who're accustomed to different methods doing different things.

The 'so similar but not quite' issue, for example ...

 $ ruby -le 'e=[]; e << (*[:A, :B])'
 -e:1: syntax error, unexpected ')', expecting :: or '[' or '.'
 $ ruby -le 'e=[]; e << *[:A, :B]'
 -e:1: syntax error, unexpected *
 $ ruby -le 'e=[]; e.push(*[:A, :B])'
 $ 

... can only really be viewed as a flaw. Every language has them, but they're usually more arcane than this.

And then there's the plain arbitrary 'use fail instead of raise unless you're just rethrowing an exception' nonsense in the Rubocop coding standards.

There are some nice bits in Ruby, but really - I'd far rather be coding in something better-founded.

android.weasel
  • 3,343
  • 1
  • 30
  • 41
2

In most situations, you'll end up using normal string delimiters. The main difference between single and double quotes is that double quotes allow you to interpolate variables.

puts 'this is a string'
# => this is a string
puts "this is a string"
# => this is a string
v = "string"
puts 'this is a #{v}'
# => this is a #{v}
puts "this is a #{v}"
# => this is a string

%q and %Q are useful when you can't use quotes because they are part of the internal string. For example, you might end up writing

html = %Q{this is a <img src="#{img_path}" class="style" /> image tag}

In this case, you can't use double quotes as delimiters unless you want to escape internal attribute delimiters. Also, you can't use single quote because the img_path variable won't be interpolated.

John Feminella
  • 303,634
  • 46
  • 339
  • 357
Simone Carletti
  • 173,507
  • 49
  • 363
  • 364
1

A lot of ruby's syntax is derived from perl's, like using q to quote a few words into a string. That probably is the main reason for such a big variety.

abyx
  • 69,862
  • 18
  • 95
  • 117
1

One more reason is a minor performance boost for non-interpolated strings. Using '' vs "" means that Ruby doesn't have to consider what's inside the string at all. So you'll see people using single quotes for array keys or symbols because they're faster. For what it's worth I'll include a little benchmark.

require 'benchmark'

Benchmark.bmbm(10) do |x|  
  x.report("single-quote") do
    for z in 0..1000000
      zf = 'hello'
    end
  end  

  x.report("double-quote") do
    for z in 0..1000000
      zf = "hello"
    end
  end  

  x.report("symbol") do
    for z in 0..1000000
      zf = :hello
    end
  end   
end

yields:

Rehearsal ------------------------------------------------
single-quote   0.610000   0.000000   0.610000 (  0.620387)
double-quote   0.630000   0.000000   0.630000 (  0.627018)
symbol         0.270000   0.000000   0.270000 (  0.309873)
--------------------------------------- total: 1.580000sec
Chuck Vose
  • 4,560
  • 24
  • 31
0

You would use non-interpolated strings if your string contains a lot of special characters (like backslashes, #{} etc.) and you don't want to escape all of them.

You'd use different delimiters if your string contains a lot of quotes that you'd otherwise have to escape.

You'd use heredocs if your strings has a lot of lines which would make normal string syntax look unwieldy.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
0

Ruby borrows constructs and ideas from lots of languages. The two most apparent influences are Smalltalk and Perl.

Depending on your comfort with Smalltalk or Perl you may well choose different constructs to do the same thing.

Dafydd Rees
  • 6,941
  • 3
  • 39
  • 48
0

Along the lines of John's answer: In quick hacks, I often end up running a perl or sed one-liner with grep syntax from within my ruby script. Being able to use %[ ] type syntax means that I can simply copy-paste my regexp from the terminal

Yannick Wurm
  • 3,617
  • 6
  • 25
  • 28