If-then-else Assignment Shortcut (#7)

Submitted by: Ron Hopper

This revision by: Ron Hopper

Date: Mon Mar 19 16:55:49 -0500 2007

ABSTRACT

There are assignment shortcuts for most binary operators, however, the ternary if-then-else operator does not have a shortcut for assignment. In some situations this shortcut makes a lot of sense and its lack is noticeable.

PROBLEM

There are frequently scenarios when a variable needs to be replaced by a modified version of itself or a default value if it is nil. Assignment in these scenarios is achieved using the ternary if-then-else operator to check for a nil value and supply a default. There is unnecessary duplication, however, in the common case that the variable being assigned to is the same one being checked, as in these examples:

page_title = page_title ? "Title: #{page_title}" : "Untitled"
tree_node = tree_node ? tree_node.next : root_node

PROPOSAL

Allow the assigment shortcut syntax for the ternary if-then-else operator, so that code previously written as:

page_title = page_title ? "Title: #{page_title}" : "Untitled"
tree_node = tree_node ? tree_node.next : root_node

can instead be written more meaningfully and succinctly as:

page_title ?= "Title: #{page_title}" : "Untitled"
tree_node ?= tree_node.next : root_node

ANALYSIS

The change is trivial, does not create any language conflicts that I am aware of, and makes the code more concise while improving readability.

IMPLEMENTATION

The syntax:

x ?= y : z

should be expanded to

x = x ? y : z

Comments

from Yukihiro Matsumoto, Mon Mar 19 18:50:38 -0500 2007

Hi,

I have never met a situation of needing it.  Do you?
Maybe it's upto programming style.  Whereas I find "||=" useful.

  a ||= b

is roughly equivalent to

  a = a ? a : b

                                                        matz.

from Trans Onoma, Mon Mar 19 18:58:49 -0500 2007

On 3/19/07, matz@ruby-lang.org <matz@ruby-lang.org> wrote:
> A comment about: RCR 7: If-then-else Assignment Shortcut
> was sent by Yukihiro Matsumoto.
>
> To send a comment, reply to this mail.  Please trim all unnecessary
> lines.
>
> You can view RCR 7 at:
> https://rcrchive.net/rcrs/9
>
> Hi,
>
> I have never met a situation of needing it.  Do you?
> Maybe it's upto programming style.  Whereas I find "||=" useful.
>
>   a ||= b
>
> is roughly equivalent to
>
>   a = a ? a : b

Yep ||= does the trick. Tough I thought it was odd to hear that

  a = b unless a

executed faster. Is that true?

A little OT, but I sometimes run into

  return a if a

would be nice if one could do

   return_on a

or something like that (especially useful when "a" is complex).

T.

from Yukihiro Matsumoto, Mon Mar 19 19:31:27 -0500 2007

Hi,

I have never benchmarked between

  a ||= b

and

  a = b unless a

but I'm sure the difference would be trivial, and situation will
change after YARV.

For return_on statement you have proposed, I am negative for it, since
we should be conservative for adding new reserved words, especially
one that change control flow.  I feel

  return_on complex_expression

is no better than

  x = complex_expression
  return x if x

It's explicit and more understandable at the cost of little verbosity
(only 7 bytes longer), besides that I have never met the situation for
code like that.

                                                        matz.

from Trans Onoma, Mon Mar 19 19:46:59 -0500 2007

On 3/19/07, matz@ruby-lang.org <matz@ruby-lang.org> wrote:
> A comment about: RCR 7: If-then-else Assignment Shortcut
> was sent by Yukihiro Matsumoto.
>
> To send a comment, reply to this mail.  Please trim all unnecessary
> lines.
>
> You can view RCR 7 at:
> https://rcrchive.net/rcrs/9
>
> Hi,
>
> I have never benchmarked between
>
>   a ||= b
>
> and
>
>   a = b unless a
>
> but I'm sure the difference would be trivial, and situation will
> change after YARV.
>
> For return_on statement you have proposed, I am negative for it, since
> we should be conservative for adding new reserved words, especially
> one that change control flow.  I feel
>
>   return_on complex_expression
>
> is no better than
>
>   x = complex_expression
>   return x if x

Well you'd usually write it like

  if x = complex_expression
    return x
  end

I would write it one line

  return x if x = complex_expression

but that fails to assign the x before the return, maybe that will be
fixed in YARV?

> It's explicit and more understandable at the cost of little verbosity
> (only 7 bytes longer), besides that I have never met the situation for
> code like that.

I've used it more than a few times. I'd have to look for one though,
I'm not very good at thinking up good examples off the top of my head.
When I run across it again I'll let you know. In any case I understand
about the additional keyword. Just wish there were a more elegant way
to write it.

T.

from Yukihiro Matsumoto, Mon Mar 19 20:23:06 -0500 2007

Hi,

In message "Re: [RCR] If-then-else Assignment Shortcut"
    on Mon, 19 Mar 2007 19:46:59 -0500, transfire@gmail.com writes:

|I would write it one line
|
|  return x if x = complex_expression
|
|but that fails to assign the x before the return, maybe that will be
|fixed in YARV?

Not for 1.9, it will be in 2.0.

                                                        matz.

from Ron Hopper, Tue Mar 20 14:59:36 -0500 2007

On 3/19/07, matz@ruby-lang.org < matz@ruby-lang.org> wrote:
>
> I have never met a situation of needing it.  Do you?
> Maybe it's upto programming style.  Whereas I find "||=" useful.
>
>   a ||= b
>
> is roughly equivalent to
>
>   a = a ? a : b
>
>                                                         matz.



While ||= is very useful for assigning a default value, it does not apply to
the case when a calculation must be performed on a non-nil value.  There are
two scenarios where I typically run into this.

1) When using potentially nil-valued string variables that require some
processing, such as appending a suffix or modifying case.  For example, I
recently wrote a script to define wizard-related methods in a Rails
controller.

  def wizard_actions
    define_method "edit" do
      #...
    end

    define_method "save_as_draft" do
      #...
    end

    # etc.
  end

I was later able to use this code in a case that required more explicit
method names, such as "edit_profile".  I would like to have modified the
code as below:

  def wizard_actions(suffix = nil)
    suffix ?= "_#{suffix}" : ""

    define_method "edit#{suffix}" do
      #...
    end

    define_method "save#{suffix}" do
      #...
    end

    # etc.
  end

Instead, I used:

  def wizard_actions(suffix = "")
    suffix = "_#{suffix}" unless suffix.blank?

I believe that the ternary shortcut would be more appropriate, however, and
can't see why it's excluded from the assignment shortcuts.

2) When managing data-structures, it is a useful way to avoid calling
methods on nil pointers.  As a simplified example, consider a singly linked
list with a method to remove the next node in the list.

class SinglyLinkedList

  #...

  class Node
    attr_accessor :next, :value

    def initialize(value)
      @next = nil
      @value = value
    end

    def remove_next
      @next ?= @next.next : nil
    end

    #...etc.
  end
end

Although, these examples are not encountered frequently compared to uses of
the other assignment shortcuts, it seems to me that there is little reason
not to allow this shortcut which is occasionally useful and fits well with
the other operator conventions.

On 3/19/07, <b class="gmail_sendername"><a href="mailto:matz@ruby-lang.org" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">matz@ruby-lang.org</a></b> &lt;<a href="mailto:matz@ruby-lang.org" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">


matz@ruby-lang.org</a>&gt; wrote:<div><span class="gmail_quote"></span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
I have never met a situation of needing it.&nbsp;&nbsp;Do you?<br>Maybe it&#39;s upto programming style.&nbsp;&nbsp;Whereas I find &quot;||=&quot; useful.<br><br>&nbsp;&nbsp;a ||= b<br><br>is roughly equivalent to<br><br>&nbsp;&nbsp;a = a ? a : b<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;matz.
</blockquote><div><br><br>While ||= is very useful for assigning a default value, it does not apply to the case when a calculation must be performed on a non-nil value.&nbsp; There are two scenarios where I typically run into this.
<br><br>1) When using potentially nil-valued string variables that require some processing, such as appending a suffix or modifying case.&nbsp; For example, I recently wrote a script to define wizard-related methods in a Rails controller.&nbsp; 
<br><br>&nbsp; def wizard_actions<br>&nbsp;&nbsp;&nbsp; define_method &quot;edit&quot; do<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #...<br>&nbsp;&nbsp;&nbsp; end<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; define_method &quot;save_as_draft&quot; do<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #...<br>&nbsp;&nbsp;&nbsp; end<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; # etc.<br>&nbsp; end<br><br>I was later able to use this code in a case that required more explicit method names, such as &quot;edit_profile&quot;.&nbsp; I would like to have modified the code as below:
<br><br>&nbsp; def wizard_actions(suffix = nil)<br>&nbsp;&nbsp;&nbsp; suffix ?= &quot;_#{suffix}&quot; : &quot;&quot;<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; define_method &quot;edit#{suffix}&quot; do<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #...<br>&nbsp;&nbsp;&nbsp; end<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; define_method &quot;save#{suffix}&quot; do
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #...<br>&nbsp;&nbsp;&nbsp; end<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; # etc.<br>&nbsp; end<br><br>Instead, I used:<br><br>&nbsp; def wizard_actions(suffix = &quot;&quot;)<br>
&nbsp;&nbsp;&nbsp; suffix = &quot;_#{suffix}&quot; unless suffix.blank?<br>
<br>I believe that the ternary shortcut would be more appropriate, however, and can&#39;t see why it&#39;s excluded from the assignment shortcuts.<br><br>2) When managing data-structures, it is a useful way to avoid calling methods on nil pointers.&nbsp; As a simplified example, consider a singly linked list with a method to remove the next node in the list.
<br><br>class SinglyLinkedList<br><br>&nbsp; #...<br><br>&nbsp; class Node<br>&nbsp;&nbsp;&nbsp; attr_accessor :next, :value<br>&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; def initialize(value)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @next = nil<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @value = value<br>&nbsp;&nbsp;&nbsp; end<br><br>&nbsp;&nbsp;&nbsp; def remove_next<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @next ?= @next.next : nil<br>&nbsp;&nbsp;&nbsp; end<br><br>&nbsp;&nbsp;&nbsp; #...etc.<br>&nbsp; end<br>end<br><br>Although, these examples are not encountered frequently compared to uses of the other assignment shortcuts, it seems to me that there is little reason not to allow this shortcut which is occasionally useful and fits well with the other operator conventions.
<br></div></div>



Return to top

Copyright © 2006, Ruby Power and Light, LLC