Forum: Ruby nil? with block

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Michiel D. (Guest)
on 2007-03-21 14:56
(Received via mailing list)
If you have a long chain of method calls, but want to check some
temporary values for nils, for instance to raise an exception,
currently the easiest way is with local variables:

e.g.:

def zipcode_for_user(user)
  address = user.personal_data.address
  raise 'no address!' unless address
  address.zipcode
end

If "nil?" is extended to accept a block, and to return self (for
Object) and the result of the yield (for NilClass), the following
notation becomes possible:

user.personal_data.address.nil?{ raise 'no address!'}.zipcode

This is more concise, and (I think) also more readable. The flow of
the program isn't broken by the nil-check. Apart from raise
statements, it would make sense to use return statements in the
blocks.

The implementation is trivial:
class Object ; def nil? ; block_given? ? self : false ; end ; end
class NilClass ; def nil? ; block_given? ? yield : true ; end ; end

Do you think this is a good idea?
David A. Black (Guest)
on 2007-03-21 15:05
(Received via mailing list)
Hi --

On 3/21/07, Michiel de Mare <removed_email_address@domain.invalid> wrote:
> end
> blocks.
>
> The implementation is trivial:
> class Object ; def nil? ; block_given? ? self : false ; end ; end
> class NilClass ; def nil? ; block_given? ? yield : true ; end ; end
>
> Do you think this is a good idea?

No, I don't like it.  It's unidiomatic for a ?-method to take a block,
and also for a block to serve as a conditional branch.  I'd rather see
it unrolled.  I understand the reasoning behind it, but it ends up
being idiosyncratic in its semantics.


David
Robert K. (Guest)
on 2007-03-21 15:06
(Received via mailing list)
On 21.03.2007 13:51, Michiel de Mare wrote:
> end
>
> If "nil?" is extended to accept a block, and to return self (for
> Object) and the result of the yield (for NilClass), the following
> notation becomes possible:
>
> user.personal_data.address.nil?{ raise 'no address!'}.zipcode
>
> This is more concise, and (I think) also more readable.

Actually I am not sure about readability.  Lines tend to grow pretty
long that way.  I would probably not use it.  Also keep in mind that you
will usually get an exception anyway since you're most likely calling a
method that nil does not support.

 > The flow of
> the program isn't broken by the nil-check. Apart from raise
> statements, it would make sense to use return statements in the
> blocks.
>
> The implementation is trivial:

... and probably slower than the current implementation as they add
another boolean check.

> class Object ; def nil? ; block_given? ? self : false ; end ; end
> class NilClass ; def nil? ; block_given? ? yield : true ; end ; end
>
> Do you think this is a good idea?

I am not so sure.  But you can easily implement this with another method
name so you don't have to change existing code's behavior.  Also, nil
values might be just only one reason to throw an exception so I am not
sure about general usefulness.

Yeah, I know - I'm a conservative skeptic. :-)

Kind regards

  robert
Sylvain Abélard (Guest)
on 2007-03-21 15:19
(Received via mailing list)
> I am not so sure.  But you can easily implement this with another method
> name so you don't have to change existing code's behavior.  Also, nil
> values might be just only one reason to throw an exception so I am not
> sure about general usefulness.

I also doubt this would ever be useful. I like 'long lines' and hate
loads of 'if-statements' but I must admit I find them useful (or at
least, any other solution looks awful to me).


Why not using, let's call them  "accessors?" which are "accessors with
a question mark".
Just by hacking with a bit of "method_missing" in both your class and
NilClass, this would not slow exec time much I guess, and the
implementation should also be trivial.

- in the class, you just send(accessor_name) when you get an unknown
accessor_name?
- in nilclass, you return "stuff" when having a '?' method (except
nil? or empty?)

The problem, IMHO, resides in the impossibility to return a coherent
"stuff".
You *want* Ruby to NoMethodError you when you fail something.
You *can't* always know what you could prefer when your call fail.
Should "stuff" be nil, 0, empty string, new object ?


I suggest you use that in your project (if that's a big one) and then
tell us in a few weeks/months if that changed your life or not. If
that made your debugging harder.
Then again, this is a matter of personal preference I guess ;)
Daniel L. (Guest)
on 2007-03-21 15:53
Michiel De mare wrote:
> If "nil?" is extended to accept a block, and to return self (for
> Object) and the result of the yield (for NilClass), the following
> notation becomes possible:
>
> user.personal_data.address.nil?{ raise 'no address!'}.zipcode
>

Why not use Object#tap?

user.p_data.address.tap {|a| raise "no address!" unless a}.zipcode

It's included in Ruby 1.9, is easily definable otherwise
(http://rubyurl.com/eG5) and does basically what you want.

best,
Dan
Gary W. (Guest)
on 2007-03-21 17:16
(Received via mailing list)
On Mar 21, 2007, at 9:04 AM, David A. Black wrote:
> No, I don't like it.  It's unidiomatic for a ?-method to take a block,

No opinion on nil?  but there are a couple examples of ?-methods
with blocks in core:  any?, all?.

Gary W.
Lou S. (Guest)
on 2007-03-21 17:33
(Received via mailing list)
On 3/21/07, Gary W. <removed_email_address@domain.invalid> wrote:

> No opinion on nil?  but there are a couple examples of ?-methods
> with blocks in core:  any?, all?.

Agreed.  However, the methods you mention use the block in order
determine whether the predicate is satisfied or not.  The action bit
is still just returning true or false.

The proposed 'nil?' uses the block to dispatch some unrelated
behavior, and it doesn't return a boolean. I agree with David, et al.
on this one.
Avdi G. (Guest)
on 2007-03-21 17:49
(Received via mailing list)
On 3/21/07, Michiel de Mare <removed_email_address@domain.invalid> wrote:
>
> user.personal_data.address.nil?{ raise 'no address!'}.zipcode
>
>
Instead of interrupting the main flow of code with error handling, how
about
this:

begin
  zipcode = user.personal_data.address.zipcode
rescue NoMethodError => error
  case error
  when :personal_data then raise "No user!"
  when :address then raise "No personal data!"
  when :zipcode then raise "No address!"
end

In fact, thanks for spurring me to think of that technique, I think I'm
going to use it in future!
Brian C. (Guest)
on 2007-03-21 22:18
(Received via mailing list)
On Wed, Mar 21, 2007 at 09:55:07PM +0900, Michiel de Mare wrote:
> end
>
> If "nil?" is extended to accept a block, and to return self (for
> Object) and the result of the yield (for NilClass), the following
> notation becomes possible:
>
> user.personal_data.address.nil?{ raise 'no address!'}.zipcode

If your result set doesn't include 'false', then you can use 'or'. Mind
you,
it gets ugly with the necessary brackets:

  (user.personal_data.address or raise "no address!").zipcode

Especially if you go to multiple levels. It looks a bit too much like
LISP...

  (((user or raise "no user!").
     personal_data or raise "no personal_data!").
     address or raise "no address!").zipcode

Regards,

Brian.
This topic is locked and can not be replied to.