So, DBC prep is well on (expect a bigger post about that some time soon of course), and this week, we got a challenge about refactoring a couple of classes and some calls to these classes about a Drawer and Silverware we’ld clean and put in it. And our goal here is to refactor and correct the errors we could find.
After talking with some boots from the cohort (DBC language, read “colleagues”), I found that people were getting stuck on the exact same part of this challenge, so I figured some may like having some explanation on what’s up here.
The code
I won’t bother you with the whole exercise, let’s just get sum the code up as :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Try and paste that if you want, the error is :
1 2 3 4 5 |
|
drawer.rb:23:in `
The problem lays in the “Main” (we’ll see about that later in the DBC cursus most likely), on like 23 of the drawer.rb file. so in our
1 2 3 4 |
|
undefined method `eat’ for nil:NilClass (NoMethodError)“`
So, there is no method called eat for the object nil, from the class NilClass. So far so good.
That is what java devs would call a “null pointer exception”.
It is an error where, basically, something is null and your code wants to work with it but it can’t. The “null” I am talking about is the “nil” object we got here, and the only methods it has are described –> here <–
Now, what is that nil and what is it doing on line 23? And why do we care if it has a #eat method?
Finding out what’s up
What do is the object that can be nil on line 23? Well, simple : fork.
No other option there, there’s only one object on that line, fork is nil.
So we go a bit up and check out how we defined it, something must have been wrong there.
Definition is on line 22, right above. Since it’s the only place where we set a value to fork, that must be where we set it to nil.
By deduction, on that line, the thing that is nil is our_drawer.remove_item(fork) then.
So, we examine every part of this:
- our_drawer does not put much of a problem. We used it above (not in the example but in the exercise we did), and it would raise an error if we were calling #remove_item from it anyway.
- #remove_item may not do exactly what we want. It uses #delete with fork as an argument. Now, if you check >here<, this method returns the item if it found and deleted it in the array… or it returns nil if it is not in the array we call the method from… So THAT is where we get that nil from, the only return is here, we get a nil from that method. Now, let’s check the next thing in the expression just in case.
- fork is passed as an argument. But then, is fork defined before that? The answer is : NO. That is definitely a problem!
Well, that was quite helpful, we now have identified 2 problems that happen in our case. I’ll use numbers for further use (… or just because i’m just tired of dots in my lists :p) :
- #remove_item returns nil if it did not find the stuff in the array, that’s where our nil comes from.
- we pass an argument that has never been created before to #remove_item (if you change the code to print item inside the method you’ll see that item is nil, the argument we gave the method was nil). So, there’s no way it can find it in an array unless we add the nil object at one point, specifically (but we did not.
Right, so now, we just need to solve that!
A solution
Nope, not giving you one right now haha. There is not one correct answer anyway, so as long as you correct 1 and 2.Send me a mail or a message on facebook, G+, anything, if you want and I’ll show you what I did, but I thought that could be more interesting for people to be able to correct it yourself, but with a clearer understanding of what’s happening.
Anyway, once you solve that, no more “NullPointerException”, no more “NoMethodError”, the code works. I know I went into a lot of details and that must be long to read, but I hope you can get a clearer view of what that error was and how it could be cleared with that.
Don’t hesitate to tell me if it stll is a bit confusing !
Cheers~