Does a getter really not modify an instance variable? - ruby

Saw this on another page:
"with getter, one obtains the current value of #a, without modifying it."
"with setter, one modifies #a, and get its new value as return value."
However, looking at this code from the cancan wiki, I see that both the setter and the getter are actually doing something to the variable in it.
def roles=(roles)
self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0, :+)
end
def roles
ROLES.reject do |r|
((roles_mask || 0) & 2**ROLES.index(r)).zero?
end
end
It looks like the getter is actually returning a truth value, and if not that, at least some sort of transformation. So is this "getters get without modifying, setters set with modifications" rule actually true?

That is the wrong way to think about "getters" and "setters". Instead, think this:
A setter alters the state of an object. It might set a simple instance variable. It might set several instances variables. As in the posted code it might transform the information before saving it.
A getter retrieves some information about the state of the object. It doesn't matter what this is; it could be a value directly stored in an instance variable. Or it could be some other value based upon the current state of the object, as in the post.
It is usually advisable for the getter and setter to take/return the same type of value and affect/report the object state in a consistent way. In the above the exposed type is an "Array of Roles" and it represents the Roles associated with the object.
Using extra named methods can show the intent of the posted code more clearly as the complex bit mask building/consuming expressions can be extracted out; note the symmetry:
def toMaskFromArray (roles)
(roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0, :+)
end
def toArrayFromMask (mask)
ROLES.reject do |r|
((mask || 0) & 2**ROLES.index(r)).zero?
end
end
def roles=(roles)
self.roles_mask = toMaskFromArray(roles)
end
def roles
toArrayFromMask(self.roles_mask)
end

Related

How to create "#property" and "#property=" that are actually methods

Is there were a way to make an #property into a method with set and get, so, #property would call a method instead of returning an actual property, and #property = someval would also call a method instead of assigning to an actual property?
In my project, objects store values in a database. Consider this simple database module that stores records in memory. In my real life project it's a DBM like PostgreSQL:
module MyDB
RECORDS = {}
def self.create(pk)
RECORDS[pk] ||= {}
end
def self.set(pk, key, val)
return RECORDS[pk][key] = val
end
def self.get(pk, key)
return RECORDS[pk][key]
end
end
Objects have fields that are stored in that database. So, in this class, the species field is stored in and retrieved from the database:
class Pet
def initialize(pk)
#pk = pk
MyDB.create(#pk)
end
def species=(val)
MyDB.set #pk, 'breed', val
end
def species()
return MyDB.get(#pk, 'breed')
end
end
A simple use of the Pet class could look like this:
motley = Pet.new('motley')
motley.species = 'cat'
It works currently, but here's where I ran into an annoyance. I did something like this within the class:
def some_method(newval)
#species = newval
end
Then, when I ran the code I got this result:
motley.some_method 'whatever'
puts motley.species #=> cat
Then I realize that wasn't corrent and what I should have done is:
def some_method(newval)
self.species = newval
end
I think #species = newval makes sense. It feels like I'm setting a property of the object.
Is were a way to assign a method to the property, something like:
def :#species=(val)
return MyDB.set(#pk, 'breed', 'val')
end
def :#species
return MyDB.get(#pk, 'breed')
end
Is there a way to do such a thing? Should there be?
Is there a way to do such a thing?
No. In Ruby setter and getter methods are the way to get/set the internal state of an object. Instance variables are just lexical variables that are scoped to an instance.
Ruby is a language based on message passing and #foo = bar sends the message =, bar to the recipient that is the lexical variable #foo. If it called self##foo= instead that would break the entire model of the language.
Should there be?
Hell no.
Do we really need a completely new language feature just because you find it hard to remember to call self.foo= instead of #foo =? No.
Would this feature add anything to the language that cannot already be done? No.
Would it break existing code? Yes.

Understanding use case of instance variable and local variable

Suppose I have a user class as below
class User
def initialize
test
end
def test
name = ['name1','name2', 'name3']
returned_value = test1(name)
lots of if else condition based on returned_value
end
def test1(name)
test2(name)
end
def test2(name)
test3(name)
end
def test3(name)
end
end
And this user class has some methods like test, test1.. and each method do some calculation one single array and then return the array. Now based on the returned value test method add or delete elements from the array. This become very ugly with lot of if else condition because returned value could be blank, one element, two dimensional array and so one.
But if I use an instance variable then I don't have to return any value and so I don't need any if else statement based on the returned value and my code looks clean. For example
class User
def initialize
#name = ['name1','name2', 'name3']
test
end
def test
test1
end
def test1
test2
end
def test2
test3
end
def test3
end
end
My question is, should I use instance variable or not in this case? An explanation would be nice.
Update:
In short it would be, I want to manipulate one single array in different methods of a Class. Now, I can create the array inside test method and then pass it to other methods (first case in my above example) or I can create the array in initialize method and then I don't have to pass the array every time(second case in my example above). So my questions is
Is my first/second approach is bad/okay? Or both approach is okay to use?
If you have data that needs to be accessible to many methods in a class, then instance variables is a good way to manage that.
I generally use instance variables in PORO classes for two reasons
To store information, usually at initialization, that many of the
class methods need access to. This is what you're asking about
above.
To memoize resource intensive methods.
For example to avoid doing an api call every time I access customer_data I would replace
def customer_data
HTTParty.get... (some api call)
end
with
def customer_data
#customer_data ||= HTTParty.get... (some api call)
end
#customer_data is only used within that method, but if I call the method multiple times only one api call is needed. This assumes (of course) that for a given class object there is only one associated customer.

Copy object without any pointers in Ruby

I am trying to write a Greedy Algorithm for a certain problem. Simplified it looks like this:
There's an object called Foo with an randomized attribute called value and a method that changes this value change_value in a way that depends on an integer input
class Foo
def initialize
value = rand(1,10)
end
def change_value(input)
#changes the value in a certain way
end
end
Now the Greedy Algorithmus just gets the new value of Foo for all possible inputs and return the best input.
foo = Foo.new
best_value = 0
best_input = 0
(1..inputs).each do |k|
temp_foo = foo.clone
temp_foo.change_value(k)
if temp_foo.value>best_value
best_value = temp_foo.value
best_input = k
end
end
Foo.change_value(best_input)
The code works nearly as intended. The big problem is that the change_value-method within the each-funtion alters the temp_foo and the foo. What do I need to change to makes those objects completly dependent of each other? I also tried .dub by the way.
I think #clone or #dup won't work because they will share a reference to #value inside Foo.
In any case, you can do it more readably by changing Foo#change_value so it doesn't actually mutate the object but returns a copy:
class Foo
def initialize(value = nil)
#value = value || rand(10)
end
def change_value(input)
# returns a new Foo instance
Foo.new(#value + 1)
end
def value
#value
end
end
Because you're copying data in any case, using an immutable object (Value Object) is more general than some kind of deep clone.
I assume you assign value to the instance variable #value in Foo#initialize not the local variable value.
I also assume you don't have a simple primitive like in your code above but rather another object that contains a pointer, otherwise you most probably would not have such problem. In other words, I assume your change_value method makes an operation that relies on the #value pointer, such as #value[key] = some_new_value and not pure assignment, such as #value = some_new_object. When your object gets copied with clone or dup, that particular pointer is being copied, instead of the underlying structure, and therefore any calls to temp_foo.change_value will result in changes to foo's underlying #value.
To avoid this, you need to duplicate the object #value refers to. There is a trick you can use with Marshal, as discussed in this post, but I recommend against it since it causes a great deal of overhead. Instead, I would define a deep_dup method, such as below:
class Foo
def deep_dup
# Either this
#value = #value.dup
# OR this, and define the method #deep_dup in the class of #value
# to dup its internal structure too:
#value = #value.deep_dup
end
end
Then instead of doing temp_foo = foo.clone do temp_foo = foo.deep_dup.

Return containing object instance in ruby

I'm trying to implement a funky version of method chaining. Returning the instance of the class after each function call is easy, you just do
def chainable_method
some_code()
self
end
My idea is that the methods you can call depend on the previous method call. I'm trying to achieve this by returning an object belonging to the containing object. The contained object will have a few special methods, and then implement method_missing to return the containing object's instance.
Edit: The child object has some state associated with it that should be in itself, and not the parent. It might not have been clear previously as to why I need a whole instance for just method calls.
super is irrelevant in this case because the contained object doesn't inherit from the containing object, and I wouldn't want to call the containing object's methods on the contained object anyway - I want to call the containing object's methods on the containing object itself. I want the containing object, not the containing object class.
Not sure if this is possible.
Edit: reworded everything to use "containing/contained object" instead of the completely incorrect parent/child object.
Also, I'm using 1.9.3, if that matters. Version isn't important, I can change if needed.
My explanation was probably unclear. Here's the code:
class AliasableString
def initialize(string)
#string = string
end
def as(aka)
#aka = aka
end
def has_aka?
!#aka.nil?
end
# alias is a reserved word
def aka
#aka
end
def to_s
#string + (self.has_aka? ? (" as " + #aka) : "")
end
end
class Query
def initialize
#select_statements = Array.new
end
def select(statement)
select_statement = AliasableString.new(statement)
#select_statements.push(select_statement)
select_statement
end
def print
if #select_statements.size != 0
puts "select"
#select_statements.each_with_index {| select, i|
puts select
}
end
end
end
# Example usage
q0 = Query.new
q0.select("This is a select statement")
.select("Here's another one")
.as("But this one has an alias")
.select("This should be passed on to the parent!")
q0.print
I haven't yet fully implemented print. AliasableString needs to have #string and #aka separate so I can pull them apart later.
First of all, it doesn't matter what class of object is contained within a Query instance. All of the syntax shown on your 'example usage' section is appropriately defined in Query. The only requirement of the objects contained within a query instance is that they respond to as (or some similar method). What you have here is something like a state machine, but the only state that really matters is that some object occupies the last position in the select_statements array. Here's how I would build this (again, based mostly on your example at the end, I'm afraid I can't quite follow your initial explanation):
class Query
# ... initialize, etc.
def select(statement, statement_class = AliasableString)
select_statements << statement_class.new(statement)
self
end
def as(aka)
# this will only ever be used on the most recent statement added
statement_to_alias = select_statements.last
# throw an error if select_statements is empty (i.e., :last returns nil)
raise 'You must add a statement first' unless statement_to_alias
# forward the message on to the statement
statement_to_alias.as(aka)
# return the query object again to permit further chaining
self
end
end
AliasableString doesn't need to know a thing about Query; all it needs to do is respond appropriately to as.

Trying to learn / understand Ruby setter and getter methods

I'm just learning to program and have decided to try Ruby. I'm sure this is a stupid question, but the instructor is talking about setter and getter methods, and I'm confused. Here is the example:
class Human
def noise=(noise)
#noise = noise
end
def noise
#noise
end
end
From this, the class is instantiated, and I can puts this out:
man = Human.new
man.noise=("Howdie!")
puts man.noise
This results in Howdie!
Now what confuses me is that the instructor is saying without the getter method (the 2nd of the two methods), there is no way to interact with the instance variable #noise.
But when I remove the getter method, I'm able to still access #noise, see example:
class Human
def noise=(noise)
#noise = noise
end
end
man = Human.new
puts man.noise=("Howdie!")
This works the same as when the getter method it used.
So now I'm confused. Why is the getter needed? What does the instructor mean by not being able to access the instance variable without it? Is it possible he's using an older version of Ruby?
Thanks in advance for your help.
You can interact with that instance variable from other methods belonging to that instance, even if there is no getter:
def noise=(noise)
#noise = noise
end
def last_noise
#noise
end
There doesn't need to be a getter defined with the same name as the method; the two are not linked at all. The getter is needed to "get" the value of the instance variable, but only in a short syntax.
What's happening in your example is that you're initializing a new object (Human.new), and then using a method (noise=, yes the method name contains the = symbol) that just-so-happens to define an instance variable (that is, a variable just for that instance), and then finally retrieving that instance variable with another method call.
You can actually use instance_variable_get to get the instance variable without defining any getter at all:
man = Human.new
man.noise = "Howdie"
man.instance_variable_get("#noise")
This will return "Howdie", even though there is no getter defined.
And no, I don't think he's using an older version of Ruby.
The line of code
puts man.noise=("Howdie!")
does NOT use the getter method, so the getter method does not need to be defined for it to work. That line just uses the setter method. The return value of the setter method is automatically equal to whatever is on the right-hand side of the equal sign, so "Howdie!" gets passed to puts.
The line of code
puts man.noise
DOES use the getter method, and it would not work if you remove the getter method.
Surely they both return a value, but their behavior are different.
Let's say there is already a member #a .
with getter, one obtains the current value of #a, without modifying it.
with setter, one modifies #a, and get its new value as return value.
when thinking about behavior of setter, note:
the old value of #a can not be obtained with setter, and got overwritten.
what returned by setter, is actually already known before invoking setter.
May be the attention for getters and setters is because some other languages allow you to access class variables directly. Python:
class k:
i = 100
print k.i # 100
k.i = 200
print k.i # 200
In contrast, Ruby keeps all of its variables completely private to the class and only exposes them through accessor methods.
In your example, if you remove the getter, you can indeed interact with the variable (that is: change it) trough the setter, but you can't get it back (in a regular way) when you need it.

Resources