Brian Candler wrote:
> If you really want to organise your code like this, you can using lambdas:
>   def foo
>     a_list = ...
>     b_list = ...
>     c_list = ...
>
>     foo1 = lambda {
>       op1(a_list, b_list, c_list)
>     }
>
>     ...
>     foo1[]
>   end
>
> This just avoids having to pass a_list, b_list, c_list to foo, because they
> are visible in the enclosing scope.
>
> But in many cases a more Rubyesque way would be to create a container class
> to hold those three lists and to group together the operations on them.
>
> class A
>   class B
>     attr_accessor :a, :b, :c
>     def initialize(a,b,c)
>       @a, @b, @c = a,b,c
>     end
>     def foo1
>       op1(@a, @b, @c)
>       # or perhaps: @a, @b, @c = op1(@a, @b, @c)
>     end
>     ...
>   end
>
>   def foo
>     a_list = ...
>     b_list = ...
>     c_list = ...
>
>     b = B.new(a_list, b_list, c_list)
>
>     b = b.foo1
>     ...
>     return b.a, b.b, b.c
>   end
> end
>
> Notice that a 'throwaway' instance of class B is created inside method
> A#foo, and is garbage-collected after it returns. That doesn't matter -
> objects are cheap to create in Ruby, and it's a small object as it just has
> three instance variables (which only hold a reference to the list objects,
> which already exist).
>
> With this approach you need to decide where it makes most sense for op1 to
> live. If it makes sense to live in class B then it gets even simpler, as it
> can access the instance variables @a, @b, @c directly without having to have
> them passed as arguments.
>
> I reiterate - objects are created and destroyed often in Ruby. You may not
> realise it, but even
>
>    10.times { puts "hello" }
>
> creates 10 distinct String objects, and garbage collects them.
>
> Regards,
>
> Brian.
>
>
>   
I was aware that could used a class to do the trick, but a like to stay
away of programming practice who generate
code.that.look.like.java.expression  ...    :-)

You must admit this type of code( foo4) is more clean, and provide a
simpler form of encapsulation of the code.

But your Lambda's version is very tempting, but my experience with the
use of Proc come at the price of performance penalty. But inside a
method, thing might be a bit different. I most admit that i like a lot
the elegance of the lambda's version.

------------------------------------------------------------------------------------------------------------------------

def foo4

  @bar = 10

  def gazonk
    print @bar
  end

  gazonk
end

foo4
--------------------------------------------------------------------------------------------------------------------------

By the way, i didn't test the third model and this is the correct
version, the @ are making a big difference:


foo()
   @a_list = # a big link list
   @b_list = # another big link list
   @c_list = # result of operation on a_list and b_link

   def foo1()
     op1(@a_list,@b_list,@c_list)
    end

    def foo2()
       op2(@a_list,@b_list,@c_list)
    end

    def foo3()
      op2(@a_list,@b_list,@c_list)
    end

foo1()
foo2()
return foo3()
end

p foo()

--------------------------------------------------------------------------------------------------------------------------

Yes, the penalty do not seem very high in Ruby, but when you are writing
a Prolog interpreter/compiler, reducing the amount of garbages is your
main concern. In some case, half of the time is spend in the garbage
collection.
   
To illustrated the importance of the garbage collection on Prolog. The
prolog's version of SWI Prolog with a very smart garbage collector is
faster the original version in C.


/Perhaps you've misunderstood how assignments work in Ruby. If you do

  a = [:an, :array, :of, :stuff]
  b = a

then the second line does *not* create any new object. So what you say is
true only if function foo1 creates and returns three new lists./



Unless Ruby have a radical new approach, every time that you are using a
function, the interpreter must clone the values that are passed in
parameter *. (That why technic 2 have 6 lists and technic 3 only 3 ,
technic 1 generate a least 12 **) That the difference between call by
value and call by reference .  You can fool the interpreter by putting
values inside an array, so it gone modify the value of variable outside
the scope of the function. ( because the interpreter copy a pointer,
exactly like an assignments)

test this:

 
  a=1
  b=1
  c=[a,b]
 
def foo1(x,y)
    x +=1
    y +=1
end

foo1(a,b)

p a,b # no modification of the content of a or b

def foo2(x)
    x[0] +=1
    x[1] +=1
end

foo2(c)

p c[0],c[1]  #Surprise. The content of c have change !


By using variable outside the function, you are bypassing the cloning
process and the old value is crushed every times that you are using that
variable. And so far, it's seem to work with every programming language.
And because it's a common practice to reclaimed the space of the inner
variable after the uses of a function in many garbage collector, i feel
technic 3 is a bit better. But in term of speed there is no big
difference between 2 and 3)

This code :

i=0
for i in 0..100000
    p i
end

is faster than this one:

for i in 0..100000
    p i
end


* That the reason why many programming language do not allowed Array as
parameter, but only pointer on an array.

** i have the bad feeling that only the first node is a copy ....  :(





  Regards
 
  Fran?oys