I was reading an article on meta-programming and it showed that you can define a method within another method. This is something that I had known for a while, but it made me ask myself the question: does this have any practical application? Is there any real life uses of defining a method within a method?
Ex:
def outer_method
def inner_method
# ...
end
# ...
end
In short: no, Ruby does not support nested methods.
Java does not support “directly” nested methods. Many functional programming languages support method within method. But you can achieve nested method functionality in Java 7 or older version by define local classes, class within method so this does compile.
Methods are time savers and help the user to reuse the code without retyping the code. Defining & Calling the method: In Ruby, the method defines with the help of def keyword followed by method_name and end with end keyword. A method must be defined before calling and the name of the method should be in lowercase.
The Method class in Ruby has a source_location function that returns the location of the method's source code - file and line number where the method starts. Then method_source essentially opens that file, finds the respective line, looks for end that will end the method and returns the code in between.
My favorite metaprogramming example like this is dynamically building a method that you're then going to use in a loop. For example, I have a query-engine I wrote in Ruby, and one of its operations is filtering. There are a bunch of different forms of filters (substring, equals, <=, >=, intersections, etc.). The naive approach is like this:
def process_filter(working_set,filter_type,filter_value)
working_set.select do |item|
case filter_spec
when "substring"
item.include?(filter_value)
when "equals"
item == filter_value
when "<="
item <= filter_value
...
end
end
end
But if your working sets can get large, you're doing this big case statement 1000s or 1000000s of times for each operation even though it's going to take the same branch on every iteration. In my case the logic is much more involved than just a case statement, so the overhead is even worse. Instead, you can do it like this:
def process_filter(working_set,filter_type,filter_value)
case filter_spec
when "substring"
def do_filter(item,filter_value)
item.include?(filter_value)
end
when "equals"
def do_filter(item,filter_value)
item == filter_value
end
when "<="
def do_filter(item,filter_value)
item <= filter_value
end
...
end
working_set.select {|item| do_filter(item,filter_value)}
end
Now the one-time branching is done once, up front, and the resulting single-purpose function is the one used in the inner loop.
In fact, my real example does three levels of this, as there are variations in the interpretation of both the working set and the filter value, not just the form of the actual test. So I build an item-prep function and a filter-value-prep function, and then build a do_filter function that uses those.
(And I actually use lambdas, not defs.)
Yes, there are. In fact, I'll bet you use at least one method that defines another method every day: attr_accessor
. If you use Rails, there are a ton more in constant use, such as belongs_to
and has_many
. It's also generally useful for AOP-style constructs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With