Why does Rubocop / the community-driven Ruby style guide recommend parentheses in method definitions?
def my_method(param1, param2)
end
# instead of
def my_method param1, param2
end
Method calls are allowed with or without parentheses depending on the situation. However, my first impression is that lack of parentheses in method calls are much more potentially ambiguous than lack of parentheses in method definitions. Was there a reason behind it, e.g. to make code more fool-proof, or did it happen because of "historical reasons" or "because it was the most widespread style"?
Clarification:
I am not asking for opinions about which style is easier to read.
The lint Lint/AmbiguousOperator is based on the idea that do_something *some_array is ambiguous and a source for bugs (Link). I wondered if this is the same case for Style/MethodDefParentheses (Link).
After going back to find the actual names of those Cops, my best guess right now is that there is no "technical" reason, but rather one is a proper "lint" and the other a "style" matter.
The rationale is omitted in the initial commit, of which this rule was part, indicating that there was no particular technical reason for it.
The fact that the corresponding cop is placed in the Style department, rather than Lint, serves as further proof that this is a matter of just that, style.
Method definitions have a very simple syntax. The def keyword is (optionally) followed by arguments, which must be followed by a terminator (newline or ;).
The possible variations are:
single line method definitions,
inline modifiers, e.g. private,
default- and keyword arguments,
splat- and block arguments.
All of these work fine both with and without parentheses. Furthermore, running a file with an unparenthesized method definition using the -w flag raises no warnings.
These factors together rule out the possibility that the parentheses are recommended to avoid ambiguity.
Related
Obviously, it is a convention in Racket/Scheme to append an exclamation point to function names that perform mutation. For example, in Racket, set!, box-set!, vector-set!, etc. Certain functions have side-effects, like print, but since those side-effects are "harmless," I understand why they don't usually come with exclamation marks attached.
However, this convention is arbitrarily violated. For example, async-channel-get and async-channel-put clearly perform mutation, but they don't have the "mutation marker" appended to their names. This can be somewhat justified by pointing out that these are channels, clearly mutation-based, so the "!" would be superfluous.
This is not a valid justification for everything, though. Racket's WebSockets library provides ws-send! and ws-close! functions, both with the obvious markers, but ws-recv does not! Is this just an isolated violation of the convention, or is there some rule?
I ask this mostly to be sure of how I should name functions in my own code. When should I use the exclamation mark, when should I not? I recognize that it's just a convention, not a rule, and it will likely be somewhat inconsistent, but I still would like to know what the best practices are.
I don't think #!racket has its own naming convention, but according to this R5RS page you can read:
The names of procedures and syntactic forms that cause side effects
end with an exclamation point ( ! ). These include set! and
vector-set!. Procedures that perform input or output technically cause
side effects, but their names are exceptions to this rule.
In the Scheme wiki variable naming convention it says procedure! is for "significant side effects". IMO that means the side effects is the hero of the procedure as in set-car! and set! while read returns a value which perhaps is the main feature of read?
I was running rubocop on my project and fixing the complaints it raised.
One particular complaint bothered me
Do not prefix reader method names with get_
I could not understand much from this complaint so I looked at source code in github.
I found this snippet
def bad_reader_name?(method_name, args)
method_name.start_with?('get_') && args.to_a.empty?
end
def bad_writer_name?(method_name, args)
method_name.start_with?('set_') && args.to_a.one?
end
So the advice or convention is as follows:
1) Actually they advice us not to use get_ when the method does not have arguments . otherwise they allow get_
2) And they advice us not to use set_ when the method has only one argument .otherwise they allow set_
What is the reason behind this convention or rule or advice?
I think the point here is ruby devs prefer to always think of methods as getters since they returns something and use the equals "syntactic sugar" (like in def self.dog=(params) which lets you do Class.dog = something). In essence the point I've always seen made is that the get and set are redundant and verbose.
In opposition to this you have get and set with multiple args which are like finder methods (particularly get; think of ActiveRecord's where).
Keep in mind that 'style guide' = pure opinion. Consistency is the higher goal of style guides in general so unless something is arguably wrong or difficult to read, your goal should be more on having everything the same than of a certain type. Which is why rubocop let's you turn this off.
Another way to see it: the getter/setter paradigm was, as far as I can tell, largely a specific convention in Java/C++ etc.; at least I knew quite a few Java codebases in the very foggy past where Beans were littered with huge amounts of get_-getters and set_-setters. In that time, the private attribute would likely be called "name" with "set_name()" and "get_name()"; as the attribute itself was called "name", the getter could not be "name()" as well.
Hence the very existence of "get_" and "set_" is due to a (trivial) technical shortcoming of languages that do not allow the "=" in method names.
In Ruby, we have quite a different array of possibilities:
First and foremost, we have name() and name=(), which immediately removes the need for the get_ and set_ syntax. So, we do have getters and setters, we just call them differently from Java.
Also, the attribute then is not name but #name, hence solving this conflict as well.
Actually, you don't have attributes with the plain "obj.name" syntax at all! For eaxmple; while Rails/ActiveRecord pretends that "person.name" is a "attribute", it is in fact simply a pair of auto-generated getter name() and setter name=(). Conceptionally, the caller is not supposed to care about what "name" is (attribute or method), it is an implementation detail of the class.
It saves 4 or 3 key presses for each call. This might seem like a joke, but writing concise yet easily comprehensible code is a trademark of Ruby, after all. :-)
The way I understand it is that it's because foo.get_value is imperative and foo.value is declarative.
For example, array.pop doesn't need a bang to permanently alter the array. Why is this so and what was the reasoning behind developing these certain Ruby methods without this conformity?
Bang methods are most commonly used to distinguish between a dangerous and a safe version of the same method. Here are some example cases that one might want to distinguish with a bang/no-bang combination:
mutator methods - one version changes the object, the other one returns a copy and leaves the original object unchanged
when encountering an error, one version throws an exception while the other one only writes an error message to the log or does nothing
However, the convention is to leave the bang off if there is only one version that makes sense. For example, poping an array without actually changing it makes no sense. In this case, it would end up being a different operation: Array#last. A lot of methods change the object they are called on, for example setters. We don't need to write these with a bang either, because it's clear that they change the object.
Lastly, there are a few exceptions to this, where some developers might use a bang method without implementing a bang-less counterpart. In these cases, the bang is simply used as a way to making the method calls stand out visually. For example:
the method does something dangerous or destructive
the method does something unexpected
the method has a significant performance impact
The bang is used to distinguish between a dangerous and less dangerous version of the same method. There is only one pop method, so there is nothing to distinguish.
Note: the name of the method has absolutely nothing whatsoever to do with what it does. Whether a method is destructive or not depends on what code it executes, not what name it has.
A suffix of ! means that a method is a dangerous version of another method. For example, save! is the dangerous version of save. Dangerous could mean editing in place, doing something with more strict errors, etc. It is not required to use the ! suffix on a method that is dangerous, but doesn't need a safer counterpart. Additionally, this is just a naming convention, so Ruby does not restrict what you can and can't do if a method does or doesn't end with !.
There is a common misconception that every method that edits something in place should end with !. This is not true, ! is only needed when there is a more dangerous version of a method that already exists, and this does not necessarily mean that the dangerous method edits in place. For example, in Rails, ActiveRecord::Base#save! is a version of ActiveRecord::Base#save that performs validations.
The meaning of bang in Ruby is "caution". It means you should use the method with caution, nothing more. I cannot find the reference anymore, but people of authority said explicitly that bang ≠ destructive method. Bang is just a semantic element associated with caution. It is up to the programmer to weigh in everything and decide when to use bang.
For example, in my simulation gem, I use #step method to obtain the step size.
simulation.step #=> 0.42
and step! method to actually perform the simulation step.
simulation.step! #=> takes the simulation to the next time step
But as for #reset method, I decided that the word "reset" it's verbose enough and it is not necessary to use bang to warn the user that the simulation state will be destroyed:
simulation.reset #=> resets the simulation back to the initial state
P.S.: Now I remember, once upon a time, Matz said half jokingly that he regrets introducing methods with bang into Ruby at all, because bang is semantically so ambiguous.
In Ruby, there is a convention to have a method name end with a question mark to indicate that its return value is boolean. Why is boolean considered so special? Is there anything convenient if you know that a method's return value is particularly boolean? After all, in Ruby, you can insert all kinds of value returning (getter) methods into a conditional without caring whether it is boolean or not.
I think it is a waste to use the question mark just for indicating a boolean value. There should be more useful uses. I have plenty of use case where I want to have a pair of getter and setter methods, where the setter method should return self so that I can use it in a method chain. And naming them something like get_foo and set_foo looks cumbersome. Rather than following the convention, I am tempted to name a pair of getter and setter methods like this:
def foo?; #foo end
def foo v; #foo = v end
where the value of #foo is not (necessarily) boolean. (Besides potential criticism that breaking the convention will confuse other programmers), is there something wrong with doing that?
There is nothing special at all, it's just a convention. A question can be answered with "yes" or "no", but also with another stuff like someone's name.
By returning a boolean on methods with a question mark, it indicates it to be an explicit behavior.
If you make the answer be "yes" or "no", it's easy for the reader of your code to identify the behavior of your method without even looking at the implementation. On the other hand, if you make it return any other type, it is more difficult for the reader to understand your code without reading your class and method definition.
With a boolean there are only two possible answers. If the return value is not boolean it can be anything, which would not help at all. You would still need to look at the method implementation. You should always look further to understand some piece of code, but using this convention makes it simpler.
There is a convention to use question mark in method names to indicate that a method is a predicate. AFAIK, this predicate is not required (by the convention) to return a boolean value, thanks to simple rules for truthy/falsey values.
Besides potential criticism that breaking the convention will confuse other programmers, is there something wrong with doing that?
Confusing and surprising fellow programmers is bad. Ruby couldn't care less. It's just a convention. And conventions exist for a reason.
You can put anything in a flow control construct, but semantically booleans are appropriate. "If" in real human language typically takes a boolean, and the same is true of the construct in many programming languages. Ruby likes to make things convenient and assigns a "truthiness" value to everything in the language, which affects how it behaves in a boolean context.
In other words, booleans are the only things that are almost exclusively used for flow control, so the convention is to make them look "right" for flow-control constructs. It's their native environment.
(Besides potential criticism that breaking the convention will confuse other programmers), is there something wrong with doing that?
In the same sense that there is nothing wrong with naming all your variables after 1920s comedians, no, there's nothing wrong with that. But also in the same sense as naming all your variables after 1920s comedians, it isn't a very good idea. Nowhere in any language that I know of -- human or computer -- does the question mark mean "get." So the semantics of your code are off with that convention.
This question and the answers boil down to "POLS" AKA "Principle of Least Surprise".
A method name can be a random choice of letters and numbers separated by underscores, with '!', '?' and '=' sprinkled through them, if we chose to do so. They could be randomly created by the code at run time, and, as long as the rest of the code used the same arrangement of characters, the program would run and Ruby would be happy.
We humans, the programmers, determine the name of the methods used, to represent something, a characteristic or an action. Trying to use randomly named methods would lead to madness, or at least a very hard to maintain program. So, instead, we try to use sensible names for things. Sometimes they're verbs or adjectives, sometimes they're more descriptive because the method does several things.
As part of that naming, sometimes we want to provide additional hints about the behavior of the method. By convention in Ruby, we use "!" to warn the coder that the method changes something or is destructive. "=" indicates the method takes a parameter and assigns it to the receiver/object. It's a setter method and in many other languages it'd be idiomatic to use "set_flag..." or "set_value..." as the name. It's just a convention in that language, and followed by developers in the language.
We use "?" in Ruby to ask a question about an object, whether it is, or isn't, true about that object. We could say "is_true?" or "true?" and indicate we are testing whether something is true about it. If it's true, or false, it's a Boolean response so we return a true/false value.
I want to know it real meaning of it and how to use it exactly.
Another question is about assert I saw
assert product.valid? product.errors.full_messages
and
assert product.valid?
But I can't find syntax for those assert what does second arg for assert (product.errors.full_messages) means or it is arg for ?
Thanks
Ruby uses specific naming conventions for methods. It allows you to quickly identify the side effects they may have, or the return type..
These conventions use special markers such as "!" and "?" at the end of method names. This is uncommon since most programming languages tend to forbid such characters in identifiers, but nevertheless, it is truly part of the method name. (and should not be confused with operators)
Post fixing "?" means that the method returns a boolean. It's a convenient way to replace the "is" prefix. (this convention tends to exist in lisp dialects too)
Post fixing "!" means that the method will modify the instance, and thus won't act on/return a copy.
Note that these are just conventions. In no way you have to follow it, but it is considered a good practice.
It is purely a convention, it has no formal meaning. It isn't unusual for people to get confused by this, since many (most?) languages don't allow characters such as ? and ! in identifiers.
It's just convention to put it on a method that returns a boolean afaik. Rather than making everythign IsSomething.