Support functional programming: forbid instance/class variables for ModuleName::method_name, allow for ModuleName.method_name
What would you say about this proposal? Is there a better alternative?
I suggest to support functional programming in Ruby by making module methods called with
ModuleName::method_name syntax raise an exception if the method uses instance or class variables (instance variables of the singleton class, of course).
If i understand correctly, currently
ModuleName.method_name behave identically, so i propose that they be different:
module M module_function def f(x) x*x end def g(x) @x ||= x @x*@x end end M.f(2) # => 4 M.g(2) # => 4 M::f(3) # => 9 M::g(3) # => Error: instance variable `@x` used in a functional call `M::g`
M.f(2) # => 4 M.g(2) # => 4 M::f(3) # => 9 M::g(3) # => 4
#1 [ruby-core:46830] Updated by alexeymuranov (Alexey Muranov) about 6 years ago
I think that if you tell a new person that
M.f are the same in Ruby, they won't believe at first. So why keeping them the same?
I do not know how to be with the use of global variables in
M::f. I imagine there are other details to discuss.
This feature wouldn't ensure truly functional programming, but i hope it can introduce a "good practice" of making it clear from the call syntax if a method can change the state of the object. In other words, i propose that when
x::f(y) is called, the state of the object
x be frozen, and unfrozen after the return from
x act simply as a namespace.
I do not know whether it would be better for
x::f to allow read-only access to the state of
x, or no access at all. Probably read-only access makes better sense, given impossibility to exclude interaction with other data anyway.
Another approach could be to forbid a function called with
:: prefix to change the state of any object that is not created by it, and to forbid to read the state of any object that is not accessible through the state of
self or the state of one of the arguments.
If the feature is implemented with read-only access to any existing data, this syntax can be used to give a precise meaning to non-exclaiming methods:
a::map instead of
a.map! stays as is.
To determine what objects are "accessible" through the state of a given object, i think it should be forbidden to go "up" with methods like "#class" or "#superclass" and then go "down". In the direction "up", only the object's class and its ancestors should be accessible, i think.
#3 [ruby-core:63432] Updated by alexeymuranov (Alexey Muranov) over 4 years ago
Besides functional programming, IMO this would support [command–query separation](https://en.wikipedia.org/wiki/Command–query_separation).
#5 [ruby-core:63434] Updated by alexeymuranov (Alexey Muranov) over 4 years ago
I meant that a function called like
Math::sin would be required to return same values (for same arguments) every time. Maybe i did not explain this well.
Foo.bar, on the other hand, would not have this restriction.
Same could be generalized to mutable (non-constant) objects, but there the distinction could be harder to make. Maybe
P.S. Thanks for reformatting the proposal.