0

Let me preface this by saying I am very new to Ruby. I am going through couple exercises writing my own versions of some enumerable functions. Everything was working fine until it kinda just stopped working. I don't think I changed anything. I have function that looks as follows:

def my_all?
    return false unless block_given?
    for i in self
        if !yield(i)
            return false
        end
    end
    return true
end

and I call it as follows:

arr = [1,2,3,4]
print arr.my_all? do |num|
    num == num
end

This should return true because every num is obviously equal to itself. However I get a false return value. After some mucking around I found out that ruby is not detecting the do...end block passed to the my_all? method (block_given? is returning false). The method DOES work if I change the do..end block to a single line bracket block as follows:

{ |num| num == num}

Can somebody please tell me what I am doing wrong regarding the do..end version? Thanks

user3355098
  • 173
  • 7

1 Answers1

0

You might want to look at iterators rather then using the for construct.

so using .each it would look like:

def my_all?
    return false unless block_given?
    self.each do |item|
        unless yield(item)
            return false
        end
    end
    return true
end

I also switched out the if ! for unless as it reads better (just don't use unless with else >_<)

Thermatix
  • 2,757
  • 21
  • 51
  • `return false unless yield(item)` maybe, and I tend to discourage people from using unnecessary explicit `return`s, but I know you were just copying the OP's code. – Dave Newton May 27 '15 at 17:21
  • I don't like using an explicit `return` unless I'm returning from several points in a function i.e. inside of an `if` or a `case`. But yeah, I decided against altering the code too much as It might end up confusing for the OP if the example I've given strays too far from the original. – Thermatix May 27 '15 at 17:23
  • @user3536548 I think Dave Newton was pointing out that it's a bad idea to have multiple return points from inside of a function, period. Much better to have a single point at which the return occurs. Much safer and cleaner. – David Hoelzer May 27 '15 at 17:33
  • @DavidHoelzer Definitely not what I was pointing out. I disagree: guard clauses with returns make sense. The second breaks out of a tiny loop; also makes sense. I strongly disagree with the "Only One Return" rule, particularly in short methods such as this; it reads far, *far* cleaner with them in. E.g., http://stackoverflow.com/a/36714/438992, http://programmers.stackexchange.com/q/118703, http://forums.xkcd.com/viewtopic.php?f=11&t=95359, http://www.hackerchick.com/2009/02/religious-war-48293-single-vs-multiple.html. – Dave Newton May 27 '15 at 17:43
  • @DaveNewton Well, I don't strongly enforce it and the short circuit that you're mentioning is a great place for it, but lots of secure coding folks will disagree: http://www.cs.rit.edu/~tmh/courses/SecureCoding/2014/docs/ErrorMessages.pdf The piece of advice that I'll often offer is that if you are creating multiple returns (more specifically, if they are sprinkled throughout a function) then that function is ripe for refactoring into smaller bits. – David Hoelzer May 27 '15 at 18:02
  • @DavidHoelzer Sure--but this function is already minute. It's also less of an issue when you don't have to manually handle resource deallocation, etc. The argument that it's easier to test (with multiple returns) is dependent on the language and the method; that the number of exits is lower doesn't explicitly reduce complexity or the number of paths through the method. – Dave Newton May 27 '15 at 18:14
  • I prefer to have one 'point of return', but when I do have multiple points then I explicitly state `return` to indicate that. – Thermatix May 27 '15 at 18:34