From: Ben Vishny on 5 Jun 2010 16:33 Hi all, really stupid question. How can I evaluate the following code without using a nested if.. then statement? if parent.respond_to? "children" if parent.children.size != 0 puts "Has children" end end Ideally I'd like to do: if parent.respond_to? "children" && parent.children.size != 0 puts "Has Children" end But I get an error if parent.children is undefined. Isn't there a way of stopping if the first condition is false? Thanks, Vish -- Posted via http://www.ruby-forum.com/.
From: Mike Austin on 5 Jun 2010 16:54 On Jun 5, 1:33 pm, Ben Vishny <bvis...(a)gmail.com> wrote: > Hi all, > > really stupid question. How can I evaluate the following code without > using a nested if.. then statement? > > if parent.respond_to? "children" > if parent.children.size != 0 > puts "Has children" > end > end > > Ideally I'd like to do: > > if parent.respond_to? "children" && parent.children.size != 0 > puts "Has Children" > end > > But I get an error if parent.children is undefined. Isn't there a way of > stopping if the first condition is false? Hi Ben, Because of precedence rules, your above code is being parsed as: if parent.respond_to?("children" && parent.children.size != 0) puts "Has Children" end "&&" and "and" have different precedence, and when leaving out parenthesis in function calls, it's not as clear as to what's going on (to the reader/writer). In this case, you can surround the two expressions with parenthesis, or use "and" instead. http://blog.jayfields.com/2007/08/ruby-operator-precedence-of-and-which.html Mike > Thanks, > > Vish > -- > Posted viahttp://www.ruby-forum.com/.
From: Brian Candler on 5 Jun 2010 17:01 Ben Vishny wrote: > Ideally I'd like to do: > > if parent.respond_to? "children" && parent.children.size != 0 > puts "Has Children" > end > > But I get an error if parent.children is undefined. Isn't there a way of > stopping if the first condition is false? Yes, but you're being bitten by the ambiguity of what you've written, which is resolved by precedence rules. I'm not sure exactly how your code was being parsed, but I guess something like if parent.respond_to?("children" && (parent.children.size != 0)) The rule is, if in doubt, add your own parentheses. The following all work as you expect: if (parent.respond_to? "children") && (parent.children.size != 0) puts "Has Children" end if parent.respond_to?("children") && parent.children.size != 0 puts "Has Children" end if parent.respond_to? "children" and parent.children.size != 0 puts "Has Children" end The last of these works because 'and' has very low precedence, but I'd say it's much better to be explicit with parentheses than clever with your knowledge of precedence rules. Incidentally, it's more idiomatic to use a symbol rather than a string for respond_to? if parent.respond_to?(:children) ... Regards, Brian. -- Posted via http://www.ruby-forum.com/.
From: Robert Klemme on 7 Jun 2010 05:24 2010/6/5 Brian Candler <b.candler(a)pobox.com>: > Ben Vishny wrote: >> Ideally I'd like to do: >> >> if parent.respond_to? "children" && parent.children.size != 0 >> puts "Has Children" >> end >> >> But I get an error if parent.children is undefined. Isn't there a way of >> stopping if the first condition is false? > > Yes, but you're being bitten by the ambiguity of what you've written, > which is resolved by precedence rules. I'm not sure exactly how your > code was being parsed, but I guess something like > > if parent.respond_to?("children" && (parent.children.size != 0)) > > The rule is, if in doubt, add your own parentheses. > > The following all work as you expect: > > if (parent.respond_to? "children") && (parent.children.size != 0) > puts "Has Children" > end > > if parent.respond_to?("children") && parent.children.size != 0 > puts "Has Children" > end > > if parent.respond_to? "children" and parent.children.size != 0 > puts "Has Children" > end > > The last of these works because 'and' has very low precedence, but I'd > say it's much better to be explicit with parentheses than clever with > your knowledge of precedence rules. > > Incidentally, it's more idiomatic to use a symbol rather than a string > for respond_to? > > if parent.respond_to?(:children) ... It's even more idiomatic to invoke a method and deal with the exception. Checking with #respond_to? does not guarantee that the method can actually be executed. In this case you could do puts "Has Children" unless parent.children.empty? rescue nil Or for a more targeted catch: begin puts "Has Children" unless parent.children.empty? rescue NoMethodError # OK, no output end Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/
From: Rein Henrichs on 7 Jun 2010 12:55 On 2010-06-07 02:24:26 -0700, Robert Klemme said: > 2010/6/5 Brian Candler <b.candler(a)pobox.com>: >> Ben Vishny wrote: >>> Ideally I'd like to do: >>> >>> if parent.respond_to? "children" && parent.children.size != 0 >>> � �puts "Has Children" >>> end >>> >>> But I get an error if parent.children is undefined. Isn't there a way of >>> stopping if the first condition is false? >> >> Yes, but you're being bitten by the ambiguity of what you've written, >> which is resolved by precedence rules. I'm not sure exactly how your >> code was being parsed, but I guess something like >> >> if parent.respond_to?("children" && (parent.children.size != 0)) >> >> The rule is, if in doubt, add your own parentheses. >> >> The following all work as you expect: >> >> if (parent.respond_to? "children") && (parent.children.size != 0) >> �puts "Has Children" >> end >> >> if parent.respond_to?("children") && parent.children.size != 0 >> �puts "Has Children" >> end >> >> if parent.respond_to? "children" and parent.children.size != 0 >> �puts "Has Children" >> end >> >> The last of these works because 'and' has very low precedence, but I'd >> say it's much better to be explicit with parentheses than clever with >> your knowledge of precedence rules. >> >> Incidentally, it's more idiomatic to use a symbol rather than a string >> for respond_to? >> >> if parent.respond_to?(:children) ... > > It's even more idiomatic to invoke a method and deal with the > exception. Checking with #respond_to? does not guarantee that the > method can actually be executed. > > In this case you could do > > puts "Has Children" unless parent.children.empty? rescue nil > > Or for a more targeted catch: > > begin > puts "Has Children" unless parent.children.empty? > rescue NoMethodError > # OK, no output > end > > Kind regards > > robert > > -- > remember.guy do |as, often| as.you_can - without end > http://blog.rubybestpractices.com/ Robert, you are correct in that "It's even more idiomatic to invoke a method and deal with the exception" but rescue nil is a code smell that I would rather see avoided. A begin/rescue block also seems unnecessary. Instead of solving a potential non-problem, I think it would be better to ask questions like... Why would this parent object not have a children method? Does this imply a design inconsistency? If parent can be nil, see the following. In order to avoid NoMethodError on nil bugs, it's most common to use &&, which short-circuits, as such: parent.children && parent.children.size != 0 I may be assuming too much about your domain, but this seems more concise: parent.children && !parent.children.empty? Furthermore, it may be useful to ask: Why would children ever be nil? The empty array is a semantically correct way to say "no children". If children were initialized to [], you could always ask children.empty? and skip the check for nil. For instance: class Parent attr_reader :children def initialize(children=[]) @children = children end end -- Rein Henrichs http://puppetlabs.com http://reinh.com
|
Next
|
Last
Pages: 1 2 Prev: Clearing TOPLEVEL_BINDING for reuse Next: 1.9 warning for 'private' and possible bug |