Tuesday, October 04, 2016

Ruby's Symbols Explained

hi I'm Peter Cooper and we're going to have a quick look at ruby symbols
so if you had to pick an all-time most asked question from the different Ruby
group stackoverflow etc
it might be what are symbols and why use them instead of strings when you're in
Ruby
well this is what symbols look like this is the one of these are symbols but we
can't just finished the video there after you give you a good answer
and that is the in Ruby they are scalar value objects that users identify as
they map immutable strings to fix the internal values that will kind of sounds
a bit like ps3 doesn't it's let's go to impress a little bit more wise than me
back in 2005 Ruby veteran Jim Wyrick said he would love it if people refer to
symbols and symbols are objects with names but if I had to bust it down to
the simplest level
I would kind of say that values with names that kind of values and objects at
the same time so let's have a look at number 42 this is not simple it's just
number 42
but in the real world you know we use this as a symbol it's not 42 particular
things it just represents the concept of 40 tunis we use the number 42 where we
want to represent that we have 42 or something or that our ages 40 to or any
kind of situation where that number is required it stands in as a symbol for
that qty ORD analogy possibly now likewise in something like Ruby the
symbol West is a me identify for the concept of west - it's not actually West
or the word West itself
now if you come from a language like c you might have played around with making
your own equivalents of symbols like with constants and things like that all
definitely armed
you know but compiler definitions like this where when you use the term Monday
or Tuesday or Wednesday gets automatically uses the integer 1 2 or
free for each of those things that in your code you can say monday tuesday
wednesday but behind the scenes is represented by numbers it more efficient
it's kind of a you know a bit like the simple concept that we're talking about
you may also use something called a num which gives you a similar arrangement is
a bit more dynamic
and a bit more scope but this is all philosophical got pretty good right so
we're going to dig into a bit more to get a better feel for all of this would
have been a practical here
look at how things actually work in the real world so when you're working with
interpreters compilers things like that they often have this idea of a symbol
table and what symbol table does it stores all the names of different things
that an interpreter or compiler knows about and then alongside those it can
store a varying type of information tends to us or system you're working
with and but let's say in this case we want to store a symbol the ID of that
individual symbol and we also want to store
what does that symbol . to like as a variable so if we say something x equals
10
you know where is 10 where is it pointing to
so let's go let's just move on you'll get a feel for this we go
so this is Ruby code now will say X equal to the string hello
what happens at this point is really creates a string object and that has the
value hello stored within it for now
it comes up with an object object ID for that still stored internally and then
what it will do is it will also create a symbol X because that's how we have
referred to it it will create a symbol and a symbol also has an ID and then it
will say that that symbol with that ID kind of is linked to all points two
nights in the official term I just come up with that for this table but it
points to that object
so if we're looking at that works we've got the symbol X the symbol X actually
on my ruby interpreter has the idea for 1748 but then I've kind of a random
number which represents the object idea of a string that says hello in it so
we're separating the concept of X and the string hello
2x many points to that string hello and that's the object idea the end
well now let's do the next one let's go y equals 50 so we create another symbol
why and why has an idea for free 8 24 8 on its own and the number 50
because of how things work in ruby has an object idea of 101
so let's carry on a bit more
now let's say Z equals 50 now z is a symbol
it's a different symbol from why so has his own ID for some 1848
but 50 is pretty much in ruby is still an object but it's an immutable object
it can't be changed you can't make 50 51 you end up with a a totally different
thing
so it's kind of a primitive value from the Ruby point of view
so it's the same object so the points to is the same here we get the same object
ID 101 for both because y and z about 50 so they're both pointing to the number
50
now let's shake things up a bit
let's say x equals x now this varies a lot depending on what language you're
working with us to what happens here but in Ruby when you say equals x
let's see what happens all we do is we say right we want I the symbol a
two-point off to the same object
the ex does so that very same hello object in memory gets . to Dubai
it doesn't duplicate it or in magic like that it just takes that object ID and
brings across the i will refer to that as well so now it's carry on
let's do B equals hello well this is an all new string object
this is not the same hello object as X and I referring to so it has a different
object ID you can see in the last column there on the symbol table
totally different object ID and you might think we'll why is this
and the reason for this is that in Ruby strings are immutable this means that
you can change then you can add extra content onto a string is the same object
but it has a different value text text wise
so where are you going to do that we're going to take out I and we're going to
say
append to that string , worlds that turns into hello world
well now x will equal hello world
I will equals hello world that be will still equals hello because it's a
totally different object as we can see from the object ids in the last column
of the table
so let's take all of these and simple variable names we got here
these are actually symbols these are represented as symbols internally within
Ruby
and that is what Ruby's a simple feature actually allows us to access and play
with
so on the symbol class there is a method called all underscore symbols and what
we can do is it's got tons and I mean when you run up I'll be or something
like that
they'll be over a thousand different symbols already defined because all the
libraries is loaded and stuff like that
so what we'll do is we'll look at the size of them so let's say you know when
we start out there is 1234 symbols we next to find a variable got brand new
name
blah blah blah equals 1 2 3 4 we check how many symbols are again this one two
three five
there is now a symbol called blah blah blah that exists on the symbol table so
symbols kind of represent values and the strings that you see like the kool on
whatever kind of represent the symbols there's a bit of a relationship going on
here
now something as well worth getting into your head is the two symbols
if they have that same string identifying them so in this case X
that's symbol on the left and the symbol on the right are exactly the same object
that the same object idea memory
they are the same thing but if you remember from before with the strings a
string of X and string of X if you just define them like that
if you use the double equals in Ruby it will say they're equal because what it's
doing is actually looking at the content of the string and saying oh yeah
X is equal to X in a textual way but if you look at the object ids they're
totally different objects within memory so they are not the same thing
and if you ask me with platform for example this may be slightly confusing
because in Python you can actually use strings in the way we use symbols in
Ruby because in Python strings are immutable so you don't have this whole
problem at all
so what can symbols represent well as a whole ton of things i can represent in
ruby is very common to use them for method names and things like concepts
and shapes and get parameters that you send in and things like that it's just
tons and tons of stuff we're gonna look at some examples in a minute but the key
thing Barry mind is they're used for unique identifier they're not used for
data
so if you've got a string that's coming from a database and it's you know random
stuff what stuff has been typed in a website and click submit its come in
it's not used for that those are strings those are just dynamic text or data we
need these for identifies they identified concepts very small limited
vocabulary is a way I've explained before where strings and more for more
kind of freeform data user-supplied data now back in two thousand seven
Jim Warrick again that name again he said if the textual content of the
object is important use a string
if the identity of the object is important to use a symbol
I totally go along with that definitely think that's the way to go
now i was reading through David blacks very very fine
well grounded rubios book and just to see some of the stuff that he had to say
about symbols and i came across one of the examples in his book and on its own
is correct but there's a slight florida and i don't want to leave this as an
exercise to you to figure out what's going on here
so very similar to what i was doing earlier he was saying symbol or symbol .
sighs getting a size creating a variable called I checking the size the size is
increased because now there's no simple could i and what he's doing is he saying
symbol for all symbols so return that array of all the different symbol names
does it include I and it does but the thing is if you take that line at the
end symbol to all symbols don't include and you put any similar name in there so
even a simple name of something that your variable it doesn't even exist so
just you know Quincy bow or whatever it will always return true
why is that I could explain why but I just want you to i have a little
challenge there so why would it do that leave us a comment or room
on the forum if you're on the course that type of thing
so let's actually talk about making symbols are here is a symbol
: gender now you can't put spaces in because otherwise how's it going to know
where the same lens
it's just you know simple word with you can have under schools in you can have
numbers and within it all that type of thing but very very simple but if you do
want to kind of make a bit more string like while still being a symbol you can
use your colon and then use your wrote quotation marks and then put in whatever
is do you want but i would not recommend ever using symbols of spaces and it just
gets horrible the way to notate them try and stick with the that notation if at
all possible
another way to do it is just taken or string and then go to sin
now you wouldn't normally do it in this way if you were here in some code you
would use to seem to convert a string that you don't have control over into a
symbol you wouldn't do it a literal like this because otherwise you might as well
just type
: gender in the first place and sable them all the the kind of the memory
problems of duplicating strings all over the place
so just keep that in mind another one that you can use these . in turn and the
whole concept of taking a string object and in turning into something in turn on
that has a one fixed value is often called interning in various languages so
that concept is in Ruby as well
another way to do it is to use percent s and this is a bit like where you can
define you know arrays with % w or strings with % q that type of thing or %
s gives you another way of turning a string into a symbol essentially so that
will also create the : gender symbol and what about the other way around we want
to take a symbol turned back into a string
just do it with this 2's converts anything to a string
perfect alternatively you can use ID to name
I think this kind of dates from the internal names of the functions that
we've been the main ruby interpreter for doing this type of work but I've not
actually
seen people really use this much in the world so don't worry too much about what
I just used to to us personally
so let's go into some common uses for symbols what can we do
well we're going to do this life because get bored of me changed about stuff
actually going to show you some examples life
okay before we get too far with this I want to really stress that whole point
about symbols being more efficient than strings so let's take a string for
example hello
and what we'll do is we'll just quickly see what is the object idea of that
string
ok seems fair enough but if we keep repeating it over and over we can see
that has a different object ID each time
and the reason for that is because there's a string in memory being crazy
time hello hello hello there are different objects and the reason for
that as i mentioned before is because strings are immutable they can be
changed if we do the same thing with symbol and we check its object ID you
can see it's always the same ID you think okay
interesting but why is that important well let's say we've got a concept of a
user in our system wave just being scrappy here we're using hash to keep
track of them and we creating something like this we've got their name so it
Fred
we've got there I each 10 something like that so it's a simple hash mapping your
keys are strings to values that may be strings or above objects anything
so we've got that now imagine if we had say I don't know several thousand of
these what would happen is all of these name and age strings here because
strings are immutable can be changed in Ruby these would keep being created new
objects
so even though every single one would have the key of name and a key of age
each of those individual strings representing the concepts of name and
age in each of those hashes would be created a fresh and we can check this by
going
user . keys so that gets us the name in the age and then what we'll do is we
will map the object ID Ian so
okay that looks good will create another user job in the same name is that in the
same age
oops I made a mistake there
I didn't put user - okay now you can see what the problem here is is that between
these two different comparisons they have different ideas
so if you had thousands or even millions of different users in this system you'll
be duplicated needless stuff with the name of the age
let's go back and make change we will use symbols instead
and this really is the whole motivation for why you would use symbols
not least because you know they kind of have a semantic difference and they look
different in the code but because of this efficiency angle so now we'll do is
we'll use the keys map and use two keys map you can see that the keys are based
on the exact same symbol objects every single time
this makes them super efficient and this is one of the main reasons we use them
so I'm kind of showing you off actually one of the first main uses for using
symbols is because you can use them as keys within hashes
that's very useful this pattern of using symbols as keys for hashes
it's so prevalent that ruby 1.9 actually i did some stuff to make the whole
system a lot simpler and to give it a slightly nicer syntax
although there are many would disagree with this but all you do something like
this
see even i'm making it wrong so in this case you would still use symbols to do
lookups
but you can see up here instead of using symbols we've just used text but then
put the colon after and this is a more kind of common syntax you'd seen
something like JavaScript or Python
there's a lot of experience redeveloped as you do not like the syntax but just
be aware you may bump into it and you may well wish to choose to use it
yourself
let's bring up an editor so we've already noted several times now that
symbols are just regular Ruby objects so they can be passed around just like any
other object
so you're sure to have done something like this already so you got a user
class and in here we've got after accessor we've got things like name age
gender or that type of thing and then you might want to create a new user and
you can set information upon them like so
and what we'll do is we'll just print out everything that's in Fred and as you
can see we get what we expect after accessor is just a method that is on the
module class and what that does is it creates accessor methods and getters and
setters for us a name equals name age equals age and gender equals and gender
& all we're doing is passing in symbols and bear it works
so that's a very common use for symbols is just to use them when you're passing
stuff into methods that are as we've said from a limited vocabulary something
on those types of lines number instance where you might use this
I just delete this and go to the M i'll be again if we got something like let's
say a string and let's say we want to ask it
do you respond to length and it's a little bit crowded in here
what do is expand that so what I do you respond to length and it is true do you
respond to those II know you don't because that method doesn't exist upon
hello
so this again is just a method that we have in Ruby on the object class and it
just takes a symbol and then it returns true or false depending on whether the
object will not respond to that message or not and or in layman's terms with it
or responses we're gonna run that method or not whether that method exists upon
that object if you've been using Ruby for more than a trivial amount of time
you may be familiar with the the concept that the if the last argument that you
pass into a method
it's a hash it doesn't have to be notated as a hash and hash literal so
for example here
I've got a very simple medical mind the school method it has free required and
parameters come in we have a baby and options
so when I now invoke that method and passing in one which will go to a to
that will go to be and I've kind of definitely literally put down a complete
hash here to pass into options so if i run that no surprises
what is in here it's the hash well you may know that of course you don't
actually need to do that in Ruby if something looks like a half
- at the end of a method call it gets treated like one
and so this is often used for doing things like named parameter type and
adventures so that still works but you might remember that 1.9 syntax I was
showing you about with ashes
well again all that works here as well if we change that over this looks a lot
more like a named parameter system that you my ex you know see in other
languages
so this is very attractive and of course we don't even need these required
parameters here you can have your entire call be done in this way and almost
looks a bit objective-c esque which is kind of cool and has been used to that
advantage in there are several web frameworks one particularly intriguing
and slightly advanced use of symbols is in what we call symbol to proc this came
in a project called the Ruby extensions project and then it got blown into rails
and then eventually actually became part of the core Ruby language and now you
can use it and fine i think i'm really want . a five and
one point nine onwards
so let's say we've got an array here it contains three words hello world and
test
what we would do if we wanted to you know create a new array with all of
those words in upper case so we might use the map method and do it this way so
we can see here we get out all of that stuff in uppercase
well this is kind of you know there's lots of ripping a repetition of the word
word and it's just extra syntax stuff like that
is there a quick way of doing this well if you've been using rails are quite a
while you've been following the style guides and reading the books and
everything you have seen this type of construction
so if we run that it does exactly the same thing and you may notice having
watched this video that a symbol is being used here so this is a symbol that
represents the up case method but was this ampersand wall
the ampersand in this situation is coercing the symbol to become a proc
object in a proxy object is something that can be passed off to a method that
you can run and how everyone so the map method will run that proc multiple times
to do the mapping from one array to the new one but back in the old days before
you know this became park or Ruby symbols couldn't be coerced
Fox didn't really make sense as a concept so someone I don't know who came
up with a clever idea that we have to do is go in
add the method to the symbol class called to underscore proc which is what
the ampersand conversion will call anyway on whatever object you pass in
and then what we do inside there is we create a proc and we accept an object
and then we use the send method which will pass the message into an object to
run and a particular method that is the same as the symbol that we've got now
that might sound a bit complicated i think i might do another video about
just this simple to proc thing specifically and can try to focus
entirely on symbols here but essentially what happens is is that that will run up
case in each case for doing the mapping from one thing to the other
so before we finish our little tour of symbols here today
I just want to cover an interesting point that ruby 1.9 point so that makes
here now
we said earlier that even though symbols are kind of represented by a mutable
strings
you know if you look at them from a physical point of view we've got our :
and then what looks like a string following it and that can't be changed
always associates this one value behind the scenes as we've seen
despite that and despite people say well no they're not really a mutable string
that's not how you should look at these really want . he added a bunch of
methods to make symbols act a bit more like a musical strings which is rather
confusing and i am not particularly keen on this and I haven't come across any
real need to use this and but they must have been added for a reason so there's
gonna be a motivation for this
so what I mean let's take a symbol that sir just do
ABCDEF that's fine well what you can now do in ruby 1.9 is you can call certain
string methods upon them
so you can get an uppercase version of your symbol you can get down case of
that will be the same
you can get the length of the string that represents that symbol so the ABCDE
F 6 characters long
you can even go in and access individual characters from the symbol
and access other things like next and stuff like that
I'm not a big fan of this i'm not sure that the need for it
just what you should be aware of this however though if you see in code
sometimes people are kind of trying to use the strings and being a little bit
clever but i would go back to what we said earlier in the video and these
really are and value objects are identities of things and so look at them
in that regard
and so there we are we are at the end of the symbols video a little bit longer
than expected it to be but there is some of the very important symbols in Ruby
you need to be aware of how they work and get a quite get a good feel for them
and hopefully I'm giving you a reasonable introduction to them but if
you have more questions
just head to the forum and ask whatever you like
this thing's I could explain better of course i could do more videos towards
that
so for now very much

No comments:

Post a Comment