This is the most relevant use of `to_s` in this class indeed. One could imagine additional methods like:
def bump_minor
self.class.new(major, minor + 1, patch)
end
(although I'm not sure why it would be useful in that particular case, it's just an example of how you can build new objects out of existing ones without having to mutate them)
Yes, to_s returns the string representation of an object.
I think it's a safety measure in case the argument passed in is not a string, but can be turned into a string. Safe to assume that calling "to_s" on a string just returns the string.
Ruby is a dynamic language, `version_string` can be anything. The author uses `to_s` to coerce it into a string. There are problems with that: if I pass in an array it'll coerce into `"[1,2,3]".split(".").map(&:to_i)`, which makes no sense.
Most times it's better to just accept the dynamic nature of the language rather than do this kind of runtime type checking. You'd have to do this `.is_a?` dance for every type to have it be reliable.
Even if you implement an "interface" (duck typing) with `respond_to?(:to_app_version)` you still can't be sure that the return type of this `:to_app_version` is actually a string you can call `split()` on.
it is a string usually but could be called with a single number or some other object that has that method overwritten and it would still do the right thing.