Reflections on Completing the "Learn Ruby" Codeacademy Course

In an effort to throw another tool in my technical toolbox, I completed Codeacademy's "Learn Ruby" course. I was enticed to use Codeacademy's platform because of a Software Engineering Daily podcast featuring Codeacademy's Senior Curriculum Director Zoe Bachman. In said podcast, Bachman mentioned courses designed to cater to specific audience, which unfortunately for me, wasn't the case with the Ruby offerings. womp womp. Regardless, As a primarily JS/TS developer, I thought I'd document some of my musings about Ruby.

Javascript vs Ruby

I'm not sure if this is heresy or not, but in all honestly, JS and Ruby aren't wildly that different. To me, the most noticeable difference was the omission of braces, but once I mentally adjusted, the language felt oddly familiar. Both are high-level languages that are dynamically typed with a JIT compiler and garbage collection. They share a significant amount of keywords and operands, and they support multiple paradigms, such as OOP, procedural, etc.

From what I've read, Ruby has a commitment to english-like syntax. For example, you can syntactically inverse an if statement, which I'm presuming makes it feel more native:

<statement> if <condition>
if <condition> do <statement>

Or reduce the gobbledygook of an iterator:

5.times do <statement>

Functions, etc

The one area I was repeatedly tripped-up with was with functions. For one, Ruby has an implicit return value. I suppose this is to encourage functional programming and limit side-effects; thought don't quote me on that.

def greeting(name)
  return "Hello, #{name}!"
end

def same_greeting_different_syntax(name)
  "Hello, #{name}!"
end

And then there's the proc, lambda, block thing. Let's start with blocks. From what I gather, a block is a function that can be declared 2 different ways:

do |n|
 puts n
end

{ |n| puts n }

Either way, the parameters are defined between |pipes|. The general syntax I kept seeing was: an iterator is called and then followed by a block:

2.times do |i|
  puts i
end

[1,2,3].each { |v| puts v }

Now the lambda v proc thing gets a little more nuanced and I'm not entirely certain on how it came about. First we'll start with the signatures:

proc_test = Proc.new { puts "I am the proc method!" }
lambda_test = lambda { puts "I am the lambda method!"}

proc_test.call # => I am the proc method!
lambda_test.call # => I am the lambda method!

Ok, we see the block syntax we called out above and it returns an object with a call method to it. I'm guessing this is because in Ruby (as in JS) "everything is an object" or at least has a object wrapper.

The nuance occurs when returning. lambda return from its own context, while a proc returns out of the embracing method's context. So does that mean a proc has closure over it's calling method? That I'm not sure. Let's see the examples though:

def proc_demo_method
  proc_demo = Proc.new { return "Only I print!" }
  proc_demo.call
  "But what about me?" # Never reached
end

puts proc_demo_method # Only I print!

def lambda_demo_method
  lambda_demo = lambda { return "Will I print?" }
  lambda_demo.call
  "Sorry - it's me that's printed."
end

puts lambda_demo_method # Sorry - it's me that's printed.

For now, that's that. I might go back and update this when I'm a little more educated. But in the meantime, let me know what you think by emailing me at blake.netzeband@gmail.com