Avoiding nil.methodcalls short and cheap

Hi,

I often have to check if a methodcall A is not returning nil before
calling another method on the return value of the methodcall A. I’m
looking for a short and cheap (avoiding to call method A two times like
in this example where xmltag.get_text is method A:
textvalue = xmltag.get_text.value if xmltag.get_text
)
The ideal solution would be a oneliner with only little complexity
calling method A just one time. Am I using the wrong approach here
anyway?

Thanks,
.tr!

On 22/06/07, Thorsten R. [email protected] wrote:

textvalue = xmltag.get_text.value if xmltag.get_text

textvalue = (text = xmltag.get_text) && text.value

Farrel

On Jun 22, 4:53 pm, Thorsten R. [email protected] wrote:

anyway?

Thanks,
tr!


Posted viahttp://www.ruby-forum.com/.
Consider this:

begin
textvalue = xmltag.get_text.value
rescue NoMethodError
end

On 6/22/07, Thorsten R. [email protected] wrote:

Hi,

I often have to check if a methodcall A is not returning nil before
calling another method on the return value of the methodcall A. I’m
looking for a short and cheap (avoiding to call method A two times like
in this example where xmltag.get_text is method A:
textvalue = xmltag.get_text.value if xmltag.get_text

Variations using just logic operators and conditionals - I think the
last two are probably best (though it vary by context)

Short, unclear

textvalue = xmltag.get_text
textvalue &&= textvalue.value

With if

textvalue = textvalue.value if textvalue = xmltag.get_text

Longer, clearer

if textvalue = xmltag.get_text
textvalue = textvalue.value
end

Re-using the variable, one-line

textvalue = xmltag.get_text and textvalue = textvalue.value

With new variable, possibly the cleanest

textvalue = (text = xmltag.get_text and text.value)

You can also redefine the object in question

def xmltag.get_text_value
text = get_text && text.value
end
textvalue = xmltag.get_text_value

On 22/06/07, Eivind E. [email protected] wrote:

last two are probably best (though it vary by context)
textvalue = textvalue.value
text = get_text && text.value
end
textvalue = xmltag.get_text_value

I would avoid code that relies on logical operators to preserve values.
That is any code that uses logical operators and would break if you
put !!() around the expression is quite dodgy in my book.

Thanks

Michal

On 6/22/07, Michal S. [email protected] wrote:

I would avoid code that relies on logical operators to preserve values.
That is any code that uses logical operators and would break if you
put !!() around the expression is quite dodgy in my book.

And I would strongly disagree with this.

Returning the value of the true expression is defined behavior, and it
allows for considerable simplification of code. Having simpler code
means that you have less chance of errors and spend less time when
reading the code.

To my mind, dodgy code is code that is difficult to understand or
increase chance of errors, ie, the opposite of code that does
appropriate use of the preservation of values in logical operators.

Not that I’m particularly happy with any of the cases above - the
closest to “good” I found was textvalue = (text = tag.get_text and
text.get_value)

Eivind.

Thanks for quick and helpful answers! I hope all of you will have a
great weekend!

Thorsten R. [email protected] writes:

The ideal solution would be a oneliner with only little complexity
calling method A just one time. Am I using the wrong approach here
anyway?

Since no one has pointed this out, I’ll remind you that this is
Ruby, which has the relatively uncommon feature of allowing one to add
to core classes, so we can use that if there’s only one or two methods
you’d like to call frequently. First note:

irb(main):001:0> nil.freeze
=> nil

Then, doing this somewhere:

class NilClass
alias value freeze
end

Lets us do this in the main code:

textvalue = xmltag.get_text.value

And nils automatically get propagated.

On Jun 22, 5:53 am, Thorsten R. [email protected] wrote:

anyway?
The conceptually simplest is:

get_text = xmltag.get_text
textvalue = get_text.value if get_text

But as you will note, it takes up two lines. Of course you can always
fix that:

get_text = xmltag.get_text; textvalue = get_text.value if get_text

Even so, I often write this as:

if get_text = xmltag.get_text
textvalue = get_text.value
end

Simply b/c I often find long one liners unpleasant to read.

However, I just want to point out that if there is no get_text, than
textvalue is not being assigned at all. Unless you have previously set
textvalue to a default, that could lead to an undefined local variable
error. So you might consider:

textvalue = (get_text = xmltag.get_text) ? get_text.value : nil

T.

Thorsten R. wrote:

anyway?
This the solution I use in my code for this common problem:
textvalue = xmltag.get_text.ergo.value

This is my personal solution and I’ve never seen anyone use something
like this, so it may not be a “common and accepted idiom” but it works
well for me. YMMV

code for “ergo”:

class NilClass
def ergo
@blackhole ||= Object.new.instance_eval do
class << self
for m in public_instance_methods
undef_method(m.to_sym) unless m =~ /^.*$/
end
end
def method_missing(*args); nil; end
self
end
@blackhole unless block_given?
end
end

class Object
def ergo
if block_given?
yield(self)
else
self
end
end
end

Trans wrote:

Interesting… I like this. Nice use of fluent / magic dot notation.
This is a good use case for Functor too (see Facets):

class NilClass
def ergo
@blackhole ||= Functor.new{ nil }
@blackhole unless block_given?
end
end

Indeed, that really simplifies the code.

One question, I’m not sure what you expect to be returned if a block
is given.

foo.ergo{ |o| o.bar } #=> result of bar
nil.ergo{ |o| o.bar } #=> nil
because sometimes some cases don’t lend themselves very well to “magic
dot” notation.

Besides that one issue, I’d like to add this to Facets and credit you.

By all means, I’d be honored.

Daniel

On Jun 23, 9:17 am, Daniel DeLorme [email protected] wrote:

calling method A just one time. Am I using the wrong approach here

 end
 end

end
end

Interesting… I like this. Nice use of fluent / magic dot notation.
This is a good use case for Functor too (see Facets):

class NilClass
def ergo
@blackhole ||= Functor.new{ nil }
@blackhole unless block_given?
end
end

One question, I’m not sure what you expect to be returned if a block
is given.

Besides that one issue, I’d like to add this to Facets and credit you.

T.

On 6/23/07, Daniel DeLorme [email protected] wrote:

code for “ergo”:
(… deleted …)

I love the solution, and have one question: Is there any deeper
rationale behind the name “ergo”?

Eivind.

On 22/06/07, Eivind E. [email protected] wrote:

reading the code.

Not always. It is defined behavior but unless you work exclusively in
Ruby you will have to deal with cases when true values are not
preserved. This makes the code more obscure, harder to read, and more
error prone.

The concept of logical operations is to preserve the logical value,
and you have to think twice about other properties they might or might
not have.

Thanks

Michal

Eivind E. wrote:

I love the solution, and have one question: Is there any deeper
rationale behind the name “ergo”?

it’s latin for “therefore”, as in:

cogito = [2,2]
cogito.ergo.sum #=> 4

:wink:

On 6/26/07, Daniel DeLorme [email protected] wrote:

Eivind E. wrote:

I love the solution, and have one question: Is there any deeper
rationale behind the name “ergo”?

it’s latin for “therefore”, as in:

I know that (ergo is commonly used in my native tongue), I just didn’t
feel that it really formed a rationale. On the other hand, I don’t
have a better name handy…

Eivind.

Eivind E. wrote:

On 6/26/07, Daniel DeLorme [email protected] wrote:

Eivind E. wrote:

I love the solution, and have one question: Is there any deeper
rationale behind the name “ergo”?

it’s latin for “therefore”, as in:

I know that (ergo is commonly used in my native tongue), I just didn’t
feel that it really formed a rationale. On the other hand, I don’t
have a better name handy…

Sorry, it seems I misunderstood the question. But I don’t know what more
‘rationale’ is needed. To me, “a ergo b” reads like “b proceeds from a”,
which expresses the same logic as “a && a.b” IMHO no deeper rationale
is required.

Daniel