 Welcome to the dark side of Ruby. And since it's just before lunch, it's my job to build up your appetite. Well, I've flown in from India, and my company's name is Joe Software. We've been doing this for the past seven years, and it's been fun. But after seven years, you realize that like in every marriage, the going is good in the start. Koichi-san, it's about for that. But after a few years, you start to understand that there is another side to your spouse. So my aim here is not to ridicule or not to, you know, chastise Ruby. But to see the cure, the weirdness of Ruby, so that's exactly what I'm gonna talk about. It's nothing scary. I still love Ruby. I still work in Ruby every day, but it's the weirdness that I want to point out. And if any one of you all get the aha moment, then we're in sync. Now, I've been seeing that not many people are asking questions after the talks. So I said, let's reverse the tide. Most of my slides are actually questions for you all. So there's no brownie points for getting the answer, right? Or wrong. But it's for you to understand. So I might ask you all, right? What do you think? You'll raise your hands and try to be as interactive as you can. Now, such a kind of talk is sometimes difficult because I don't know the audience come from a broad spectrum, which is either beginners or some experts. But I realized that the slide is the dark side of Ruby and it rhymed with the dark side of the moon. So I tagged my slides and I have my transformer friends to help me bumblebee for all the signs of questions which are like a beginner level questions and Optimus Prime for all kinds of little crazy stuff. So in case you need to tune out you're learning these questions, that's okay. So without further ado, let's question. Let's talk about the infamous infinity. Now, everybody, I'm being easy, you can see bumblebee there. It's all simple stuff first. Everyone knows the output of this? No points for that. We all know it's division by zero, but what about this? The hint is in the slide, guys. Infinity, well, all right, so let's see what is infinity and infinity turns out to be, all right. So that's interesting. So I'm like, hmm. But then most of us already know that infinity is a constant defined in the float class. Well, all right, so I said, let's go find it. I actually went and dug into the code and found it. Infinity is defined like that in Ruby. But you know the interesting part here is defining missing.h. So that's pretty cool. So I had no idea infinity was actually missing. Well, these are the kinds of things that I'm gonna keep talking about. I'm gonna ask a lot more questions. So I'm just warming you up into the game. The adrenaline rush. Anyone knows the output of this or what this really does. It's a number conversion to a string as an octal. So far, so good. No problems at all. What happens if I push the limit? That's still a number. So any one of y'all next time sees names like ashtricks, obliques, get-of-ix, it could be a number. Well, let's push it, let's push it further. What happens now? That's an invalid radix. Now, that seems strange. But here's the trick. Radix 36 actually worked because I have 26 affabets in 10 digits. So I can go up to 36. So if any one of y'all is lucky or smart enough to get a new alphabet introduced in the English language, we're gonna have radix 37. Well, let's move on to our star of the show, the splat expander. We always use the star in lots of places, multiplication, but anyone knows the output of this. Sounds pretty simple. It looks like I've said it's a hash, so it should be a hash, which looks pretty straightforward. But it gets a little more weird after this. What about this? Now I got, now it's pretty simple stuff, man. What are the, any take-offs for this one? Who would think, will it be three arrays of one, two, and three? Anyone? Will it be one array of one, one, one, two, two, and three, three, three? Or will it be one, two, three? Yeah, I see some modding heads and that's perfectly fine, which, see, makes logical sense, right? What about this? Is the same array interspersed with percent? Well, synchronization. So what you see is not always what you get. Let's do a little more stuff here. Some more fun. This is a lambda. What if I call this? What is the output here? And this is straight forward Ruby stuff. Really, there's nothing weird in this. It's five? Because you're looking at the first, I gave the hints there, middle, second last, and last, and the output's pretty straight forward. But the interesting part here is in the call. We all know that we call a block like this, right? What happens if I do something like this, pay close attention to this part? Is that a syntax error? Anybody's syntax error? That actually works, because that is a synthetic sugar for calling a block. And we'll see a little bit of it later. Speaking of syntax, this should be interesting. And now we'll actually see how many were really paying attention to Koichi-san's talk in the morning. We're all used to seeing functions like this, right? Koichi-san showed us this earlier in the morning. They're keyword arguments. Introduced in Ruby 2.0. Use it, because when you're looking at variables, A and B, what look like parameters there can be actually accessed as local variables inside the function foo. And then special attention to this part. Have you written a syntax like this? Any takers if this is gonna be a syntax error? But this is a mandatory keyword argument. It's part of the show because of the morning talk. But this is a mandatory argument introduced in Ruby 2.1. Let's see some more syntax. Again, very simple stuff. Straightforward method. Nothing fancier, right? How do I invoke this method? This works, right? Right? But when I try this, I get a syntax error. Now, why do I get a syntax error here? Did that look a little weird? No, I say, okay, let's do it again. And all I've done is close the gap. And this works perfectly fine. Why did this happen? It's Ruby. We say that you can call a method without passing the round parenthesis. So if I put a space there, the parts are actually gonna interpret that as some sort of evaluation. And then if I had written that as one plus two, it would evaluate and pass three to method foo. But since it came across a comma, he says, dude, I have no idea what you're doing. So sometimes what you think should work doesn't really work. Well, I've used the title syntax, but now is a simple question for you guys. And I'm pretty sure you'll be able to answer, what is A in this particular slide? Let me give you some multiple choice. How many think it's an array? A is an array. You can raise your hand, you're not wrong. Come on, how many think it's an array? It is an array, right? But can it be something else? Can it be a hash? It can be a hash, right? Because in Ruby, keys can be anything. Can it be something else? Of course it can be a string, but that was obvious, right? Something else? How about it being a proc? That actually works, because I can call a proc using the square brackets. Well, let's get to some sort of case complexities. All right, there pops up Optimus Prime. Time to take a break. Well, we look at, we all use to using case statements. Typically we use it for simple stuff, checking that if some value exists, if there's a number, if it's a string. But you know what? I can actually use and call a method here. This particular method effectively turns out to be evaluated like this. So I can actually have a method with a case equality, which is passed the parameter in the case statement. So using this, I can use this case equality operator to actually evaluate something, but then what is it? The case equality operator is just an alias to the call method. So that's how we get the output, and this is the evaluated form of that case equality operator, which in effect means that if I really want to change the way I want to compare two objects, all I have to do is override the method, and I can just do what I want. But speaking of the case equality operator, speaking of equality, let's have some more fun. What is the output of this? Don't think too much. If this was not true, would you even use this language? It's true, all right, don't worry about it, it's true, what about this? Any takers? JavaScript people? Somebody thought, ah, type check? Come on guys, how can it be false? I just said it was a case equality operator, so it just compares the two. A common mistake made in Ruby because typically because of a JavaScript bias, we feel that it's a type equality check, you check the data type of the object stuff. Oh, it's as simple as that, it's just a case equality operator, it's true. Well, what about this? Eql does seem like equal, it's true, but with some caveats. It's just an alias for the generic equality operator, however, it's overwritten only for the numeric class. Most class is just alias it off to the generic equality operator. Well, what about this? It's gotta be something different, right? When in doubt, choose either true or false. What's the output people? Nil, that is not binary, man, but what else? It's gotta give some output. This is anyone for true? Raise your hands, don't be shy. Anyone for false? And the rest? Nil, ah, this is actually an object identity check. So when you're using equal question mark, it's actually checking the object identity, which is why it's different. So, what's the output here? Hey, people have been listening. And what's the output here? Come on, we've not been listening. True or false? There's two different objects. True, false, well, in this case, it's true. Why? Because object IDs for fixed num are calculated like that. So if you have an object ID for a string, it gives you some big number, but object IDs for a fixed num are just multiplied by two plus one. Interesting, right? Now I urge you to go and ask a few of the core Ruby committers here. Why is this so? Because this is pretty complex. Actually, not quite. Here's another snippet, which I was just pushing the limit to find out. On a 64-bit machine, if I do that, two raised to 62 minus one, it gives me a fixed num, but two raised to 62 gives big num. Two different classes. Now, anyone 62, I'm sure it's nothing to do with a random number because it could have been 42, and it could have been the answer to life universe and everything. But we chose 62. It's a 64-bit machine. The last bit of fixed num actually determined whether that is going to be used as an object ID or not for other fixed nums. So you have only 63 bits to play with, and that's why that's how it works. Well, let's try and see if we have hit a jackpot today. So I wrote some code. And my code is simple. It's three pulls for a jackpot. Three pulls should tell me whether I've actually got a jackpot or I am the sucker. But I've written the code in a slightly different way with special mention about the curry method. Now, seems different, and here you can notice that I've actually called a block of code using square brackets. I'm calling the same method, but the evaluation is slightly different when I use the curry recipe. With curry, unless all the parameters, the block parameters are satisfied, it's not going to evaluate it. It's going to retain you another block. So it evaluates it twice when all the third time the parameter actually comes in, it just evaluates the block. Well, there you have it. Go and curry. So you think you can tell. Protect it from private. Okay, well, what do you think of this? Here, will I save private Ryan? Traditional object-oriented methodologies tell us that private methods are not inherited, right? In Ruby, all methods are inherited. Private methods are indeed inherited. And though this sounds very simple, though this sounds a little astounding to a few people here, my entire talk, my preparation of the talk started off with this point because let me take a simple poll. How many of you do not work in Rails, but work in Ruby? There'll be, oh, I could count it on my fingers. The problem is all of us started working in Rails, and when you start working in Rails, it's so cool, it's so awesome that we tend to forget that it's also very important to learn Ruby. So when I started digging deeper with some of our developers, yes, we are a Ruby on Rails development company, and I started quizzing a few people, I realized that people did not know this. And I was stumped because if we do not know Ruby, then we cannot be good Rails programmers. But since Rails just makes it work, the Rails magic, people continue. Hence, the essence of my talk was to open your eyes to these things. Having said that, and we know that private methods are inherited, then what is the difference between protected and private anyway? We'll come to it. Before that, quick thought, we always use include, right? For any, including any module, but what is include? Is it a keyword? Is it a method? It's a method which is defined as a private method, private instance method in the class module. That's how you can actually use it there. Well, like I mentioned earlier, if all private methods are inherited, then what is protected in Ruby? Because again, traditionally, we've been taught that, oh, protected methods, oh, deals with inheritance. All protected methods are inherited in the subclasses, but you cannot call them on the object. Well, our private methods are also inherited. They cannot be called on the object. So what is the difference between the two? Ruby takes a very pragmatic approach, and protected works with objects and not classes. So you can invoke a protected method on an object if it's in the same lineage, and then you go, what the? It's better than example. So check this out. I actually have initialized Optimus Prime here, but can I call the protected method on it? I have an attribute accessor, nick there, for nick name, for brevity. Can I call the protected method on this object? It doesn't work. It's absolutely right. It doesn't work because it's not supposed to work. You cannot directly call an object, or you cannot call a protected method on an object. However, what happens if I change my code a little bit? I've actually defined a public method called fights. I've passed it another Autobot. Special attention again to this particular piece of code. Have I just called a protected method there? So it is possible to call the protected method on an object if both the objects come from the same hierarchy, the same lineage. So if two objects have the same parent class or the same class or their hierarchy, you can actually call them as long as you're within the class. Well, moving on, does Ruby have any keywords? Yeah, Ruby has keywords? So then I want y'all to tell me whether I'm serious or I'm joking. Can I define a method called true? This code actually works. And it's not that I can define a method true, I can define a method called def. I can define a method called if. I can define a method by any freaking name that I want, whether we use it in standard Ruby or anything. But try defining a method with end, def end, and then you're going to have a little bit of what we call problems because I gotta manage my tongue here. Okay, so if you try and define any keyword as a method inside your class, it works. But again, it will work only in your class. Try this on IRB and it won't work. Try this on IRB, it won't work. Put it inside a Ruby file, it works. Because IRB itself is a Ruby program. So you're evaluating this outside its scope. So put it inside a class, everything works fine. Well, who thought it was stacked too deep and went into a recursive loop? Well, it doesn't. But can it, can I make this, can I make it go into stacked too deep? If I had self.true inside my method false, if I had written self.true and inside my method def true, I had written self.false, it would actually go into a recursive loop and have a stacked too deep error. All right, super. Up there, we have it. We all know what super is, right? Super. If I try this, if I try out this code here, here I've written a class in which I've defined a method called search and in the child class, I've defined another method called search in which I take a mandatory keyword argument and I call super. Should it work? I thought it should work, but it gives me an error which I couldn't quite follow in this talk. Wrong number of arguments, one for zero. Now, it's actually given me an error exactly where super has been called and it says wrong number of arguments, one for zero. I didn't pass any arguments there, so should it have been zero for one? Because I didn't pass any argument. Did I pass there? No, I didn't pass any argument. But if I change my code a little bit, again, notice all I've added is the parenthesis there and this code works fine. So if you really thought in Ruby that you'd never, ever really need to use round brackets and it's always optional, think again. Think again. Well, if this was good enough sauce for you right now, let's move on to modules and see how module mixings are sometimes pretty funny. Now, this is a sample piece of code. The sample is pretty simple. And nothing fancy here. I've just defined three superheroes, the Superman, Batman, and Iron Man all having the fly method in them, all right? This is how I invoke, or this is how I call a method, all right? I created a new guy, Tiny Man, all right? I want him to get the superpowers of Superman, Batman, and Iron Man and I want to make Tiny Man fly and this just works fine. No questions so far. However, if I go and change my code in my modules, I do the unthinkable and add super in my module. What happens now? We know that modules are not classes. We know that modules cannot inherit from other modules. So if I call super in one of the methods, what happens? Lo and behold, this actually works. And now I was stopped. I was like, dude, there's something wrong here. How can this really work? So what happens here is when this class is instantiated, the meta class hierarchy that is built is actually done on the fly. So my inheritance hierarchy actually flows in this particular order, which means that if I just change my module in inheritance structure, I change the inclusion order, I actually get a different inheritance hierarchy. And that is why super actually works. This is to be done with a pinch of salt. This we found out the hard way. We found this out in actual production code because somebody made a mistake and somebody wanted to take a shortcut and had it super in one of the module methods and shit hit the roof. And you're wondering, how the hell can this happen? Till we duck deep and found out, all right, there is more to Ruby than meets the eye. Well, if this wasn't enough, what about something like this? I want to cherry-pick. This is my module Megatron, who is powerful but is evil. Now, in typical Indian style, I have my own class called Hanuman. I want him to be as powerful as Megatron. But if I include him, Hanuman's going to be evil and I am going to be killed. So I cannot let this happen. So can I cherry-pick from the Megatron module? I want the power, but I don't want the evilness. Welcome to unbounded methods. So I can actually cherry-pick from my module, find the method, it's an unbounded method, I bind it to my own object, and I can call it. And in this particular case, Hanuman is powerful, but he is not evil. And if this has not built your appetite, there are a lot of other things that happen in Ruby, but I have only half an hour from my talk. And I have a few minutes for questions. And if you're not going to ask me questions, I could probably ask you a few more. Well, that's all folks.