- Read Tutorial
- Watch Guide Video
Brayden speaking
Cool. I'm the host now that's scary.
So alright I will go ahead and get started. Some of you have been in my class or I've taught a class for you; you might have seen this already. So I hate to disappoint you, but we're going to go over scope and some basic Ruby stuff. James kind of told me that the group was essentially going to be people that are kind of still working through Ruby and that sort of thing. So that's kind of where we're going to start, and depending on time we'll go build to something else.
So, let's go ahead and figure out how to share this particular. Let's go here, do that. How does that look on your yours? Is that what they're seeing. We're going to go ahead and we're going to talk about scope. We'll start there and we'll build from there. Can you hear me also too? Can you guys hear me out there? Thumbs up? Yes in the chat?
SCOPE
OK, let's go ahead and talk about scope. So let me click into my, so scope especially in Ruby, but in pretty much any language. I guess I can describe myself. James did introduce me I'm the senior instructor here for Ruby and doing this for a while. Love that. So happy to talk to some part time people that I have maybe interacted with but we haven't done a face to face so I appreciate James for inviting me out to this.
OK so scope in Ruby comes down to two things. It comes down to essentially Variables and Visibility and so moving on with that. Variables, according to Ruby. There is essentially a place to store data, and they hold objects, and they're given unique names. The reason that they're giving unique names is because when you call their name, there are actually two different sides.
I like to think of the variables. I like think of them as a string and not a string necessarily of you know, data. I wanna say like a shoe string like it like it you take the laces out of your shoe and you can hold both ends. And I want a picture one of those ends going inside of a computer. I want the other end to go on your screen. Right. And so essentially we type words that go into memory and they reserve space in memory. So that's what RAM that stands for random access memory in your computer. It's what makes video games look good. Also what makes your programs work. So there are those two different sides to it. The place is RAM and the name on our side that we code with.
VARIABLES
So with that said, there are five different variables in Ruby. There's a local variable, an instance variable, there is a class variable, a global variable, and a constant variable. So we have these five different variables and we'll use them to varying degrees and we want to make sure that we want to make sure that these kind of have their own proper place. Because where we use them matters inside of any programming language but especially inside Ruby. So we'll talk about that.
LOCAL VARIABLES
So we have the local variable and what happens is the ruby interpreter will put a local variable inside of scope whenever it sees assignation whenever and we'll talk about what that means. Doesn't matter if the code is executed or not. The moment the interpreter sees the assignment of a local variable it puts it inside, into local scope. So if we have an arrow that goes essentially from right, right it's pointing left. We want to think of it assignation when you assign something of value that works right to left.
So we talked about the variable that we create. What happens is everything on the right side of the assignment operator in other words the equal sign, that gets stored inside of that name as a value. So we have right here 'a string'
and that is going to get stored inside of some_variable
. So we say some_variable = 'a string'
but it's not necessarily the best way to think of that. We actually want to preface this as some_variable
is assigned the value of 'a string'
. Because that value can actually change and so you can assign different values depending on your need. So right here we say x
is assigned 4
. Then we could say String.new
is assigned to my_string
and so that's kind of how the local variable works.
INSTANCE VARIABLES
We'll talk about instance variables next. So an instance variable is associated with a particular object as long as you're inside of that object, you have access to them. An instance variable begin with an @
(in Ruby). An uninitialized instance variable has the value nil
. So we'll talk a little bit about the difference between local and instance variable in the second. But it works the same way with instance variables.
Assignation works right to left. So a string
gets assigned to @some_variable
. @some_variable
is assigned the value of a string
. @x
is assigned the value of 4
or you know the lazy way to say it is @x=4
. But it technically contains and has the value 4
. x
now (in Ruby) is it's own property, and you have a String.new
which is being assigned to @my_str
.
CLASS VARIABLES
So moving on to class variables. This is where the water starts to get just a little bit more muddy. So class variables are available from the class definition and any subclasses. It's not available from anywhere outside. Class variables are shared by all class instances in other words, subclasses, whereas class instance variables, the thing that we just talked about.
When it says class instance variables, we're talking about instance variables that belong to a class. They're specific to only that class, but if you don't intend to extend your class, the difference is purely academic. So basically, it comes down to inheritance. Class variables will extend to the children classes or the subclasses. So that's good, but it can also be very bad. And who wants to know why? Can somebody out there, does somebody out there know why it's a bad idea to have something available and different classes? Anybody feel brave?
Parker speaking
You could unintentionally change something that you didn't mean to.
Brayden speaking
Sure. So the way that class variables work is you have a class that you know holds a value the variable holds value inside that class. Now let's say we step down one child let's say we step down another child. So we have a parent and then we have you know like the super parent. So if we change the variables down in this class we can actually affect the variables in the first class and maybe, you know what, I wasn't planning on doing this, but maybe we'll just do this.
So let's call this now, ruby_variables.rb
. OK let's say we have a class
. Class...I don't know what we should name it. class RubyVar
and let's go end
, then let's go ahead and do a local variable, local_var = 3
.
class RubyVar local_var = 3 puts local_var end
And let's say instead of muddying the waters a little bit let's call this a method for now.
def ruby_vars local_var = 3 puts local_var end ruby_vars
So what is this going to put? Whoops, I hit the wrong thing. For those of you that haven't used this before in sublime if you hit command B then it will actually run your program for you in screen. It's a basic version of it it won't get like input and stuff like that. So you can see that I've got my local variable right? But now what happens if I step outside?
local_var = 3 def ruby_vars puts local_var end ruby_vars
You see that it doesn't work right? And it says right here, unidentified local variable or method 'local_var' for main:Object
, which is kind of an interesting thing. I want you to pay attention to is main object and also unidentified local variable or method. Isn't it interesting that it doesn't even know what it is. Cause it technically is outside of scope. So how do we fix this?
There's a couple ways. So the first way that we fix this is go ahead and get in here and step that inside. So now it's local to the method and that'll fix it.
def ruby_vars local_var = 3 puts local_var end ruby_vars
Another way is we can make it an instance variable. Make them both instance variables. And we're able to see those as well because they're all attached to something called the main object.
@local_var = 3 def ruby_vars puts @local_var end ruby_vars
Now here's an interesting thing, when we make it a class. So let's say my_class
we're going to instantiate equals RubyStuff.new
. So could do my_class
and then we could call ruby_vars
right? Now this doesn't work.
class RubyStuff @local_var = 3 def ruby_vars puts @local_var end end my_class = RubyStuff.new my_class.ruby_vars
I mean technically it says local variable. Like it says nothing. That's because this came up nil
. So there's a reason that this doesn't work. Now if I were to move this inside. And we run this again then it'll work. And it's because that instance variable that we just talked about gets attached to this class.
class RubyStuff def ruby_vars @local_var = 3 puts @local_var end end my_class = RubyStuff.new my_class.ruby_vars
So when we make a new one, we'll make my_class
which if we do now my_class.class
and we print that out. It's a RubyStuff
class. Does that make sense?
class RubyStuff @local_var = 3 def ruby_vars puts @local_var end end my_class = RubyStuff.new my_class.ruby_vars p my_class.class
So if we get rid of all of this. We'll keep that class, leave the instantiation. I didn't want to expose this right here. We'll kill that line.
class RubyStuff @local_var = 3 def ruby_vars puts @local_var end end my_class = RubyStuff.new p my_class.class
It's a RubyStuff
class. It is a class made out of the exact make up RubyStuff
, but it's own class called my_class
. And so the instance variable stays inside of that.
And now let's talk about the class variable.
class RubyStuff @@local_var = 3 def ruby_vars puts @@local_var end end my_class = RubyStuff.new p my_class.class
You guys see how that will actually. Get that back, the way that you guys saw it prior where we'll calling the method. Now let's make this an instance variable instead. Now when we do this, we get the value. Which is really cool. Except for when we start, let's make another method. Let's make another class. Let's say class NewClass
and then we're going to inherit from my_class
. Inside here, we're going to say @@
local variable which I guess isn't properly named because I'm changing it to instance variable and that sort of thing, but I didn't catch that until now. Sorry about that. And then what if I say this is now going to be 7
.
class RubyStuff @@local_var = 3 def ruby_vars puts @@local_var end end my_class = RubyStuff.new p my_class.class class NewClass <my_Class @@local_var = 7 end
It's calling it 3
and then saying superclass must be a class
.
And so it's essentially we're inheriting. It's essentially having problems crawling up to the top class which isn't exactly what the behavior that we want. So what, we're going to do is we'll hop back into stop sharing that and start.
So let's get back into here. And so essentially the idea is that these class variables are going to change the definition as they, up and down as they go. And that can be really dangerous in our program. So we assign them the same way but we use them a little bit differently and we'll get into that exercise a little bit later that demonstrates that.
GLOBAL VARIABLE
So next we have a global variable and that's available everywhere within your script. And it's just not a good idea to use these. They can be assigned and reassigned everywhere inside of our codebase. So assignation works right to left. We don't ever want to use one of those so then we say don't do this.
CONSTANT VARIABLE
And last we have a constant variable. And that begins with an uppercase letter. Constants defined within the class or module can be accessed from within that class or module. And those defined outside the class or module can be accessed globally. So we'll see an example of that in just a second. Constants may not be defined within methods referencing an uninitialized constant produces an error, which you guys have probably seen. Generally, when you forget to capitalize a class it will say uninitialized constant, class must be a constant. So making the assignment to a constant that is already initialized produces a warning. Ruby is actually flexible enough that even your constants, it will allow you to change. It will just give you a warning saying, hey you're about to change this constant. Are you sure you want to do that? So assignation works right to left and MY_CONSTANT
here is assigned the value of a string
.
LOCAL VARIABLE VS INSTANCE VARIABLE
So we'll talk about Local Variable vs Instance Variable which is partly what we did in the example. But instance variables are associated with a particular object, like the class that we made, as long as you're inside of that object you have access to them. Local Variables unlike Instance Variables are associated with a particular scope. So as long as you're inside of that scope you have access to those, but not necessarily anywhere else inside of the object. Instance variables change and they get replaced with every new object. And local variables change and they get replaced with every new scope.
So how do you know the scope has changed? Something called scope gates. And just like a gate opens and closes, your scope opens and closes in a program. The variables and the visibility that those variables have through the rest of your program.
So one time a fun thing to do is if you hop into to...yeah I don't want to switch this too much but just take my word for it I guess. If you hop into a terminal and you just say hey puts self
you'll get something called main
. And main
is actually an inherited object from the object class
of Ruby.
That main
is an object that is the top the top level context. In other words the top level scope of a ruby program. So any method defined in the top level scope. In other words methods that are not wrapped in a class or a module. They are bound to the main object and so that's why you can say x = 4
or x
is assigned 4
and right underneath it you can say puts x
. It knows about x
because it's inside of the main scope.
So just like this slide shows. We have a main scope and then let's say this is like a terminal or this is a like a sublime or a text editor for us. When we create this module called SomeModule
we define new scope and that scope exists down to where that light blue end ends itself.
And the same thing with a class. When we start a new class called SomeClass
we define new scope inside of that class and when we create a method called SomeMethod
we define new scope with that def end
. So module end tells us the scope of SomeModule
. Class end
tells us the scope of a class and def end
tells us the scope that that method scope. They're known as scope gates because a new scope is created the old scope is no longer available and variables that were available inside of it are replaced with any new new scope.
So I like to think of things in terms of video games right? You can see my shirt and you know I have kind of a video-game mind. So I like to think of Super Mario Bros being like its own class. What it exists inside of Super Mario Bros? Well Mario would be one. Luigi would be another. Princess would be another. You can have level 1, 1 you could have level 1, 2 you could have the Underwater World. You could have all these different things inside of Mario that kind of help Mario to run. Help Mario to be a thing. There are all sorts of attributes that belong to Mario and the video game that belong inside of that class.
A module is a little bit different than a class. I have here a bunch of different video games Mario Bros, Zelda, Punch-Out, Contra and I like to think of a module like a reusable library. So let's say let's say that the main difference between a module and a class is that a module can never be instantiated. In other words you cannot create a new version of that, as you know some sort of a template. Where you know we can take, in the prior example, we can take Mario Bros and we can make a new one of it. We can make Mario Bros 2 and 3 and 4. Let's say that if it was a module, instead of a class, we couldn't make a new one we would just be able to use that code to do fun things you know.
So I like to think of a lot of times that does confuse my students, but I like to think of a module being processes. So it's not necessarily something that you're going to have to reuse to make new versions of it. Like a checkout process, for example. If you go to Walmart or Smith's or any of these different kinds of stores. You're not going to check out substantially different depending on what store you go to. It's the same type of thing that a lot of different stores. Right? So that is like using a module. It's the same type of code, the same exact code, used in a lot of different ways; used in a lot of different places. And so that's the main difference between modules and classes.
We haven't talked. We talked a little bit about visual representation, but this is more of a visual for it. So we have a, we have a local scope which is just that black box that only knows about itself. Then we have the instant scope which is attached to that object. Then we have the class scope which actually sees outside of that object into any sub-objects, and then we have a global scope which is everywhere.
But we haven't talked about the most important scope which is the Super Scope
. I had a lot of fun with toy running around in my back backyard. I don't think that there is actually any very many good games for it. It was a lot of fun. So moving on with that we now get to **Super Scope Bros (#1), which this is an example that I kind of wanted to play with you guys.
Given that we have a class called SuperMarioBros
. And that saved_princess
is assigned the value of true
. Then we have a method called castle_one
that we started and we say if saved_princess
. What I want you to think about it is that actually equals equals true. In Ruby a shorthand way of just asking if something exists is just by saying if
and then the name of it. Because we don't have to always say if it exists then it is true in Ruby.
So we say if saved_princess
puts smooch
. else
. In other words puts I'm sorry your process is another castle
. Then we end that scope and then the if end
and end the method itself and then we're ending the class and down on 15 we're saying mario
and then we're assigning mario
a new class of SuperMarioBros
. So were instantiating. We're making a new instance of SuperMarioBros
. And then we're calling castle_one
from mario
.
So the question that I have for you guys is are we going to get smooch
when we run this? Are we going to get I'm sorry your princess and another castle
? Or are we going to get syntax error because the program won't run?
You guys can ask any questions. I'm not going to answer them too much because I want to make sure that you know, I'm not leading the decision making but does anybody have any question about this or...go ahead and maybe give it about five six seven more seconds. Anybody said anything so far?
James speaking
We have one person saying it's going to say smooch. Two people now. General consensus say smooch.
Brayden speaking
All right. So we'll go ahead and do the big reveal so it's not, I'm sorry and it's not smooch.
So it's a syntax error. The program won't run. And the reason that it won't run is because it's outside of the local the local context for it. saved princesses
is being saved locally inside of SuperMarioBros
and castle_one
is its own scope.
So we'll go ahead and do another one. Now we've changed a few things that @saved_ princess
so saved_princess
turned into @saved_princess
so we made an instance variable of it. And we also are calling it as an instance variable on line seven.
So with that said during the rest of the same process is it going to be smooch
, I'm sorry your princess is in another castle
, or a syntax error. The program won't run?
So with that let's go ahead. And just not 'A'. And it's not 'B' it's not 'C' . Sorry it is 'B'.
So an interesting thing happened with this. So we have saved_princess
a lot of a lot of you thought it should be a smooch. Because he said, well it's an instance variable and saved_princess
can see inside of castle_one
. And you would be very correct about that, if line 17 didn't happen. But what we've done on line 17 is we have created a new class based on the SuperMarioBros
class called mario
and we're calling castle_one
the method that lives inside of mario
.
One of the things that we talked about with instance variables is that they are saved to the object that they live inside of. Another word for that is the class object. So they so they live inside this saved_princess
lives inside of SuperMarioBros
. But def castle_one
gets copied over exactly as it is. So the only time saved_princess
is mentioned inside of our new mario
class is on line, what would be line 7 of the new class. Line 3 save_princess
does not. It does not pack its bags and go for the ride. It is a instance variable so it belongs to the instance or in other words the object act that it is attached to. So any questions on either one of those so far?
Alright let's move on to one more. I technically have two more, but this this first one. So we're @@saved_princess
now. So we're saying if @@saved_princess
So we've now turned it from an instance variable into a class variables.
Based on what we talked about with class variables versus instance variables, the example we went through we have now the question of: Is it Smooch? Is it I'm sorry your princesses and another castle? Or is that syntax error because the program won't run?
James speaking
Everyone's saying 'A'.
Brayden speaking
Give you a few seconds on that. Sweet! Everyone's right on this time this one is like third time's the charm kind of thing. It is smooch time because the class variable is going to get saved to mario
. So line 3 is going to exist inside of mario
. Line 7 will also exist the same way because that comes with the method. The actual call that saved_princess
is making a reference to saved_princess
and it understands what saved_princess
is because it comes along for the ride.
@@ saved_princess
belongs to any of the classes or subclasses that share that inheritance. That's a good thing in this in this context. It could be a bad thing in a coding world context based on the behavior that we want it to have. It could be a bad thing if we do change it down further below. It would actually change it up above as well inside of our parent class, SuperMarioBros
. So we want to kind of be careful about that, but in this case it's exactly right.
Moving on to our last one, we have Saved_princess
now outside in the main scope and I've done a little tricky thing. So we'll ask you the same question and you're welcome to ask any questions about what you think is happening in that sort of thing. But the question I have for you is: Is it a smooch? Is it I'm sorry your princess is in the other castle? Or is it syntax error because the program won't run? Are there any questions up over there?
James speaking
Just to be sure that is a constant variable correct?
Brayden speaking
Correct. Yeah. So that is a constant. I'm a little bit being a little bit tricky about it because I'm only capitalizing the first letter which still technically makes it a constant, but best practice in Ruby is that we capitalize everything just so we're super explicit. But good catch. So it is a it is a constant. It's technically outside of SuperMarioBros
class scope so what does that make it? What did we say? Do we have any guesses? We have one 'A', going for two .
James speaking
And somebody to second it.
Brayden speaking
Now we're going second it. Everybody is stumped. And that's OK. So moving on it is not 'B'. It is not 'C'. It is 'A'. So congratulations to those of you that thought it was 'A'. Essentially what's happening is because it's outside of SuperMarioBros
scope, but still inside of main scope, it actually becomes a global variable to anything inside of this program. So that's pretty cool behavior, when we want it to do that.
Sometimes we don't want that to happen, but generally when you're working with constants you kind of want them to be universally available. It just kind of depends on the scope that you're going for. That is that. I think that it's my portion of the lecture. What I want to do is I want to I've got to leave in about 10 minutes or so, 10, 15 minutes. But I want to fill in questions if there are any questions about how about this. And then I'll hand it back over to James you can.
James speaking
Any tips on finding correct scope? I have been having issues with that.
Brayden speaking
Yeah that's a great question. So one way to find correct scope is to just get it wrong. Right? When you get it wrong, you generally get some ideas of what's happening wrong. Let's let's go. So the question was: Any tips on finding scope?
One of my favorite things to do. I don't know if you guys have learned much about pry
or if you had used pry
. I am a big big big prize. So I'm going to require 'pry'
up at the top of my program and then I'm going to puts self
. Print that out. So hey so there's my main
.
And then if I do this, my main
is an object so that's kind of cool.
But as far as finding scope it's really just the practice of what variables you're working with and making sure that you can kind of play. I would just play around with all of them. So he's got a method we'll call it def leppard
. I'm sure nobody has ever done that joke. I'm breaking breaking new ground. So then if I try and puts x
, it's not going to know about it.
Just because it doesn't know that scope then I can come in and I can change them to be @x
. Now I've got 4
.
You can have you know create different methods that call each other and they call in different scope. Use reading a lot of programming too kind of helps to where you're saying okay where does my scope begin and end. I've got a def end
. In fact, this is one for you guys maybe. I don't know if you're using sublime, there's command shift P
which is your package installer and if you hit an install
like that, then it will pull up all these different all these different things that you can install as part of your stuff.
And there's one that I like called bracket highlighter. You type in bracket and it will come up as bracket highlighter. I technically have it so it's not going to install it. command shift P
instead of install. You can see the bracket highlighter
.
But command shift p, I've got a bracket highlighter and I've got a few other that are installed it, Gitgutter and some others. But bracket highlighter I like because it shows me def end
here and then like let's figure a javascript program where I've got some different parentheses and different enclosures that are half the thing, and promises and that sort of thing.
That's what I do like Bracket Highlighters. It will tell me when I select different code where I'm at inside of that code. So if I have a class, and it's class Dog
, then I've got a method inside of that called cat
, cause it's a crazy world. It tells me, it gives me my def end
and it tells me right here. I've got def
and I've got end and now I'm inside of my class and that actually does help me with scope because now I know OK this is my scope gate def end
. This is my scope from my class that I know I have an instance variable here called @kitty
and I know that. OK. My instance variable attaches to this entire class named Dog. And it starts here and ends there.
So hopefully that answers your question a little bit. It's just practice really helps. And you know some some tools like this do bit too. Any other questions? No questions. I'll just hand over to you. Well I'll show you guys the intro of the next scope one because it's pretty great. I'm proud of it. So should you invite me back. You know if you guys want to do this again. This is my next one I like to share with my classes where we talk about getter and setter methods. So Scope Wars (aka Scope 2.0, The Interpeter Strikes Back.
brief clip from that slideshow
It's pretty good. Couple lame jokes on their so we'll hand it back to James now. Appreciate the invite and good luck. Go ahead and reach out to me in the Slack. I am @braydengreen or something like that.
James speaking
Thanks so much Brayden. I remember when I very first watched this slide show or this presentation from Brayden and I did not have the slightest idea what was going on. I mean even watching it a second time and it's been probably about two months or so since I've seen this. It it all makes a lot more sense now. If there's any questions that you did have feel free to reach out to any of the mentors that are on tonight or in the daytime as well or even to Brayden. Don't feel overwhelmed if you didn't get anything because you'll eventually get it and you'll always have this recording available to refer back to. But again thank you for Brayden and I think we'll just go ahead and end it here.
We won't be having a webinar this Thursday, but we'll pick up back next Tuesday and Thursday. The one I have planned for today, actually, for next Tuesday, sorry, feeds perfectly into this. We'll be using a lot of what Brayden covered today to actually build kind of a "Choose Your Own Adventure Type Game". So it'll be really fun and we'll be using all of these are not all of these, but several different variables, classes, creating those classes, calling those classes and so on. So it should be really exciting I hope that everyone is able to come and participate in that next Tuesday. But again thank you so much. And we will be available all night for any questions if you have any. You guys have a great night.