0

For example:

def recurse(value)
  if value < 5
    self.send(__method__, value + 1)
  else
    value
  end
end

This works, but it's a bit ugly.

Basically I'm looking for a prettier way to call the currently executing method, without referring to it explicitly by name.

If there is a less-cryptic syntax for this, I would probably use it (to avoid the name duplication, reduce effort required for renaming a function, etc). If there isn't a nicer syntax for this, I'll just hard-code the name like normal.

Daniel Wyatt
  • 379
  • 3
  • 7
  • Possible duplicate of [Get the name of the currently executing method](http://stackoverflow.com/questions/199527/get-the-name-of-the-currently-executing-method) – Sagar Pandya Apr 09 '17 at 03:24
  • 4
    I think your solution reads quite nicely. As a side note, you can omit both `return`s and you should use 2 spaces for indentation. – Sagar Pandya Apr 09 '17 at 04:19
  • 1
    A lot of the time a recursive approach to something isn't nearly as concise or effective as an iterative one. Ruby's Enumerable library offers considerably more functionality than most and can work wonders on lists. In many cases recursive things can be expressed as a series of list transformations. – tadman Apr 09 '17 at 06:28
  • 3
    Why do you want to do that? The only advantage I can see of your code over code that uses the method name (`recurse`) explicitly is that you can change the method name without changing the body of the method. However, using the method name results in simpler and more readable code, informing the reader in an instant that the method is recursive. – Cary Swoveland Apr 09 '17 at 06:41
  • 5
    Note that `send(__method__, ...)` isn't recognized by tail call optimization. – Stefan Apr 09 '17 at 13:15
  • @tadman A recursive approach makes sense for the real-life code, though it's obviously silly for the example I used. The example is just for demonstration. – Daniel Wyatt Apr 09 '17 at 15:43
  • 1
    @EricDuminil I'm sorry but your answer doesn't answer anything at all. – Daniel Wyatt Apr 09 '17 at 15:57
  • @Stefan One of the few good points in here, thanks for pointing that out. – Daniel Wyatt Apr 09 '17 at 15:57
  • @EricDuminil This question isn't about justifying the use of recursion. The question is "I'm looking for a prettier way to call the currently executing method, without referring to it explicitly by name." – Daniel Wyatt Apr 09 '17 at 16:15
  • Please take a good look at this [answer about the XY problem](https://meta.stackexchange.com/a/66378). – Eric Duminil Apr 09 '17 at 16:25
  • 1
    I do not think that this is an exact duplicate of the nominated exemplar. That question is about how to get the name of the current method; this question is about how to call the current method. – Wayne Conrad Apr 09 '17 at 17:05

2 Answers2

2

It's a comment rather, as @sagarpandya82 mentioned, you can omit some redundant parts and use both variants. I would refactor it a bit:

def recurse(value)
  return value unless value < 5 # return value if value >= 5
  send(__method__, value + 1) # or just recurse(value + 1)
end

Non-recursion version with a block:

def non_recurse(value)
  if value >= 5
    yield value
  else 
    (value..5).each do |i|
      yield i
    end
  end
end
non_recurse(3) {|i| puts i}
#=> 3, 4, 5
non_recurse(6) {|i| puts i}
#=> 6
Ilya
  • 13,337
  • 5
  • 37
  • 53
  • Technically true, but seeing this in production code would make me question the intentions of the author. Many recursive algorithms are already complicated beasts, and this adds more confusion. – tadman Apr 09 '17 at 06:20
  • 2
    @tadman, I agree about a production environment but seems like the author is learning this programming feature. Anyway almost in all cases in Ruby iteration is better then recursion. – Ilya Apr 09 '17 at 08:34
  • Can you add an iterative alternative to your answer. thanks – Sagar Pandya Apr 09 '17 at 08:59
1

If you really want to use __method__, your method is correct and reasonably readable. To comply with usual Ruby guidelines, you could just remove returns and use 2 spaces as indent (as mentioned by @sagarpandya82 in the comments):

def recurse(value)
  if value < 5
    self.send(__method__, value + 1)
  else
    value
  end
end

I don't see any reason to use self.send(__method__) here, so you could write :

def recurse(value)
  if value < 5
    recurse(value + 1)
  else
    value
  end
end

Actually, I'd say that you don't need recursion at all. All your method does is to keep adding 1 to the value until it reaches 5. If the value is bigger than 5, it returns the value :

For integers:

def no_recurse(value)
  [value, 5].max
end

no_recurse(4)
# 5
no_recurse(-3)
# 5
no_recurse(7)
# 7
no_recurse(-2**1000)
# 5
no_recurse(4.5)
# 5 # <- That's wrong

For floats, you'd just need to add the decimal part to 5. This will work for any number:

def no_recurse(value)
  [value, 5 + value % 1].max
end

no_recurse(4.5)
# 5.5
no_recurse(5.5)
# 5.5
no_recurse(6)
# 6
no_recurse(-7)
# 5
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124