coding style: use parameter or instance variable? - coding-style

I often have functions which take a parameter, set an instance variable to that parameter, and then do other things, e.g.:
def updateFoo(self, foo):
self.foo = foo
fooProcessor1(foo)
fooProcessor2(self.foo)
Do you prefer to pass the parameter itself, as in fooProcessor1, or the newly-set instance variable, as in fooProcessor2? Why or why not?

A function named setFoo() really shouldn't do anything more than setting foo unless it is computing and caching a value derived from foo, in which case I would advise something along the lines of:
def setFoo(self, foo):
self.foo = foo
self.__fooUpdated()
def __fooUpdated(self):
# Recompute values derived from foo, dispatch signal to listeners, etc.
Of the options you suggested, I prefer fooProcessor1(foo). That said, it is mostly a matter of personal preference. As long as you are consistent, I don't think it matters all that much.

Coders should be lazy. self. is way too much to type at 1 am.

Related

Why is there no `.split!` in Ruby?

It just seems pretty logical to have it when there's even a downcase!. Has anyone else run into this use case in Ruby?
For the curious, I'm trying to do this:
def some_method(foo)
foo.downcase!.split!(" ")
## do some stuff with foo later. ##
end
some_method("A String like any other")
Instead of this:
def some_method(foo)
foo = foo.downcase.split(" ")
## do some stuff with foo later. ##
end
some_method("A String like any other")
Which isn't a really big deal...but ! just seems cooler.
Why is there no .split! in Ruby?
It just seems pretty logical to have it when there's even a downcase!.
It may be logical, but it is impossible: objects cannot change their class or their identity in Ruby. You may be thinking of Smalltalk's become: which doesn't and cannot exist in Ruby. become: changes the identity of an object and thus can also change its class.
I don't see this "use case" as very important.
The only thing a "bang method" is doing is saving you the trouble of assigning a variable.
The reason "bang methods" are the exception instead of the rule is they can produce confusing results if you don't understand them.
i.e. if you write
a = "string"
def my_upcase(string)
string.upcase!
end
b = my_upcase(a)
then both a and b will have transformed value even if you didn't intend to change a. Removing the exclamation point fixes this example, but if you're using mutable objects such as hashes and arrays you'll have to look out for this in other situations as well.
a = [1,2,3]
def get_last_element(array)
array.pop
end
b = get_last_element(a)
Since Array#pop has side effects, a is now 1,2. It has the last element removed, which might not have been what you intended. You could replace .pop here with [-1] or .last to get rid of the side effect
The exclamation point in a method name is essentially warning you that there are side effects. This is important in the concept of functional programming, which prescribes side effect free code. Ruby is very much a functional programming language by design (although it's very object oriented as well).
If your "use case" boils down to avoiding assigning a variable, that seems like a really minor discomfort.
For a more technical reason, though, see Jorg Mittag's answer. It's impossible to write a method which changes the class of self
this
def some_method(foo)
foo = foo.downcase.split(" ")
end
some_method("A String like any other")
is the same as this
def some_method(foo)
foo.downcase.split
end
some_method("A String like any other")
Actually, both of your methods return the same result. We can look at a few examples of methods that modify the caller.
array.map! return a modified original array
string.upcase! return a modified original string
However,
split modifies the class of the caller, changing a string to an array.
Notice how the above examples only modify the content of the object, instead of changing its class.
This is most likely why there isn't a split! method, although it's pretty easy to define one yourself.
#split creates an array out of a string, you can't permanently mutate(!) the string into being an array. Because the method is creating a new form from the source information(string), the only thing you need to do to make it permanent, is to bind it to a variable.

How to avoid instance variable initializing ugliness

I see this popping up all the time in my code
class Foo
def initialize(foo)
#foo = foo
end
#...
end
This isn't too bad, but it gets worse:
class Foo
def initialize(foo,baz,bar,a,b,c,d)
#foo = foo
#baz = baz
#bar = bar
#etc...
You can sortof get around this by doing something like
#foo, #baz, #bar = foo, baz, bar
But even that feels wrong and is annoying to type. Is there a better way to define instance variables according to arguments?
Edit:
There seem to be 2 distinct solutions to this problem. See:
spickermann's answer
Antarr Byrd's answer
You might want to consider using a Struct:
class Foo < Struct.new(foo,baz,bar,a,b,c,d)
end
foo = Foo.new(1,2,3,4,5,6,7)
foo.bar #=> 2
No need to define an extra initialize method at all...
Yes, that's the preferred way to initialize instance variables in Ruby. It can be annoying to type, but it's a well understood pattern. As always in Ruby, using metaprogramming to automate it away is possible, but will make your code harder to follow.
I'd also argue that it's probably a good thing for a class to look ugly when it's taking more than two or three arguments. If your class depends on six different things to function, it's a strong candidate for refactoring.
def initialize args
#foo, #baz, #bar = *args
end
I think there are 3 ways to make initialization of instance variables shorter:
Use Struct or OpenStruct.
Use ruby's parallel assignment.
Use metaprogramming to make a macro like this.
The fattr gem was recently endorsed on Ruby Tapas to help solve this problem. Another consideration though, is whether there are too many things being passed into the initializer. It could be that this class is doing too much and needs to be broken into smaller pieces.

Can I create an instance of a class using a designated name?

I have already wrote a class in ruby, call it Foo. Now I want to create some instance of it. However, I want to use the value stored in a variable as the name of the instance.
For example, the value of a variable bar is "ABC". Now I want to make the name of the new instance "ABC" as the statement ABC = Foo.new
Can I realize this? If it is possible, please tell me how. Thanks!!!
In Ruby, you should also not be afraid to use eval(), as long as you feed it only data constructed by you, the programmer, without unsafe external influence. In this case,
cocos = "ABC"
class_sym = :Foo
eval "#{cocos} = #{class_sym}.new"
Eval has bad reputation in many languages, but in Ruby, its quite comfortable and basically as fast as static code.
as a local variable, no, but you can use instance_variable_set and friends to name the created objects as instance variables.
You can also use const_set if you are really working with constants:
constant = 'ABC'
Object.const_set constant.to_sym, Foo.new

Redundancy of notation in instance_variable_set, instance_variable_get

When I set or get instance variables using some name, for example #foo, I can do something like:
instance_variable_set("#foo", some_value)
...
instance_variable_get("#foo")
But often, I use a variable for the method name, which does not include the # prefix, so that I end up doing:
method = :foo
...
instance_variable_set("##{method}", some_value)
...
instance_variable_get("##{method}")
But since all instance variables are prefixed with #, I think it redundant to have to type "##{method}" instead of simply typing method. Why are the methods instance_variable_set and instance_variable_get not designed to accept string/symbol without # as its first argument like this:
method = :foo
...
instance_variable_set(method, some_value)
...
instance_variable_get(method)
where the variable to be actually set will be #foo rather than foo?
Is there any advantage with the way it is?
The reason is, quite simply, that the instance variable is named #foo, not foo. The # is part of the variable name, just as the $ is part of the global variable name $foo.
The reason that # is not necessary when calling attr_accessor and friends is because they define attribute methods, so it makes sense to provide the method names, not the variable names.
Of course there is no technical reason instance_variable_set cannot prepend the # itself. However, the method accepts a symbol that corresponds to the variable name. A symbol by definition represents the identifier with the given name. So the only symbol that corresponds to the instance variable #foo is :#foo. That is why you have to include the #, because we know that :foo does not correspond to any instance variable identifier at all. (And if you supply a string, it will be converted to a symbol internally first.)
Update: In the C Ruby implementation (MRI), there is actually no mention of # anywhere in the code that handles instance variables. Only the parser knows instance variables start with a #. So it seems that separating code parsing from implementation is another possible reason.

Why are exclamation marks used in Ruby methods?

In Ruby some methods have a question mark (?) that ask a question like include? that ask if the object in question is included, this then returns a true/false.
But why do some methods have exclamation marks (!) where others don't?
What does it mean?
In general, methods that end in ! indicate that the method will modify the object it's called on. Ruby calls these as "dangerous methods" because they change state that someone else might have a reference to. Here's a simple example for strings:
foo = "A STRING" # a string called foo
foo.downcase! # modifies foo itself
puts foo # prints modified foo
This will output:
a string
In the standard libraries, there are a lot of places you'll see pairs of similarly named methods, one with the ! and one without. The ones without are called "safe methods", and they return a copy of the original with changes applied to the copy, with the callee unchanged. Here's the same example without the !:
foo = "A STRING" # a string called foo
bar = foo.downcase # doesn't modify foo; returns a modified string
puts foo # prints unchanged foo
puts bar # prints newly created bar
This outputs:
A STRING
a string
Keep in mind this is just a convention, but a lot of Ruby classes follow it. It also helps you keep track of what's getting modified in your code.
The exclamation point means many things, and sometimes you can't tell a lot from it other than "this is dangerous, be careful".
As others have said, in standard methods it's often used to indicate a method that causes an object to mutate itself, but not always. Note that many standard methods change their receiver and don't have an exclamation point (pop, shift, clear), and some methods with exclamation points don't change their receiver (exit!). See this article for example.
Other libraries may use it differently. In Rails an exclamation point often means that the method will throw an exception on failure rather than failing silently.
It's a naming convention but many people use it in subtly different ways. In your own code a good rule of thumbs is to use it whenever a method is doing something "dangerous", especially when two methods with the same name exist and one of them is more "dangerous" than the other. "Dangerous" can mean nearly anything though.
This naming convention is lifted from Scheme.
1.3.5 Naming conventions
By convention, the names of procedures
that always return a boolean value
usually end in ``?''. Such procedures
are called predicates.
By convention, the names of procedures
that store values into previously
allocated locations (see section 3.4)
usually end in ``!''. Such procedures
are called mutation procedures. By
convention, the value returned by a
mutation procedure is unspecified.
! typically means that the method acts upon the object instead of returning a result. From the book Programming Ruby:
Methods that are "dangerous," or modify the receiver, might be named with a trailing "!".
It is most accurate to say that methods with a Bang! are the more dangerous or surprising version. There are many methods that mutate without a Bang such as .destroy and in general methods only have bangs where a safer alternative exists in the core lib.
For instance, on Array we have .compact and .compact!, both methods mutate the array, but .compact! returns nil instead of self if there are no nil's in the array, which is more surprising than just returning self.
The only non-mutating method I've found with a bang is Kernel's .exit! which is more surprising than .exit because you cannot catch SystemExit while the process is closing.
Rails and ActiveRecord continues this trend in that it uses bang for more 'surprising' effects like .create! which raises errors on failure.
From themomorohoax.com:
A bang can used in the below ways, in order of my personal preference.
An active record method raises an error if the method does not do
what it says it will.
An active record method saves the record or a method saves an
object (e.g. strip!)
A method does something “extra”, like posts to someplace, or does
some action.
The point is: only use a bang when you’ve really thought about whether
it’s necessary, to save other developers the annoyance of having to
check why you are using a bang.
The bang provides two cues to other developers.
that it’s not necessary to save the object after calling the
method.
when you call the method, the db is going to be changed.
Simple explanation:
foo = "BEST DAY EVER" #assign a string to variable foo.
=> foo.downcase #call method downcase, this is without any exclamation.
"best day ever" #returns the result in downcase, but no change in value of foo.
=> foo #call the variable foo now.
"BEST DAY EVER" #variable is unchanged.
=> foo.downcase! #call destructive version.
=> foo #call the variable foo now.
"best day ever" #variable has been mutated in place.
But if you ever called a method downcase! in the explanation above, foo would change to downcase permanently. downcase! would not return a new string object but replace the string in place, totally changing the foo to downcase.
I suggest you don't use downcase! unless it is totally necessary.
!
I like to think of this as an explosive change that destroys all that has gone before it. Bang or exclamation mark means that you are making a permanent saved change in your code.
If you use for example Ruby's method for global substitutiongsub!the substitution you make is permanent.
Another way you can imagine it, is opening a text file and doing find and replace, followed by saving. ! does the same in your code.
Another useful reminder if you come from the bash world is sed -i has this similar effect of making permanent saved change.
Bottom line: ! methods just change the value of the object they are called upon, whereas a method without ! returns a manipulated value without writing over the object the method was called upon.
Only use ! if you do not plan on needing the original value stored at the variable you called the method on.
I prefer to do something like:
foo = "word"
bar = foo.capitalize
puts bar
OR
foo = "word"
puts foo.capitalize
Instead of
foo = "word"
foo.capitalize!
puts foo
Just in case I would like to access the original value again.
Called "Destructive Methods" They tend to change the original copy of the object you are referring to.
numbers=[1,0,10,5,8]
numbers.collect{|n| puts n*2} # would multiply each number by two
numbers #returns the same original copy
numbers.collect!{|n| puts n*2} # would multiply each number by two and destructs the original copy from the array
numbers # returns [nil,nil,nil,nil,nil]
My answer explains the significance of Ruby methods with exclamation marks/shebangs in the context of Ruby on Rails (RoR) model validations.
Essentially, whenever developers define Model validations (explained here), their ultimate goal is to decline a database record change & raise/throw the relevant exception(s) in case invalid data has been submitted to update the record in question.
RoR ActiveRecord gem defines various model manipulation methods (Ruby on Rails guides.). Among the methods, the valid? method is the only one that triggers validation without database action/modification. The rest of the methods attempt to change the database.
These methods trigger callbacks whenever they run. Some of the methods in the list feature a sister method with a shebang. What is the difference between the two? It has to do with the form of callback returned whenever a record validation fails.
Methods without the exclamation/shebang merely return a boolean false in the event of record validation failure while the methods with a shebang raise/throw an exception which can then be handled appropriately in code.
Just as a heads-up, since I experienced this myself.
In Ruby, ! mutates the object and returns it. Otherwise it will return nil.
So, if you are doing some kind of operations on an array for example, and call the method .compact! and there is nothig to compact, it will return nil.
Example:
arr = [1, 2, 3, nil]
arr.compact!
=> [1, 2, 3]
Run again arr.compact!
=> nil
It is better to explicitly return again the array arr if you need to use it down the line, otherwise you will get the nil value.
Example:
arr = [1, 2, 3]
arr.compact! => nil
arr # to get the value of the array

Resources