5

I do this a lot in javascript

some_var || some_var = function(){ return "blah"}();

I'm wondering what the equivalent in ruby might be so I can do

some_var ||= # sequence of operations

edit

the Proc.new.call has been brought to my attention, but I also just came across this in someone's code:

a ||= begin
  # do some stuff
  # return some stuff
end

Is this functionally equivalent to using a Proc.new.call ??

edit2 People seem to be confused as to what I'm trying to achieve. Imagine this in javascript:

function someExpensiveFunction(){
  # do some really expensive stuff
  return "some expensive calculations"
}

a || a = someExpensiveFunction();

Obviously sets a once... calls expensive function once... In this case I don't care about scoping, I just need my return value to be a calculated sequence of events rather than a single value.

I'm pretty sure my example above a ||= begin; ... end; is equivalent...

2
  • what exactly are you trying to accomplish? Ruby has block level scoping, which is different from the lexical scoping that JavaScript has. Often you'll see anonymous functions in JS to avoid scoping problems. Commented Nov 24, 2010 at 15:53
  • don't care about scoping... just want a clean syntax for setting a variable using ||= that involves multiple lines of code Commented Nov 24, 2010 at 15:58

6 Answers 6

2

Per your comment:

don't care about scoping... just want a clean syntax for setting a variable using ||= that involves multiple lines of code

I'm not sure I understand why you feel you have t use ||= and a lambda. You could, for example, use

if(some_var.nil?)
   # do some stuff
   some_var = result_of_doing_some_stuf
end

Or, as you put it in your example:

a ||= begin
  # do some stuff
  # return some stuff
end

It isn't clear to me why you must be using a proc or lambda.

But if you are bent on using ||= and lambdas, you could do:

calculate = lambda { 1 + 1 }
some_var ||= calculate.call
Sign up to request clarification or add additional context in comments.

1 Comment

i'm actually trying to avoid Proc/lambda it was just given as an example which is why i referenced it.
1
s = Proc.new { 5 + 5 }.call

2 Comments

I just came across: a ||= begin # some code end You ever see that? Is it equivalent?
a crap taht formatting didn't come out right, i'll edit my post
0

I wasn't sure what part you are asking about at first. The logical || does effect your expected operations. In Ruby, the equivalent is:

somevar = "blah" unless somevar;

If somevar is nil value or a false value change to "blah". If somevar is not nil or true, the line is not executed. The opposite action would be:

somevar = "blah" if somevar;

That would assign "blah" if somevar is true or not nil.

Ruby has language features similar to the self executing function, and many javascript libraries have been inspired by those features.

Check out this page for more information:

http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_containers.html

The section on "Blocks and Iterators" would be of interest here. Also "Blocks for Transactions" and "Blocks can be closures".

Essentially the Ruby block and the ruby lambda are the closest things to the Javascript's self executing function.

2 Comments

I understand what ||= does, i want to ||= some_function
Now seeing your 2+ edits, it is clearer what you were trying to accomplish. You've already accepted the answer, so I won't attempt editing this one.
0

You can do it with lambda blocks

some_var ||= lambda { "something" }.call

or

some_var ||= Proc.new { "something" }.call

In JS self executing functions are usually used to avoid polluting scopes, so you can use local variables internally but don't expose them. Unfortunately, if using blocks in Ruby prior to 1.9, this is not the case, where blocks don't have their own scope.

# Ruby 1.8.7
x = "some initial value"
some_var ||= Proc.new { x = 10; x + 2 }.call #=> 12
x #=> 10

so if that's the case, there is probably a better solution for what you're trying to do. Ruby ain't Javascript.}

EDIT: Sorry, I forgot about variable definition in scopes vs. variable assignment. Updated snippet to reflect that

5 Comments

Ruby 1.8.6 gives x undefined in your block scope example above. Everything I have ever done or read about ruby suggests it has pretty must always supported block scope.
Yep, I meant to show variable shadowing there. See my updated answer, you're right about the block scope. I wonder what is the OP trying to do with that programming style.
I'm still confused - there is no variable shadowing going on in your snipper above. In fact, you are demonstrating the opposite.
for example, in JS, you can get a variable with the same name but different scope by declaring it with var in the inner/anonymous function. If you don't label it with var, it will assume the identity of the outer scope, via a closure. In Ruby, you don't ever 'declare' a variable like you do in JS. The inner block captures the outer variable in a closure. If it were shadowing, there result would be "some initial value", but it doesn't - the result is 10, showing there is no shadowing, just a closure.
Well, my point is that in Ruby you can't declare local variables in block scopes. Compare with gist.github.com/3687b09f40b6a1194999. Anyway, just saw what the OP tried to do, so we can move the discussion to the chat rooms perhaps?
0

You can do:

def run
  @a ||= begin
    x = 1 + 1
    puts "Calculated x"
    x
  end
end
puts "run = #{run}" # => Calculated x, run = 2
puts "run = #{run}" # => run = 2

Or use a lambda if you want to pass a variable

def run
  @a ||= lambda do |i|
    x = i + i
    puts "Calculated x"
    x
  end.call(1)
end
puts "run = #{run}" # => Calculated x, run = 2
puts "run = #{run}" # => run = 2

But it's less magical and more readable to use a method if you're gonna call the lambda immediately

def calc(i)
  x = i + i
  puts "Calculated x"
  x
end

def run
  @a ||= calc(1)
end
puts "run = #{run}" # => Calculated x, run = 2
puts "run = #{run}" # => run = 2

Comments

0

The difference between a block (begin ... end) a proc and a lambda are the way the handle return. return is not allowed in the block. Return in a Proc return from the where it's been defined and return in Lambda do what is expected

So

def f()
  a = Proc.new do
          return 5 # exit from f
      end.call
  # never called
  a+10
end 

returns 5 (and not 15)

def g()
  a = lambda do
        return 5
  end.call
  a+10
end

returns 15 (as expected)

and

def f()
  a = begin
        return 5
  end 
  a+10
end

doesn't compile.

If you are not using return in your block, then you can use begin... do (I like it by the way).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.