Are symbols scoped to the class they're declared in? - ruby

I've been learning about symbols, and there's one aspect I have a question on that I cannot find an answer to anywhere. It seems relatively common to create a symbol for an accessor on a class:
class Person
attr_accessor :name
end
person = Person.new
person.name = "Dennis"
person.name # => "Dennis"
Since symbols can only be declared and written to once, does that mean nowhere else in this program can :name be created as a symbol? Or is it scoped to the Person class, which would allow it to be created elsewhere in other contexts?

Symbols aren't "declared", and they don't have a scope. They just are. When you assign the Integer 1 to a variable, this does not mean that you aren't allowed to use the Integer 1 anywhere else in your program. Symbols are just like numbers. In fact, Symbols are almost exactly like numbers, much more so than they are like Strings.
Also, Symbols can't be "written to". They are immutable, again very much like numbers: you can't "write to" the number 1 and change it into the number two, so that 1 + 1 equals 4.

A symbol is global. Every :name has the same object id. This is like numbers: Every number 4711 is the same object. You can verify this in irb by doint a
:name.object_id == :name.dup.object_id
which will return true.
Like everyone can use the number 4711, everyone can use the symbol :name. If you want to have unique objects, use a String, where you can control duplication
v = 'name'
w = v.dup # different object

Related

Class instance with names defined by string

In 'pure ruby' (not rails), given a class:
class Person
end
...and an array of strings:
people_names = ['John', 'Jane', 'Barbara', 'Bob']
how can I instantiate the Person class, with each instance variable named one of the elements in my array?
John = Person.new
Jane = Person.new
Barbara = Person.new
Bob = Person.new
Its pretty unclear what you actually want here since an identifier in ruby starting with an uppercase letter in Ruby is a constant.
John = Person.new
Jane = Person.new
Barbara = Person.new
Bob = Person.new
You can dynamically assign constants with Module#const_set.
module MyModule
['John', 'Jane', 'Barbara', 'Bob'].each do |name|
const_set(name, Person.new)
end
end
# this imports the constants into Main which is the global scope
include MyModule
John
=> #<Person:0x007f973586a618>
Instance variables on the other hand use the # sigil. You can dynamically assign instance variables with instance_variable_set:
['John', 'Jane', 'Barbara', 'Bob'].map(&:downcase).each do |name|
instance_variable_set("##{name}", Person.new)
end
#john
# => #<Person:0x007f9734089530>
While you can declare an instance variable named #John it violates the conventions of the language.
Local variables cannot actually be defined dynamically. You can only change existing variables via eval and binding.local_variable_set.
def foo
a = 1
bind = binding
bind.local_variable_set(:a, 2) # set existing local variable `a'
bind.local_variable_set(:b, 3) # create new local variable `b'
# `b' exists only in binding
p bind.local_variable_get(:a) #=> 2
p bind.local_variable_get(:b) #=> 3
p a #=> 2
p b #=> NameError
end
I'm sure Ruby has some means for you into defining constants dynamically, but I'm not going to bother looking that up because this feels, almost 100%, like something you don't really want to do. It seems like you want some way to associate a "name" to a class instance. That is exactly what Hash is for.
people_names = ['John', 'Jane', 'Barbara', 'Bob']
people = people_names.each_with_object({}) do |name, ppl|
ppl[name] = Person.new(name)
end
people['John'].name # => 'John'
people['Jane'].name # => 'Jane'
Why do I say what you're asking for is probably not what you want? Because use meta programming to dynamically create and dynamically read from local variables/constants/instance variables is just generally frowned upon in professional development. For your own projects, for experimentation, sure maybe. For any project as part of a team though, when you start using meta-programming features to dynamically add these values and reference them (maybe directly, maybe indirectly later) is all well and good but when you try and figure out what's going on you will almost never be able to figure out where these things are defined/coming from unless the array with the dynamic names is hard coded. And if it's hard-coded why can't you just build the constants/variables/targets directly in the code? That's significantly better than dynamically doing it.
# this is a fake API to demonstrate
# let's assume this is what you want
PEOPLE_NAMES = ['John', 'Jane']
PEOPLE_NAMES.each do |name|
const_def(name, Person.new)
end
get_person('Jane').do_something # maps to const_get('Jane').do_something
get_person(PEOPLE_NAMES[0]).do_something
John.do_something
If you want the above, why can't you just do:
John = Person.new
Jane = Person.new
John.do_something
The latter is loads more clear, can still be dynamically looked up, but has a hardcoded definition that can easily be targeted when debugging.
That's my recommendation and answer. I'm pretty sure you don't want to do what you're asking to do. Hash totally fits the needs you desire, it's used heavily for purposes like this and closely related to it, I recommend you try and make that work for your needs then try and figure how to solve the problem you're specifically looking to get an answer too.
EDIT
As a really fun add-on, you can do some really cool dynamic stuff with Hash here that doesn't lead to tons of confusion unless you happen to hide where the hash is coming from. But you could do something like:
people = Hash.new { |h, k| h[k] = Person.new(k) }
# right now, people contains no actual people
people['John'].name # => 'John'
# now people contains one Person instance
This is cool for two reasons 1) You don't have to have a list to generate the hash, so if you get names after hash creation that's fine you can just add them by accessing that users name and 2) Being lazy, it will only use the memory you need. If you preload the hash with all four persons, and then access data from only two persons you wasted the space required for the unused 2 Person instances, so this let's you use only as much as you need and otherwise offers you all the same benefits.
You can certainly do it, although as Brandon says it probably isn't a good idea. Here's how to do it:
people_names.each { |name| eval("#{name} = Person.new")}
eval takes a string passed as an argument and executes it as a line of code. So, you use each to do that once for each member of your array.
You might want to google "eval" to see any number of articles about why it's evil. Many of these go off on metaprogramming (eval is an example of metaprogramming) in general, and make some good points. I have a bit more moderate approach to metaprogramming than that (attr_accessor, after all, is an example of metaprogramming, too, and people use it all the time), but you can certainly write some very tangled code using eval.
Note also, as several posters have observed, that by capitalizing your strings you are defining them as constants. You can change a constant's value in Ruby, but you will get a warning every time you do so.

What is the use of symbols?

I heard that two symbols with the same name create only one memory area, but two strings with the same content create two memory areas.
What is the use of symbols?
Is symbol like a variable? If so, how can I assign a value to a symbol?
If I allocate memory only once for symbols with the same name, what am I doing with the symbols?
Ok, so the misunderstanding probably stems from this:
A symbol is not a variable, it is a value. like 9 is a value that is a number.
A symbol is a value that is kinda of roughly a string... it's just not a string that you can change... and because you can't change it, we can use a shortcut -> all symbols with the same name/value are stored in the same memory-spot (to save space).
You store the symbol into a variable, or use the value somewhere - eg as the key of a hash.... this last is probably one of the most common uses of a symbol.
you make a hash that contains key-value pairs eg:
thing_attrs = {:name => "My thing", :colour => "blue", :size => 6}
thing_attrs[:colour] # 'blue'
In this has - the symbols are the keys you can use any object as a key, but symbols are good to use as they use english words, and are thus easy to understand what you're storing/fetching... much better than, say numbers. Imagine you had:
thing_attrs = {0 => "My thing", 1 => "blue", 2 => 6}
thing_attrs[1] # => "blue"
It would be annoying and hard to remember that attribute 1 is the colour... it's much nicer to give names that you can read when you're reading the code. Thus we have two options: a string, or a symbol.
There would be very little difference between the two. A string is definitely usable eg:
thing_attrs = {"name" => "My thing", "colour" => "blue", "size" => 6}
thing_attrs["colour"] # 'blue'
except that as we know... symbols use less memory. Not a lot less, but enough less that in a large program, over time, you will notice it.
So it has become a ruby-standard to use symbols instead.
A Symbol is the most basic Ruby object you can create. It's just a name and an internal ID. Symbols are useful because a given symbol name refers to the same object throughout a Ruby program. Symbols are more efficient than strings. Two strings with the same contents are two different objects, but for any given name there is only one Symbol object. This can save both time and memory.
# p039symbol.rb
# use the object_id method of class Object
# it returns an integer identifier for an object
puts "string".object_id
puts "string".object_id
puts :symbol.object_id
puts :symbol.object_id
>ruby p039symbol.rb
21066960
21066930
132178
132178
>Exit code: 0
I find it most helpful to think of symbols as strings without all the fancy string features.
Their main use is as the name of other things in your program.
For example, say you have a hash of user information.
You could do
user = { 'name' => 'Tim', 'age' => 20 }
Here the hash keys are strings.
This is fine, but it's really overkill.
Strings have lots of fancy methods like substitution and smart capitalization, and they are mutable (i.e. string objects can be changed in place).
You are never going to change hash keys, so you don't need any of that.
Thus, it's better just to use symbols
user = { :name => 'Tim', :age => 20 }
Another place symbols show up is referring to class methods.
Say I have the following class
class Foo
def initialize(bar)
#bar = bar
end
end
If I need access to the value of #bar from outside of Foo I need to add a getter method to Foo.
That would look like this
class Foo
def initialize(bar)
#bar = bar
end
def bar
bar
end
end
However, this is a pretty common thing to want to do, so ruby provides shorthand as follows
class Foo
attribute_reader :bar
def initialize(bar)
#bar = bar
end
end
This tells Foo to create for us the method we added by hand in the previous version.
As you can see, we refer to the #bar variable using a symbol.
In answer to your second question, no, a symbol is not a variable.
You can't "assign it a value."
However, as you can see, symbols can sometimes be used to refer to variables.

Are these objects? Why do they look like that when I print them?

this is my first post and I'm quite new to programming/this site, so I apologise in advance if I'm doing something wrong/annoying.
I wanted to find a way to define objects without having to do so for each object. I came up with this
class Number
def initialize(name)
#name = name
end
def description
puts "I'm #{#name} "
end
end
a = ["zero", "one","two", "three", "four"]
for i in (0..5) do
a[i] = Number.new(a[i])
end
a[3].description
I'm hoping someone can tell me what kind of Frankensteins monster I've created?
It seems to work, a[3].description returns "I'm three" but does that mean three/a[3] exists as its own object and not an element of an array?
Furthermore if I try to do:
puts a[3]
I get:
<Context::Number:0x000000009b7fd0 #name="three">, #
To clarify I just want to know whether I have actually managed to create objects here, and why on earth when I try and access elements of my array I get that weird feedback (kind of seems like its accessing memory or something, but that is a little beyond me)
My thanks in advance for anyone who replies to this.
All objects stand on their own, regardless of whether they are contained by/in other objects such as Array instances.
Regarding this:
<Context::Number:0x000000009b7fd0 #name="three">, #
...did you mean you get that when you puts a[3] and not puts a?
Every instance of Object and its subclasses has a to_s method that returns a string representation of the object. Since you did not override that in your Number class, it used the default implementation defined in class Object. It is showing you:
1) the class name (I presume you defined Number in side a class or module named Context)
2) the object id (a unique id in the Ruby runtime)
3) the string representation of its instance variable(s)
Also, regarding this:
a = ["zero", "one","two", "three", "four"]
This is equivalent and easier to type (I use 2 spaces for better readability):
%w(zero one two three four)
Also, as Ilya pointed out, map will simplify your code. I'll go a little further and recommend this to do the array initialization:
a = %w(zero one two three four).map { |s| Number.new(s) }
Yes, you have created objects. It's just how Ruby represents a class as a string.
class MyClass
attr_accessor :one, :two
def initialize(one, two)
#one, #two = one, two
end
end
my_class = MyClass.new(1, 2)
my_class.to_s # #<MyClass:0x007fcacb8c7c68>
my_class.inspect # #<MyClass:0x007fcacb8c7c68 #one=1, #two=2>

Why ruby constants are changable? What is the difference between variable?

I was learning ruby, and i learnt that ruby constants must start with a Upper case letter (e.g. Myconstant). This will make it a constant, but its value is changeable!
If a constant's value is changeable then why do we need constant, what is the difference between variable then?
Constants have lexical scoping, whereas methods have dynamic scoping:
class Super
Constant = "Super::Constant"
def method
'Super#method'
end
def get_constant
Constant
end
def get_method
method
end
end
class Sub < Super
Constant = 'Sub::Constant'
def method
'Sub#method'
end
end
Super.new.get_constant # => "Super::Constant"
Sub.new.get_constant # => "Super::Constant"
Super.new.get_method # => "Super#method"
Sub.new.get_method # => "Sub#method"
And as far as variables, they are inaccessible from the outside. How would you intend to access these?
class Object
Constant = 'constant'
local_var = 'local var'
#instance_var = 'instance var'
##class_var = 'class var' # btw, never use these
end
Also, there's a lot of things you can do in Ruby, but for your own sanity, be wary. I'd recommend against changing constants around, it will likely frustrate your team.
Ruby lets you shoot yourself in the foot (if you really want to). But, at least in this case, it warns you about it.
ONE = 'one'
ONE = 'two' # !> already initialized constant ONE
Some reasons:
1) Convention. It's easy to see just from the name of an identifier that it's not supposed to change.
2) Technical. It (probably; someone more knowledgeable than I will probably answer) makes the interpreter simpler.
3) Dynamism is sometimes helpful; in testing, for example, it's possible to redefine things for testing purposes rather than having to stub/proxy everything…
I use this feature sometimes to test out code without otherwise necessary parameters, eg when i run the script from my editor where it is difficult to provide a parameter.
#ARGV[0] = "c:/test.txt" #in case of testing i remove the first remark sign

What's the difference between a string and a symbol in Ruby?

What's the difference between a string and a symbol in Ruby and when should I use one over the other?
The main difference is that multiple symbols representing a single value are identical whereas this is not true with strings. For example:
irb(main):007:0> :test.object_id
=> 83618
irb(main):008:0> :test.object_id
=> 83618
irb(main):009:0> :test.object_id
=> 83618
Those are three references to the symbol :test, which are all the same object.
irb(main):010:0> "test".object_id
=> -605770378
irb(main):011:0> "test".object_id
=> -605779298
irb(main):012:0> "test".object_id
=> -605784948
Those are three references to the string "test", but are all different objects.
This means that using symbols can potentially save a good bit of memory depending on the application. It is also faster to compare symbols for equality since they are the same object, comparing identical strings is much slower since the string values need to be compared instead of just the object ids.
As far as when to use which, I usually use strings for almost everything except things like hash keys where I really want a unique identifier, not a string.
What are the differences between Symbols and Strings?
Symbols are immutable: Their value remains constant.
Multiple uses of the same symbol have the same object ID and are the same object compared to string which will be a different object with unique object ID, everytime.
You can't call any of the String methods like split on Symbols.
From Understanding Differences Between Symbols & Strings in Ruby
If you know Chinese, you can also read 理解 Ruby Symbol.
The statement:
foo = "bar"
creates a new object in memory. If we repeat the statement:
foo = "bar"
We create another object.
To understand it more clearly please try this code in IRB:
foo = "bar"
puts "string #{foo} with object id = #{foo.object_id}"
foo = "bar"
puts "string #{foo} with object id = #{foo.object_id}"
You will get output like:
string bar with object id = 70358547221180
string bar with object id = 70358548927060
which clearly shows there are two different object for the same string. Now if you use a symbol it will create one object per symbol so:
foo = :bar
puts "symbol #{foo} with object id = #{foo.object_id}"
foo = :bar
puts "symbol #{foo} with object id = #{foo.object_id}"
shows:
symbol bar with object id = 7523228
symbol bar with object id = 7523228
which means there is only one object for :bar.
Further, Symbols are immutable and you can't call any of the String methods like upcase or split on Symbols.
Comparing Symbols are faster than comparing Strings. Symbols can be thought of as constant/immutable strings that form a unique set that are effectively converted to memory pointers on the heap. This means comparing two symbols is fast because you are just comparing two integers (memory pointers).
Strings are mutable so the memory pointer to their value on the heap can change after modification. This means comparison operations are slower because duplicates can exist that are semantically equivalent.
Use a symbol when you are sure that the value will remain constant, for example use symbols for hash keys. Use a string when you want to change the value or want to use a string method on it.
An additional difference between String and Symbol is that a String has a lot more methods on it for string manipulation, while a Symbol is a relatively lean object.
Check out the documentation for the String class and the Symbol class.
Case where symbol can be disaster. Lets say you have
params.map(&:to_sym) in your rails controller .
Now here if you are converting the data provided by the user to symbol due to some reason then it could be dangerous. If the data provided by the user is too large and as we know that symbol is not a garbage collector, you might end up exhausting your server's memory which can takedown your website.
There are two main differences between String and Symbol in Ruby.
String is mutable and Symbol is not:
Because the String is mutable, it can be change in somewhere and can lead to the result is not correct.
Symbol is immutable.
String is an Object so it needs memory allocation
puts "abc".object_id # 70322858612020
puts "abc".object_id # 70322846847380
puts "abc".object_id # 70322846815460
In the other hand, Symbol will return the same object:
puts :abc.object_id # 1147868
puts :abc.object_id # 1147868
puts :abc.object_id # 1147868
So the String will take more time to use and to compare than Symbol.
Read "The Difference Between Ruby Symbols and Strings" for more information.
The main difference is that string can have value inside a variable whereas symbol not . For example:
x = "hello"
p x => "hello"
p :x => :x
A symbol is something you use to represent names and strings. You would want to use a symbol when you may have need to use a string several times as this far easier and more productive.
And just found this via google, which may offer greater detail: Here you go
Symbols and strings are completely different this post has a little insight into the differences. As to when and where to use them, there is a pretty extensive post on this subject over on has many :through.
symbol is immutable and string is mutable.
when we perform any operation on string then it create a new object and take memory. As we perform more and more operation on string means we are consuming more and more memory.
symbol is object that are immutable mean if we perform any operation then it performs changes in original object, It will not create any object, that's why it is more profitable.
for more info, you can click here

Resources