Bubblesort! using proc question

Hi!

So I’m currently working on the Bubble_sort! method which uses a proc but I’m having some difficulty understanding how it works. The test for this section is as follows:

it "will use a block if given" do
  sorted = array.bubble_sort! do |num1, num2|
    # order numbers based on descending sort of their squares
    num2**2 <=> num1**2
  end

  expect(sorted).to eq([5, 4, 3, 2, 1])
end

So I thought that I’d write bubble_sort!(&prc), which uses prc.call to use the proc to check num2^2 <=> num1^2, where num1 and num2 are adjacent elements in the array.
However this didn’t work, upon checking the solution I see all I was missing was

`prc ||= Proc.new {|x,y| x<=>y}`

But I don’t understand what this is doing/why it’s necessary. If the block is being defined inside the method then we’re not really giving bubble_sort! a proc are we? And what is the point of giving bubble_sort! a block in the test if we’re just going to redefine prc in the first line of our method?

Thanks!
-Willis

2 Likes

Yeah, I recall having the same reaction to that exercise. (I haven’t gone back and looked at the newly-revised curriculum, but I found the whole “Blocs & Procs” section really sketchy…confusing explanations and no practice exercises. I ended up studying as much as I could on the topic from other sources and then just moving on.)

1 Like

Hey Willis,

In Ruby, we can use the ||= operator to assign a variable only if it is falsey. To be clear, this is just shorthand. Writing prc ||= Proc.new ... is the same as writing prc || prc = Proc.new ...

If prc is a falsey variable, Ruby will evaluate what’s on the right side of the || operator, meaning the variable will be reassigned. If prc is truthy, Ruby will only need to evaluate the left side of the expression, meaning the variable is never reassigned.

a = "hello"

a || a = "goodbye"

# => "hello"

In the above example, a already has a truthy value, so it was never reassigned. The OR operator only needs one truthy value in order to return true, so it stops evaluating once it hits the first truthy value.

In the following example, b is assigned to nil, a falsey value, and is thus assigned to a new value, goodbye.

b = nil
b || b = "goobye"

# => "goodbye"

For more info on this operator, check out this helpful Stack Overflow link. I also encourage you to mess around with it in whichever repl you are using.

Now, onto our bubble_sort! method. In this case, we use this operator to conditionally assign our prc variable. So, if we call:

array.bubble_sort!

the prc variable will be passed in as nil, as we didn’t pass the method a block. This means it will be reassigned to our Proc.new call.

However, if we call:

array.bubble_sort! { | num1, num2 | num2 <=> num1 }

the prc variable will already have a truthy value since we pass in a block to the method.

So, the main takeaway here is that we want our method to sort objects in plain-old ascending order if the method’s caller does not specify otherwise. If the method’s caller does specify a block (like in the example you gave), that block will be used instead of the one inside of our method.

Hope this helps, and please let me know if you have any further questions!

Best,
-David

4 Likes

Haha yeaa definitely a bit of a jump in material from the previous exercises to the bubblesort/Class/proc ones lol

1 Like

Wow, that actually clears things up a lot. I didn’t really consider we needed a default proc in case the user didn’t input one, and also guess I didn’t really understand how ||= works. Thanks!