views:

544

answers:

3

Should I use if defined?

 return @current_user_session if defined?(@current_user_session)
 @current_user_session = UserSession.find

Or ||=

@current_user_session ||= UserSession.find

I noticed the if defined? method being used more and more recently. Is there any advantage to one over the other? Personally, I prefer ||= for readability. I also think Rails might have a memoize macro which provides this behavior transparently. Is this the case?

+8  A: 

Be careful: x ||= y assigns x = y if x returns false. That may mean that x is undefined, nil, or false.

There are many times variables will be defined and false, though perhaps not in the context of the @current_user_session instance variable.

If you desire conciseness, try the conditional construct:

defined?(@current_user_session) ?
    @current_user_session : @current_user_session = UserSession.find

or just:

defined?(@current_user_session) || @current_user_session = UserSession.find

if you just need to initialize the variable.

guns
A: 

Additionally, the nicer ||= produces a warning (on 1.8.6 and 1.8.7, at least) about uninitialized instance variables, while the more verbose defined? version does not.

On the other hand, this probably does what you want:

def initialize
  @foo = nil
end

def foo
  @foo ||= some_long_calculation_for_a_foo
end

But this almost certainly does not:

def initialize
  @foo = nil
end

def foo
  return @foo if defined?(@foo)
  @foo = some_long_calculation_for_a_foo
end

since @foo will always be defined at that point.

James A. Rosen
the whole point of defined? is to check for uninitialized instance variables.
Sam
Also, defined?(:@foo) ALWAYS returns "expression". You meant defined?(@foo). defined?(@foo) returns either nil or "instance-variable".
Bob Aman
thanks for the catch, Sporkmonger. Typo is now fixed.
James A. Rosen
+1  A: 

Rails does have memoization, check out the screencast below for a great introduction:

http://railscasts.com/episodes/137-memoization

class Product < ActiveRecord::Base
extend ActiveSupport::Memoizable

belongs_to :category

def filesize(num = 1)
  # some expensive operation
  sleep 2
  12345789 * num
end
memoize :filesize
end
mwilliams
However, do NOT use Rails' memoization if any of your parameters are Hashes unless you're on Ruby 1.9.
Bob Aman