Is Assignment in a Conditional an Idiom?

Hi

I was just reading the following blog post
Elctech.com is for sale | HugeDomains,
and like the author, it is the first time I have seen code as he
describes. From the comments it would seem that some think it is an
idiom to be used, and perhaps others do not.

Just curious as to how common this use it? I do tend to side with
view that it is not clear at first glance.

Thanks
Richard

On Oct 2, 2:38 pm, [email protected] wrote:

Hi

I was just reading the following blog posthttp://www.elctech.com/blog/clarity-over-cleverness-but-what-is-clever,
and like the author, it is the first time I have seen code as he
describes. From the comments it would seem that some think it is an
idiom to be used, and perhaps others do not.

Just curious as to how common this use it? I do tend to side with
view that it is not clear at first glance.

It’s pretty common; since it saves a line of code. As long as the
assignment is right on the surface of the condition, and not buried
deep inside other logic, I think it works well and is quite readable.

IMHO,
T.

On Thu, Oct 2, 2008 at 8:38 PM, [email protected] wrote:

Thanks
Richard

It seems very bad code to me, what is wrong with the following?
@attributes[‘comments’] = @attributes[‘comments’].split( " " )
rescue @attributes[‘comments’]
although I suspect that
@attributes[‘comments’].split …
is what the good fellow really wants.

HTH
Robert


C’est véritablement utile puisque c’est joli.

Antoine de Saint Exupéry

On Oct 2, 2:55 pm, “Robert D.” [email protected] wrote:

view that it is not clear at first glance.

Thanks
Richard

It seems very bad code to me, what is wrong with the following?
@attributes[‘comments’] = @attributes[‘comments’].split( " " )
rescue @attributes[‘comments’]
although I suspect that
@attributes[‘comments’].split …
is what the good fellow really wants.

I wouldn’t recommend that. Rule of thumb, don’t use rescue when a
regular condition does the job.

Also one must consider if there is a difference between key presence
and key returning nil. In which case it may be better to use:

if @attributes.key?(‘comments’)

T.

Awesome!
For the record, this is the code mentioned in the blog:

1 if (comments = @attributes[‘comments’]) &&
comments.is_a?(String) 2 @attributes[‘comments’] =
comments.split(" ") 3 end

I never knew it was possible to define a variable from within a
condition.
Goes to show you that ruby offers plenty of rope to hang yourself if you
are
not careful. Correction -I have accidentally done it in the past and
never
viewed it as a feature until now.

One thing I found intriguing, was how the conditions were looking at the
response from the definition, not the value of the variable being
defined.
That makes sense in thinking about it but

For example, in IRB the second line yields false:
irb(main):001:0> (a = nil)
=> nil
irb(main):002:0> (!a = a)
=> true

However neither of these two yield true in a conditional:
puts “you wont see this” unless (a = nil) or (!a = a)

I found the logistics(or lack thereof) of the example annoying. Rob is
spot
on in saying being that an object of type String can never be nil. The
only
excuse one could have for using this code is if they referenced the
comments
variable outside of the if statement somewhere else. At which point the
comments variable could be an Array or Nil, requiring more code.

2008/10/3 list. rb [email protected]:

I found the logistics(or lack thereof) of the example annoying.

I find the results of your example very logical. What part exactly
surprised you?

Regards,
Pit

On 02.10.2008 20:35, [email protected] wrote:

I was just reading the following blog post
Elctech.com is for sale | HugeDomains,
and like the author, it is the first time I have seen code as he
describes. From the comments it would seem that some think it is an
idiom to be used, and perhaps others do not.

Just curious as to how common this use it? I do tend to side with
view that it is not clear at first glance.

I believe this is a bad idiom. First, the test for “comments” is not
needed because “String === comments” will be false if “comments” is nil.
The statement would have been written much clearer as

comments = @attributes[‘comments’])

if comments.is_a? String
@attributes[‘comments’] = comments.split(" ")
end

or

comments = @attributes[‘comments’])
@attributes[‘comments’] = comments.split(" ") if comments.is_a? String

or

comments = @attributes[‘comments’])
@attributes[‘comments’] = comments.split(" ") if String === comments

There is only one situation where assignment in a conditional actually
makes code clearer and that is with loops, e.g.

while line = io.gets
puts line
end

My 0.02EUR

Kind regards

robert

On 03.10.2008 08:22, list. rb wrote:

Awesome!
For the record, this is the code mentioned in the blog:

1 if (comments = @attributes[‘comments’]) &&
comments.is_a?(String) 2 @attributes[‘comments’] =
comments.split(" ") 3 end

Good point. Sorry for not including this.

I never knew it was possible to define a variable from within a condition.

Actually the picture may become simpler if you remember that there is no
distinction between statement and expression in Ruby. Every line of
code is an expression and thusly has a value. So “if a = 123” is not so
much different from “a = 123” - only in the latter case the result of
evaluating the expression is not used.

Goes to show you that ruby offers plenty of rope to hang yourself if you are
not careful. Correction -I have accidentally done it in the past and never
viewed it as a feature until now.

:slight_smile: There’s a lot of rope in other programming languages as well - it’s
just of a different material. :slight_smile:

One thing I found intriguing, was how the conditions were looking at the
response from the definition, not the value of the variable being defined.

In the case of an assignment there is no difference between the two.
The result of evaluating an assignment is the new value of the variable.

One additional hint: assignment operators are evaluated right to left as
opposed to other operators.

That makes sense in thinking about it but

For example, in IRB the second line yields false:
irb(main):001:0> (a = nil)
=> nil
irb(main):002:0> (!a = a)
=> true

This is actually the same as “!(a = a)”.

However neither of these two yield true in a conditional:
puts “you wont see this” unless (a = nil) or (!a = a)

This is not correct: because the second expression yields “true” you
won’t see the output (you used “unless”):

irb(main):003:0> puts “you wont see this” unless (a = nil) or (!a = a)
=> nil
irb(main):004:0> puts “you wont see this” if (a = nil) or (!a = a)
you wont see this
=> nil
irb(main):005:0> (a = nil) or (!a = a)
=> true
irb(main):006:0>

Cheers

robert

PS: please try to avoid top posting.

On Thu, Oct 2, 2008 at 9:20 PM, Trans [email protected] wrote:

I wouldn’t recommend that. Rule of thumb, don’t use rescue when a
regular condition does the job.

You surprise me here Tom, what is rescue for then, I mean the one line
version of course. However let us assume that you are right, what
really troubles me is the is_a? String or String#=== part of the
condition.
Assuming that you should not use rescue this should be written as
follows

@attributes["comments] = @attributes[“comments”].split if
@attributes[“comments”].respond_to?(:split)

Do not optimize the three lookups into assignement into a local
variable unless you have performance problems.

However I agree that the assignment to a local variable in an
ifcondition is by all means idiomatic and useful Ruby.

As is the rescue clause, I really would know more about why not to use
it.

Robert


C’est véritablement utile puisque c’est joli.

Antoine de Saint Exupéry

Hi –

On Fri, 3 Oct 2008, [email protected] wrote:

Hi

I was just reading the following blog post
Elctech.com is for sale | HugeDomains,
and like the author, it is the first time I have seen code as he
describes. From the comments it would seem that some think it is an
idiom to be used, and perhaps others do not.

Just curious as to how common this use it? I do tend to side with
view that it is not clear at first glance.

It depends whose first glance, I guess. It was clear to me, and I
think it’s something that’s common enough that every Rubyist should be
ready and willing to understand it. For better or worse, clarity and
cleverness are fuzzy concepts, but in this case it’s a pretty common
idiom and not a wildly inventive or convoluted elaboration of the
language. We all go through the process of not quite getting
something, and then having the “Ah ha!” moment. I don’t think the fact
that the blogger you quote had that experience means that this is
something to avoid.

It’s not my favorite idiom, though; it always has a slightly
unbalanced, side-effect-esque feel to it. But it’s liveable with.

Ruby does something rather cool, though, to help you with this idiom:
if you do accidentally leave off the second = in a case where the rhs
can be statically determined to be true, you get a warning:

if x = 10; end
(irb):3: warning: found = in conditional, should be ==

There’s no reason you would ever say “if x = 10”, since it will be
true 100% of the time. If the rhs is not unchangeably true, you don’t
get the warning:

y = 10
=> 10
if x = y; end
=> nil

David

list. rb wrote:

not careful. Correction -I have accidentally done it in the past and never
viewed it as a feature until now.

It’s not really a feature of Ruby, it is common in many languages and is
also a common source of bugs and logical errors.
For example, in C/C++, assignment is always true, so in cases when you
intend to do comparison but miss the second equals sign, you end up
doing assignment. Not only is it subtle logically, it is also subtle
visually since assignment and comparison look so similar (in these
languages).
The issue is so common that if Ruby thinks you are intending to do
comparison, you will typical getting a warning: “warning: found = in
conditional, should be ==”

My thoughts on the code itself is that I would not have done it that way
at all. Why even introduce a new variable unless, somehow, performance
was an issue? The overall style is not particularly 'Rubyesque" in my
opinion. I would have probably written it as:

@attributes['comments] = @attributes[‘comments’].split if
@attributes[‘comments’].is_a? String

However neither of these two yield true in a conditional:
puts “you wont see this” unless (a = nil) or (!a = a)

(!a = a) [ actually, !(a = a) ] is true, so the “puts” statement is not
executed. Maybe you meant ‘if’ instead of ‘unless’?

-Justin

On Fri, Oct 3, 2008 at 5:16 AM, Robert D. [email protected]
wrote:

As is the rescue clause, I really would know more about why not to use it.

It swallows all possible errors, not just the one you’re banking on
running into if your object is nil.

Robert D. wrote:

It seems very bad code to me, what is wrong with the following?
@attributes[‘comments’] = @attributes[‘comments’].split( " " )
rescue @attributes[‘comments’]

I think I remember hearing that ‘expr rescue val’ is not going to rescue
a NoMethodError in future versions of Ruby.

Having said that, other non-backwards-compatible changes have been
reverted (like Array#zip)

I just figured ruby was looking at the value of a returned from the
definition in the condition. The value of ‘a’ is still false after
the second condition.

Sent from my iPhone

On Oct 3, 2008, at 2:42 AM, “Pit C.” [email protected]

On Fri, Oct 3, 2008 at 4:36 PM, David A. Black [email protected]
wrote:

its logic.
See http://www.rubypal.com for details and updates!

It was late, sorry. I have no idea what I was thinking.

Hi –

On Sat, 4 Oct 2008, List.rb wrote:

I just figured ruby was looking at the value of a returned from the
definition in the condition. The value of ‘a’ is still false after the
second condition.

Are you talking about this one?

puts “Never reached” unless (a = nil) || (!a = a)

It’s a peculiar line of code, but it’s entirely logical. The
expression !a = a has to mean !(a = a), because !a isn’t an lvalue.
Since a is nil, the expression a = a (or x = a, etc.) evaluates to
nil. So you’ve basically got:

unless nil || nil

I might be misunderstanding the part you thought was questionable in
its logic.

David

On Fri, Oct 3, 2008 at 10:18 PM, Gregory B.
[email protected] wrote:

On Fri, Oct 3, 2008 at 5:16 AM, Robert D. [email protected] wrote:

As is the rescue clause, I really would know more about why not to use it.

It swallows all possible errors, not just the one you’re banking on
running into if your object is nil.
The fact that you know this makes it so usable.
I like educational code and I dislike rules.
I do not see why
x = @a[“b”].split rescue []
is bad code, only because
x = @a[some_method()].split rescue []
is bad code.
But there is no account for taste, see Rick I improve my idiomatic
English thanks to you ;).

Cheers
Robert

C’est véritablement utile puisque c’est joli.

Antoine de Saint Exupéry

On Sat, Oct 4, 2008 at 6:23 AM, Robert D. [email protected]
wrote:

I do not see why
x = @a[“b”].split rescue []
is bad code, only because
x = @a[some_method()].split rescue []
is bad code.
But there is no account for taste, see Rick I improve my idiomatic
English thanks to you ;).

Personal experience only but I believe I’ve seen virtually every line
of code again in the form of:

a rescue b

At the end of a long debugging session. The reason is because even in
the simple case:

@a[“b”].split rescue []

What you’re trying to say is “If @a[‘b’] is nil, default to []”

But when you have

@a = nil,

this does not catch it.

When you have @a[“b”] && !@a[“b”].respond_to?(:split)

this does not catch it.

Instead, you lump three distinct failure cases into a single failure
condition. If you can be absolutely sure that you really want it to
act that way in all those cases,
go for it. But you know, if I’m refactoring and I change @a to @apple
throughout my app, I sort of want lines that still reference @a to
break.

When I refactor code that once returned a string to return an object
that maybe requires something like foo.text to get at the string, I
want to know about the old places where I’m calling foo.split.

I think this is a case where people have found something that allows
them to be a little bit lazy, and then tried to pretend that it fits
another good pattern (trying something and then rescuing some
unambiguous exception, rather than futzing around with respond_to?),
when it’s really a totally different animal.

Your code is far from educational, it is misleading, and the rules you
talk about are really behaviors, and if you want to assume that you
could treat all behaviors the same way, go for it, and have fun
debugging.

-greg

On Sat, Oct 4, 2008 at 5:19 PM, Gregory B.
[email protected] wrote:

@a[“b”].split rescue []

What you’re trying to say is “If @a[‘b’] is nil, default to []”
No OP had non strings and wanted them unchanged, so that was just short
for
@a[“b”] = @a[“b”].split rescue @a[“b”]

But when you have

@a = nil,

this does not catch it.
That however is a valid point. I indeed made a mistake here, I consider
@a[‘b’].split rescue nil
bad code too but did not recognize it.
This makes it difficult to argue for
x.split rescue []
So I have eventually to give in :slight_smile: in most cases.
Your code is far from educational, it is misleading, and the rules you
talk about are really behaviors, and if you want to assume that you
could treat all behaviors the same way, go for it, and have fun
debugging.
No debugging, testing, and no rules, I mean I screwed my rules up :).
But you are right my code was not educational.
Robert


C’est véritablement utile puisque c’est joli.

Antoine de Saint Exupéry