Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Clean try syntax

#5013

The syntax for try is really ugly with array/hash access. ie. list.try(:[],4)

I would really like to see try return a proxy object when the original object is a NilObject. This would allow try to be used like:

list.try[2]

other methods can be called right off of try:

list.try.size

Reported by Amos King · June 30th, 2010 @ 05:35 AM

State: wontfix
Milestone: none
Assigned to: José Valim José Valim
Importance: Low

Activity

  1. Amos King
    Amos King
    • Tag changed from active_support, core_ext, rails3 to active_support, core_ext, patch, rails3

    here is a patch, and it keeps backwards compatibility.

    June 30th, 2010 @ 05:41 AM

  2. Amos King
    Amos King
    • Tag changed from active_support, core_ext, patch, rails3 to active_support, core_ext, documentation, patch, rails3

    I also updated the documentation in the same patch.

    June 30th, 2010 @ 05:44 AM

  3. José Valim
    José Valim
    • State changed from new to wontfix
    • Importance changed from to Low

    Thanks for the patch, but the syntax something.try[2] is not obvious (for me). try(:[], 2) is simpler with no extra tricks in the implementation.

    June 30th, 2010 @ 12:18 PM

  4. Amos King
    Amos King

    This patch supports both syntaxes.

    June 30th, 2010 @ 01:06 PM

  5. José Valim
    José Valim

    Yes, but I don't see a reason to support a more complex syntax to be used rather rarely (in :[] cases).

    June 30th, 2010 @ 01:11 PM

  6. yairgo
    yairgo

    +1

    Are you really going to disregard this patch because the syntax "is not obvious" for you?

    I've worked with 5 or 6 people at my company on a rails project that I'm part time on and I've shown at least 4 of them the try(:[], 4) syntax. They've all pretty much said afterward that they would have never even thought to use 'try' that way.

    something.try[2] makes a lot more sense to me than something.try(:[],2), one says here try this on my object the other says here is a method and some params try them on my object.

    "Yes, but I don't see a reason to support a more complex syntax which is used rather rarely." Is the patch really introducing a more complex syntax?
    try[2] vs try(:[], 2)

    June 30th, 2010 @ 02:54 PM

  7. Amos King
    Amos King

    Why not support both syntaxes for a little while, and see where the community goes with it. Then we can deprecate one, or maybe decide to keep both?

    June 30th, 2010 @ 03:00 PM

  8. José Valim
    José Valim
    • Assigned user set to José Valim

    Sorry, when I said "complex", I was referring about the implementation required to support such syntax and difficulty to understand what is going on:

      self.try(:[], 2) #=> is a method that sends the given method unless self is nil
      self.try[2]      #=> is a method that returns self if not nil, else a proxy that discards any call
    

    A proxy just adds complexity:

      object.try(:freeze) #=> return nil if object nil
      object.try.freeze   #=> freezes the proxy and returns the proxy if object nil
    

    Another possible failure is with to_json:

      require 'json'       #=> Ruby 1.9.2
      nil.to_json          #=> "null"
      object.try(:to_json) #=> nil
      object.try.to_json   #=> "#<Try:0x00000101826fe8>"
    

    There are several other cases where returning a proxy might have a surprising behavior. Note that this is nothing new, we had this discussion a long time ago because there were solutions like andand which had a similar approach to try+proxy and we voted to be explicit with try, since it has no special cases or caveats.

    Edited to add proper formatting to block codes.

    June 30th, 2010 @ 03:28 PM

  9. Amos King
    Amos King

    What if the implementation used BasicObject if the implementation is Ruby 1.9? I'm not in a place where I can test that right now.

    June 30th, 2010 @ 04:03 PM

  10. José Valim
    José Valim

    We could consider that in the future when we drop support for Ruby 1.8.x, but not right now because the implementation would behave considerably different depending on the Ruby version (something that ActiveSupport tries to minimize).

    June 30th, 2010 @ 04:11 PM

  11. Jeremy Kemper
    Jeremy Kemper

    I agree maybe_hash_maybe_nil.try(:[], key) is ugly. But the proxy approach is error-prone and less obvious.

    A third way is to use instance_eval: list.try { self[2] } or object.try { to_json }. That's clear, but line-noisey.

    I think the simplest choice is to use try for simple cases and simply do not use it for the few ugly cases.

    June 30th, 2010 @ 05:15 PM

  12. Amos King
    Amos King

    irb(main):003:0> require 'json'
    => true irb(main):005:0> Try = Class.new(BasicObject) { def method_missing(*) nil; end }
    => Try irb(main):006:0> Try.new.to_json
    => nil

    This was with 1.9, and with 1.8.7 it did the same thing.

    I'm not sure how you got the Try object with the to_json call.

    July 11th, 2010 @ 05:46 AM