Programming 101

24 Sep 2013

I have a buddy who's gotten it into his head to start learning to program later in life. He's tired of his day job, tired of feeling unwanted, and he thinks a good way out is to become a computer programmer. I haven't had the heart to tell him otherwise.

The thing is, he's been asking really great questions. As an older guy (not old, just not 20), he's got his head on straight. He doesn't think he knows it all, but at the same time, he wants to dig in and really take the time to understand what is going on. It's made me realize all the concepts and ideas I take for granted having done this kind of thing for most of my life.

I thought I'd share some of the emails, cleaned up and presented as blog articles, so that others can get this good introduction to programming, driven by a noob, guided by a (supposed) expert.

Installing Ruby

Ruby is a great language to learn just starting out. You can start simple with one or two lines of code, which you can then grow into procedural, object-oriented, and functional code. It also has a really great REPL, which lets you type in Ruby commands and see their output right away.

Of course, that paragraph may have made little sense to you, but that's ok. Just realize that Ruby is a great language to learn. But first we have to install it.

Windows Users

If you're on Windows, your best course of action is to use the RubyInstaller. It will give you the complete Ruby environment. Download and install the latest Ruby 2.0.0 version.

Linux and Mac OS X Users

We're going to install a tool called RVM, the Ruby Version Manager. It's a bit more complicated than the RubyInstaller for Windows, but you're going to get the official environment that 99.9% of all Ruby and Rails developers work with.

I'm on a Mac. If you're on Linux, whenever I write about the "Terminal" app, you should think "shell" (though I think Ubuntu calls it the "Terminal" app now too).

The RVM web site has great documentation. If you wanted to follow their instructions, I won't feel slighted. To paraphrase:

  • In the Terminal, run this (the $ represents your prompt; don't include it):
    $ \curl -L https://get.rvm.io | bash -s stable
  • Once RVM is installed, Install the latest version of Ruby, preferably some version of Ruby >= 2.0.0, using RVM:
    $ rvm list known
    # MRI Rubies
    [ruby-]1.8.6[-p420]
    [ruby-]1.8.7[-p374]
    [ruby-]1.9.1[-p431]
    [ruby-]1.9.2[-p320]
    [ruby-]1.9.3[-p448]
    [ruby-]2.0.0-p195
    [ruby-]2.0.0[-p247]
    [ruby-]2.0.0-head
    ruby-head

    # GoRuby
    goruby

    # Topaz
    topaz

    # TheCodeShop - MRI experimental patches
    ...

Just type "q" to quit on that first page; you want one of the "MRI Rubies". Also, your list may be different than mine (I haven't updated RVM in a while).

  • Install Ruby:
    $ rvm install 2.0.0

Those brackets in the list indicate optional values. So you can type "rvm install ruby-2.0.0-p247", or you can just install "rvm install 2.0.0" and it will fill in "ruby-" and "-p247". Also, this step will take a while.

  • Make this Ruby your default. That way any time you open the Terminal, RVM will automatically start using Ruby 2.0 instead of the version that may come preinstalled on your version of OS X or Linux.
    $ rvm --default use 2.0.0

You can make sure this works at this point. After you type this, close the Terminal, reopen it, and type:

    $ rvm info

    ruby-2.0.0-p247:

      system:
        uname:       "Darwin hypatia.local 12.4.0 Darwin Kernel Version 12.4.0: Wed May  1 17:57:12 PDT 2013; root:xnu-2050.24.15~1/RELEASE_X86_64 x86_64"
        system:      "osx/10.8/x86_64"
        bash:        "/bin/bash => GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)"
        zsh:         "/bin/zsh => zsh 4.3.11 (i386-apple-darwin12.0)"

      rvm:
        version:      "rvm 1.21.3 (master) by Wayne E. Seguin , Michal Papis  [https://rvm.io/]"
        updated:      "1 month 8 days 4 hours 53 minutes 22 seconds ago"

      ruby:
        interpreter:  "ruby"
        version:      "2.0.0p247"
        date:         "2013-06-27"
        platform:     "x86_64-darwin12.3.0"
        patchlevel:   "2013-06-27 revision 41674"
        full_version: "ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.3.0]"

      homes:
        gem:          "/Users/sbowman/.rvm/gems/ruby-2.0.0-p247"
        ruby:         "/Users/sbowman/.rvm/rubies/ruby-2.0.0-p247"

      binaries:
        ruby:         "/Users/sbowman/.rvm/rubies/ruby-2.0.0-p247/bin/ruby"
        irb:          "/Users/sbowman/.rvm/rubies/ruby-2.0.0-p247/bin/irb"
        gem:          "/Users/sbowman/.rvm/rubies/ruby-2.0.0-p247/bin/gem"
        rake:         "/Users/sbowman/.rvm/gems/ruby-2.0.0-p247@global/bin/rake"

      environment:
        PATH:         "/Users/sbowman/.rvm/gems/ruby-2.0.0-p247/bin:/Users/sbowman/.rvm/gems/ruby-2.0.0-p247@global/bin:/Users/sbowman/.rvm/rubies/ruby-2.0.0-p247/bin:/Users/sbowman/.rvm/bin:/usr/local/share/python:/Users/sbowman/Projects/go/bin:/Users/sbowman/Library/Haskell/bin:/usr/local/share/npm/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin"
        GEM_HOME:     "/Users/sbowman/.rvm/gems/ruby-2.0.0-p247"
        GEM_PATH:     "/Users/sbowman/.rvm/gems/ruby-2.0.0-p247:/Users/sbowman/.rvm/gems/ruby-2.0.0-p247@global"
        MY_RUBY_HOME: "/Users/sbowman/.rvm/rubies/ruby-2.0.0-p247"
        IRBRC:        "/Users/sbowman/.rvm/rubies/ruby-2.0.0-p247/.irbrc"
        RUBYOPT:      ""
        gemset:       ""

Obviously your directory paths and operating system info will be different, but you should see that version set to some version of 2.0.0.

A Note on Gems

Ruby refers third-party libraries as gems. These gems are written by people just like you and shared online in a couple of places. You can download these gems using the gem tool that comes with Ruby. Gems allow you to do things like connect to databases, build web sites, and draw graphics on the screen.

RVM uses something it calls a "gemset" to organize these libraries you download into a group for a specific project. For example, if you're building a web site using Ruby on Rails, you create a gemset, install Rails--which is itself a collection of gems--and start building. But if you want to build a second Ruby application, you may want a compeletely different collection of libraries. Using RVM, you can create a second gemset, install the libraries for the new project in that gemset, and switch between the two gemsets as necessary.

You may think, "Why bother keeping the libraries separate? If I don't use a library, won't Ruby just ignore it?" Yes, it would. But a problem arises: the longer you work on projects, the more likely some libraries will release new versions that break your older code. You may want to use an older gem on project A, but a newer gem on project B. For example, I have projects that are written in Rails 3 that I'm not ready to update to the latest version of Rails 4. Because each project uses its own gemset, I don't have a problem working on my older Rails 3 applications, then jumping into a new application that uses Rails 4.

Back to our original programming...

  • Now, setup a "gemset" you can use to try out new things.
    $ rvm gemset create tutorials
  • Any time you start the Terminal, you'll be using Ruby 2.0, but you need to specify the gemset. Just type this shorthand (type this now):
    $ rvm use @tutorials

Now you should be ready to go with the latest version of Ruby and a pristine gemset space.

Don't forget the "gemset create" step! You should run that every time you open the Terminal. When you're ready to start writing apps, you can create new gemsets to keep the libraries straight and clean between them. In that situation, create a new gemset for the application: rvm gemset create flashcards; rvm use @flashcards.

  • The ruby command is used to run Ruby scripts (programs). But to run Ruby commands directly, don't run ruby; use the irb command instead (aka interactive ruby):
    $ irb
    2.0.0p247 :001 >

You can type Ruby commands right into the interactive interpreter, and see the immediate results:

    2.0.0p247 :001 > puts "Hello"
    Hello
    => nil
    2.0.0p247 :002 >

To get out of irb, type "exit".

    2.0.0p247 :001 > exit
    $

A Simple Problem

Let's try out this new installation of Ruby by solving a simple problem. This comes from one of the Ruby message boards. It's a little test they make you take before joining, to make sure (a) you're human and (b) you know at least a little bit about programming.

    # What does the following Ruby code print out?
    puts ((1100.to_s * 2).to_i/2)

The answer is 5500550.

Easy right? Ok, if you didn't see it right away, let's walk through it.

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

Start from the inside parentheses out, just like you'd do in math. You do remember your rules for solving equations in algebra? We call it operator precedence. If not, check out Safari Books. In the meantime, I'll walk you through it.

1. 1100.to_s * 2 -> "11001100"

1100.to_s takes the number 1100 and converts it to a string of characters, '1100'. In Ruby, multiplying a string makes copies of it, so '1100' * 2 becomes '11001100'. Strings are always written with either single quotes or double quotes (there's a difference, but it doesn't really matter for you right now).

2. "11001100".to_i -> 11001100

The to_i will convert the string back to a number, 11001100. As a human, you might write this as 11,001,100, but in most programming languages we leave out the commas. In fact, if you tried to put commas in, you'd get weird error messages from Ruby.

3. 11001100 / 2 -> 5500550

Simple, right? Divide 11001100 by two (the slash is division, the asterisk is multiplication).

Integers and Floats

Numbers are numbers, right? Well, for humans they are. For computers it's a different story. Computers don't see numbers the way you and I do, but because of that they can also perform really complex calculations much faster than we can. There are really gory details as to how this whole process works inside a computers *math processor unit*, but I won't go into it now.

For now, just accept that it's really, really easy for a computer to work with whole numbers like 1, 5, 7, and 9, and much more difficult to work with what are called floating point numbers, i.e. numbers with decimal fractions like 3.141592. In fact, because it's so much easier for a computer to deal with whole numbers, programmers will sometimes "cheat" and use whole numbers in place of floating point numbers, such as 3141592 instead of 3.141592, then just shift the decimal place around afterwards.

I should have qualified that. Computers work really well with small whole numbers. Again, it's a technical reason, but one you may run across in real life sometimes. Ever hear of someone referring to a computer as "32-bit", or how great it is the new iPhone is finally "64-bit"? In a simple sense that has to do with the size of the whole number the computer can deal with. The largest signed whole number a 64-bit computer can easily deal with is 9,223,372,036,854,775,807, while the smallest is -9,223,372,036,854,775,808. When I started, that range was -128 to 127, so you can start to see how computers have gotten more powerful.

What I'm getting at is there is a difference between a whole number, or integer, and a decimal fraction, or floating point number. Accept it for now, maybe understand it a little bit, but as your knowledge about computers grows, you'll better understand why this is.

That said, because 11001100 and 2 are both integers, you'll do what we call integer division, which means you'll get a whole number answer with the decimal remainder chopped off. But that doesn't really matter; since you're dividing an even number in half, the answer is a whole number already: 5500550.

If you did something like 3 / 4, you'd get back 0 because of integer division. If you wanted the decimal fraction, you need to tell Ruby you're expecting a decimal number by making one of the whole numbers a floating point number. 3 / 4.0 or 3.0 / 4 or 3.0 / 4.0. Then you'll get 0.75 as the answer.

Let's see all of this in action, in an irb session:

    $ irb
    2.0.0p247 :001 > (1100.to_s * 2).to_i / 2
     => 5500550
    2.0.0p247 :002 > 11001100 / 2
     => 5500550

Just for fun, here's that floating point division too:

    2.0.0p247 :003 > 3 / 4
     => 0
    2.0.0p247 :004 > 3.0 / 4
     => 0.75
    2.0.0p247 :005 > 3 / 4.0
     => 0.75
    2.0.0p247 :006 > 3.0 / 4.0
     => 0.75

If all that is working for you, congratulations! You've got Ruby installed properly, and you've taken your first steps to understanding how to program a computer. Dive into other Ruby tutorials to get your feet wet. I'll be back shortly with a follow-up tutorial. They'll keep coming as long as my friend keeps asking great questions.

©2013 Vineberry, LLC