Skip to main content
Rails for Beginners:

Symbols vs Strings

32

Episode 284 · February 14, 2019

Ever wondered what the difference between Symbols and Strings were? Why would we use one over the other when most languages only have strings?

ruby Basics


Transcripts

Symbols vs String

This episode we're gonna be talking about some Ruby basics, specifically the difference between strings and symbols in Ruby and why Rails tends to use symbols all over the place.

This is something that confused me a lot as a beginner and coming from Python or another language that where there's only strings, it's hard to understand why we had symbols and what they were useful for.

So that's why I want to explain in this episode. Let's open up the rails console and take a look at strings versus symbols really fast. So a string is anything where it's got characters inside of double quotes or single quotes. If you create this it's going to then go take those characters put them in memory somewhere and whenever you stop referencing them, it removes that when you're not needing it anymore.

  "asdf"

If you remove all references to that then it will get rid of it so if you do that inside of a method when the method ends it will remove those strings from memory because you don't need them anymore unless you save them in a variable outside of that method. So that's a string.

You can add strings together and you can say let's create a new string so it creates two new strings and then it creates a third string with everything together and it gets rid of the first two strings.

  "asdf" + "hello"
  => "asdfhello"

So that is going to be doing more memory manipulation but a symbol is different than this. a symbol like asdf will start with a colon and have no ending characters so it's not a colon on both sides just a colon on one side. A symbol is going to allocate memory with the SDF in memory but it's not going to get rid of it and that's the big difference. When you create a symbol it rarely ever will remove from memory.

  :asdf

The reason for that is for speed, so there's the benefit you get to doing that but you have to take advantage of it carefully otherwise you could end up with a whole bunch of stuff that you added to memory and it never gets you never gets garbage collected and that would be called a memory leak because eventually it will run out of memory.

Now, an easy way for us to tell if we're creating new objects in memory or referencing existing ones is to check the objects ID. So every object in Ruby has this object ID method.

  "asdf".object_id
  => 70251919440280

  "asdf".object_id
  => 70251919453360

If you call that on a string it's going to return a number to you but if you call it again on a new string it will give you a different number. We can do this a bunch of times and that number is going to change every time because it's allocating a new string in memory and then asking for the ID from it and then it gets rid of it and the next line creates a new string for asdf so we basically just done a couple of things by adding stuff and removing stuff from memory.

But if we do this with a symbol we'll have a single object ID no matter how many times we reference that symbol and so it's a lot faster because we're not allocating new stuff in memory at all and we're not removing things either.

  :asdf.object_id
  => 9756828

  :asdf.object_id
  => 9756828

We've gone and put it in the first time and we left it there and every future time we'll just go look that up. And that's all there is to it. Strings, for example can add things together like we did before but you cannot do that with symbols symbols are a single hard-coded esque string that is just saved in memory and that's it so there's no ability for you to create a new one like this by adding two symbols together. They're not like strings in that sense. They're more meant for hard-coded values.

  "asdf" + "hello"
  => "asdfhello"

  :asdf + :hello
  => NoMethodError (undefined method '+' for :asdf:Symbol)

Now you might be thinking well what's the point of all this?

If we open up a rails application we can take a look at the use of symbols here. Just for a quick reference all of these purple snippets of code here are symbols and all of the strings are in yellow.

So when we're doing this stuff we are typically using symbols in our controllers and our models and other things like that in our routes. We're using these symbols because they're faster.

That's the main reason for this because when we create this for action, we're calling a method with the same name as the symbol set project, the name for this method is never going to change.

  before_action :set_project, only: [:show, :edit, :update, :destroy]

If we use a symbol, we can reference it faster. We're going to be able to grab that very quickly and look up the method and call it because we know that that name is always going to be the same we don't need to use a string there we can use a symbol and it will be faster.

The reason it's faster is because rather than a string allocating and deallocating memory, every single time that this controller requested, we are going to reference it in memory one time with the symbol. Then we can look it up very very fast because we're not doing that extra work of allocating and deallocating memory.

You might think that that's very simple that maybe it's not going to give a big performance improvement but if we do this all over the place it's going to add speed it to our application in various different ways.

That's why you see all of these symbols and your Rails controllers and your routes and your models because those method names your database columns rarely change, so if we just use symbols instead that can make speed improvements tiny speed improvements everywhere.

If you have a fast application that's getting lots of requests like Github or Shopify, that is something where you need it to be very quick and so these speed improvements can make a big difference.

Now you might be asking why we have a string down here for our notice message every time you create successfully a new project.
The reason for that is because symbols cannot contain spaces in their normal syntax.

  notice: 'Project was successfully created'

What you can do however is take a string and put a colon before it which creates a symbol that allows spaces in it but it's actually a string inside. It's kind of strange and allows you to skirt around some of the symbol syntax. The problem is what this is doing is creating a new string in memory and then converting it to a symbol. So if we're already making a string we're just doing extra work to convert it to a symbol so you might as well just leave a bit of string. That is the reason why you see strings in those cases.

  notice: :'Project was successfully created'
  # unnecessary to convert it back to string

Now the last thing that I want to mention here is strings seem to have two formats. One is with the colon on the left side the other is a string like this or a symbol like this where there's a colon on the right side what's the difference the reason comes down to hashes.

So if you were using an early early early version of Ruby like Ruby 1.8.7, you would be able to create a hash like this just like the one up above.

  # For Ruby 1.8.7
  { :only => [:show, :edit, ...] }

If we were doing this in the same syntax you would have this and it would look like that. So one thing to remember is that the last set of arguments to any function can be a hash and you don't have to specify the curly braces. They're optional in that case.

  # For Ruby 1.8.7
  before_action :set_project, { :only => [:show, :edit, :update, :destroy] }

So what you're actually doing here is calling before action with curly braces around the ending options. So it's pretty handy that you can do that and just get rid of those curly braces because Ruby knows to take those and combine them all into one hash.

  # For Ruby 2.0+
  before_action :set_project, { only: [:show, :edit, :update, :destroy] }

That's pretty nifty syntax and like you probably already know, parentheses are optional so when you're calling before action here you're really calling something like this.

  before_action(:set_project, { only: [:show, :edit, :update, :destroy] })

Normally in the old versions of Ruby we'd have to use this in the long syntax with this fat arrow but that is adding three extra characters compared to the new syntax where we can move the colon to the right side and that's our separator. So this saves three characters every single item you have in your hash and if you have a whole bunch of these, your hash could be really really really long and saving those extra characters can be pretty handy.

So that's what they did in one of the early Ruby versions either Ruby 2.0 I believe was the one where it officially came out and maybe Ruby 1.9.3 added support for it. But basically they decided, "Hey, this syntax is a little long. Let's see if we can make some special syntax for symbols." Both of these are equally valid you can use either one of those just fine and it doesn't matter.

Now the last thing I want to mention here because I talked about. When we are using this before action up here we're actually calling the method that looks something like this.

  def before_action(method_name, options={})
  end

before action takes a method name and then it has a hash of options at the end. Ruby knows when you call this method up here to take this first argument and put an in method name and then the rest of this appears to be a hash, so it's going to take all of those other hash keys and values and stuff them into the options variable. That way, you don't have to define each one of these out individually later on.

You can save yourself a little bit of syntax here without having to put the curly braces in there. So that's the way that this is really working.

This is calling this method right here and Ruby's just smart enough to handle that extra optional syntax so that's really the difference between strings and symbols and Ruby and why you see symbols all over the place in Rails and why the syntax of those symbols can be a little bit different in different cases.

So that is the basics of symbols and strings. If you guys have more questions about basics of Ruby and stuff like that, we're going to be diving into more of that so let me know in the comments below and we'll talk about those things in the future.

Loading...

Subscribe to the newsletter

Join 24,647+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.