Project

General

Profile

Actions

Bug #797

closed

bug or feature: local method ?

Added by Francoys_Proulx (Francois Proulx) over 15 years ago. Updated about 13 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
Backport:
[ruby-core:20092]

Description

=begin
It's possible to create a method inside a method. I've never see any mention of this in any documentation. It's a feature that is officially part the spec of the language or it's a bug ?
=end

Actions #1

Updated by matz (Yukihiro Matsumoto) over 15 years ago

=begin
Hi,

In message "Re: [ruby-core:20092] [Bug #797] bug or feature: local method ?"
on Wed, 26 Nov 2008 03:20:35 +0900, Francois Proulx writes:

|It's possible to create a method inside a method. I've never see any mention of this in any documentation. It's a feature that is officially part the spec of the language or it's a bug ?

Even though it's syntactically allowed, we have never made it
"official". The current behavior is useless. It's not a bug either.
It's undocumented and should not be used nor touched. I'd like to
spare this syntax for the future.

						matz.

=end

Actions #2

Updated by matz (Yukihiro Matsumoto) over 15 years ago

  • Status changed from Open to Closed

=begin

=end

Actions #3

Updated by pragdave (Dave Thomas) over 15 years ago

=begin

On Nov 25, 2008, at 12:44 PM, Yukihiro Matsumoto wrote:

Even though it's syntactically allowed, we have never made it
"official". The current behavior is useless. It's not a bug either.
It's undocumented and should not be used nor touched. I'd like to
spare this syntax for the future.

I don't think it's useless: it's a great way of having a method
redefine itself after the first call.

def something
def something
@result
end

 @result = really_expensive_calculation

end

(OK, maybe not the best example, but I have used this capability a few
times in real code)

Dave

=end

Actions #4

Updated by matz (Yukihiro Matsumoto) over 15 years ago

=begin
Hi,

In message "Re: [ruby-core:20098] Re: [Bug #797] bug or feature: local method ?"
on Wed, 26 Nov 2008 03:52:55 +0900, Dave Thomas writes:
|
|> Even though it's syntactically allowed, we have never made it
|> "official". The current behavior is useless. It's not a bug either.
|> It's undocumented and should not be used nor touched. I'd like to
|> spare this syntax for the future.
|
|I don't think it's useless: it's a great way of having a method
|redefine itself after the first call.

Ah, maybe. But this syntax can be spared for more fantastic purpose,
such as defining a method only visible from enclosing method, for
example. You can redefine a method using #define_method.

But your post made me think using this syntax in the future might be
impossible. It already abused somewhere (in the real code). Sigh.

						matz.

=end

Actions #5

Updated by pragdave (Dave Thomas) over 15 years ago

=begin

On Nov 25, 2008, at 12:59 PM, Yukihiro Matsumoto wrote:

But your post made me think using this syntax in the future might be
impossible. It already abused somewhere (in the real code). Sigh.

I'm OK if you deprecate it in 1.9.3: I've used in just a few times,
and there are always alternatives. I just have this stupid need to
stick up for the underdog, and felt I had to react when you called the
poor thing "useless." I was worried you'd hurt its feelings.

Dave

=end

Actions #6

Updated by bitsweat (Jeremy Daer) over 15 years ago

=begin
On Tue, Nov 25, 2008 at 12:20 PM, Ezra Zygmuntowicz wrote:

On Nov 25, 2008, at 11:05 AM, Dave Thomas wrote:

On Nov 25, 2008, at 12:59 PM, Yukihiro Matsumoto wrote:

But your post made me think using this syntax in the future might be
impossible. It already abused somewhere (in the real code). Sigh.

I'm OK if you deprecate it in 1.9.3: I've used in just a few times, and
there are always alternatives. I just have this stupid need to stick up for
the underdog, and felt I had to react when you called the poor thing
"useless." I was worried you'd hurt its feelings.

Dave

   Rails routing code uses this method redefinition inside of itself

extensively. So I think we're stuck with it unless someone wants to rewrite
rails router ;)

Rails defines routing methods using instance_eval. It doesn't use
method self-redefinition or this literal syntax. Too bad; it's kind of
cool :)

jeremy

=end

Actions #7

Updated by Francoys_Proulx (Francois Proulx) over 15 years ago

=begin
Yukihiro Matsumoto wrote:

Ah, maybe. But this syntax can be spared for more fantastic purpose,
such as defining a method only visible from enclosing method, for
example. You can redefine a method using #define_method.

But your post made me think using this syntax in the future might be
impossible. It already abused somewhere (in the real code). Sigh.

 					matz.

Well, it's seem that i am the last man standing to save the underdog. To
me it is a definitively a feature.

I'm working now on a prolog evaluator that could be used as a librairy
extention for Ruby. i have wrote the original program in Pascal with a
lot of procedures with parameter call by reference to maximized the
performance. (I don't think that i have to explained to any of you, the
performance gain that could be obtained by using call by reference)

So i'm facing theses solutions to convert theses procedures:

  • replace theses parameters with globals values (ugly)
  • using one size array to emulate pointer (uglier)

or

declaring variables inside a method that are accessibles to all the
nested methods.

If someone have a 'rubyly correct' way's to solve my problem. I'm am
open. But keep in mind this: Prolog is a slow langage, so every
performance gain count !

As who see, i am facing a real life situation where nested methods seem
very useful and the more elegant solution.

=end

Actions #8

Updated by austin (Austin Ziegler) over 15 years ago

=begin
On Wed, Nov 26, 2008 at 1:32 PM, Francoys wrote:

As who see, i am facing a real life situation where nested methods
seem very useful and the more elegant solution.

Nested methods in Ruby don't work like they do in Pascal; they appear in
the main object scope:

class Foo
def bar
def baz
puts "baz"
end
puts "bar"
end
end

foo = Foo.new
foo.baz #=> exception
foo.bar #=> "bar"
foo.baz #=> "baz"

I'm not sure if that matters for your use case.

-austin

Austin Ziegler * * http://www.halostatue.ca/
* * http://www.halostatue.ca/feed/
*

=end

Actions #9

Updated by candlerb (Brian Candler) over 15 years ago

=begin
On Thu, Nov 27, 2008 at 03:32:18AM +0900, Francoys wrote:

declaring variables inside a method that are accessibles to all the
nested methods.

You can do this with closures:

f = lambda { |a|
x = 0
g = lambda { |b|
x += b
}
a.each { |e| g[e] }
x
}
puts f[[1,2,3]]

Or else you have objects and instance variables.

If someone have a 'rubyly correct' way's to solve my problem. I'm am
open. But keep in mind this: Prolog is a slow langage, so every
performance gain count !

Then I might question whether Ruby is the correct implementation platform
for Prolog, except perhaps as a learning exercise (in which case performance
isn't important)

As who see, i am facing a real life situation where nested methods seem
very useful and the more elegant solution.

Note that when you write

def foo
... body
end

then it's the execution of "def foo ... end" which creates and defines the
method foo on the object. But the body is not executed until the time when
foo is called.

Maybe a def which occurs inside a method body (or block) would have to
become an alias for

foo = lambda { 
  ...
}

instead. Unfortunately, this particular foo would be called using foo.call
or foo[], not foo().

Regards,

Brian.

=end

Actions #10

Updated by Francoys_Proulx (Francois Proulx) over 15 years ago

=begin
Brian Candler wrote:

On Thu, Nov 27, 2008 at 03:32:18AM +0900, Francoys wrote:

declaring variables inside a method that are accessibles to all the
nested methods.

You can do this with closures:

f = lambda { |a|
x = 0
g = lambda { |b|
x += b
}
a.each { |e| g[e] }
x
}
puts f[[1,2,3]]

Or else you have objects and instance variables.

If someone have a 'rubyly correct' way's to solve my problem. I'm am
open. But keep in mind this: Prolog is a slow langage, so every
performance gain count !

Then I might question whether Ruby is the correct implementation platform
for Prolog, except perhaps as a learning exercise (in which case performance
isn't important)

As who see, i am facing a real life situation where nested methods seem
very useful and the more elegant solution.

Note that when you write

def foo
... body
end

then it's the execution of "def foo ... end" which creates and defines the
method foo on the object. But the body is not executed until the time when
foo is called.

Maybe a def which occurs inside a method body (or block) would have to
become an alias for

foo = lambda {
...
}

instead. Unfortunately, this particular foo would be called using foo.call
or foo[], not foo().

Regards,

Brian.

Brian: It's have everything to do with variable and nothing about function


technic 1 (bad)

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(x,y,z)
.....
end

def foo2(x,y,z)
......
end

def foo3(x,y,z)
.....
end

le content of a_lst, b_lst, c_lst are will be modify by foo1, foo2, foo3

foo(x,y,z)
a_lst, b_lst, c_lst = foo1(x,y,z)
a_lst, b_lst, c_lst = foo2(a_lst, b_lst, c_lst)
a_lst, b_lst, c_lst = foo3(a_lst, b_lst, c_lst)
return a_lst, b_lst, c_lst
end

p( foo(a_list, b_list, c_list))

in this case scenario: 6 lists ares needed !


technic 2 (faster and better because it's create less list, but i do not
like globals variables)

$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

foo()
foo1()
foo2()
foo3()
end

foo()
p $a_list, $b_list, $c_list

in this case scenario: 3 lists ares needed !


technic 3 (faster, and smarter because lists cease to exist with the end
of execution of p )

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()


An prolog's interpreter done with an interpretor. I would probably
questioned the sanity of the programmer, myself.
But it is a Prolog engine ( a WAM class) that could be used as an
interpretor.

As you know, Prolog is a zombie language ( not really dead, not really
alive ...)
The basics types of Prolog are : Int , Char and Prolog list.

Replace theses types with Ruby objects and Prolog list and you have a
very different mix in the blender with lot a potential, a kind of
Prolog++ with domain and classes.

All the existing implementation never seem to have the rights primitives.
If you give to the programmer the possibility to extent with theres owns
primitives in Ruby,
you got something lot more flexible.

Why a WAM class? For the same reason of the Continuation class exist.
To make great thing with fews lines of code.
And for some types of problems, declarative language are unbeatable.

=end

Actions #11

Updated by candlerb (Brian Candler) over 15 years ago

=begin
On Fri, Nov 28, 2008 at 03:41:40AM +0900, Francoys wrote:


technic 1 (bad)

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(x,y,z)
.....
end

def foo2(x,y,z)
......
end

def foo3(x,y,z)
.....
end

le content of a_lst, b_lst, c_lst are will be modify by foo1, foo2, foo3

foo(x,y,z)
a_lst, b_lst, c_lst = foo1(x,y,z)
a_lst, b_lst, c_lst = foo2(a_lst, b_lst, c_lst)
a_lst, b_lst, c_lst = foo3(a_lst, b_lst, c_lst)
return a_lst, b_lst, c_lst
end

p( foo(a_list, b_list, c_list))

in this case scenario: 6 lists ares needed !

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.

Now, if foo1, foo2 and foo3 each modify the lists (as you say), then they
don't even need to return them. You could just do:

def foo(x,y,z)
foo1(x,y,z)
foo2(x,y,z)
foo3(x,y,z)
end

foo(a_list, b_list, c_list)
p a_list, b_list, c_list


technic 2 (faster and better because it's create less list, but i do not
like globals variables)

$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

foo()
foo1()
foo2()
foo3()
end

foo()
p $a_list, $b_list, $c_list

in this case scenario: 3 lists ares needed !

That ends up being pretty much the same as my modified example above, except
that I didn't use any globals.

As you're probably aware, after execution of

op1($a_list, $b_list, $c_list)

those three global variables must still be pointing to the same objects -
the references are passed by value. However op1 can mutate those objects.


technic 3 (faster, and smarter because lists cease to exist with the end
of execution of p )

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()

No, not faster or necessarily smarter. Objects are not destroyed when they
drop out of scope; they are destroyed after they no longer have any live
references, when the next garbage collection is done.

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 (A A), @b, @c = a,b,c
end
def foo1
op1(@A (A A), @b, @c)
# or perhaps: @A (A A), @b, @c = op1(@A (A 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 (A 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.

=end

Actions #12

Updated by dblack (David Black) over 15 years ago

=begin
Hi --

On Fri, 28 Nov 2008, Daniel Luz wrote:

Isn't the current behavior the same as using def self.foo?

For example:

class C
def foo1
def bar
:bar
end
end

def foo2
def self.bar
:bar
end
end
end

I haven't checked how the first case works internally, but my first
impression is that foo1 and foo2 would do precisely the same (only the
second form is somewhat more documented, being particularly common for
defining class methods).

They're not the same. self.bar is a singleton method on whatever
instance of C just called foo2. The bar in foo1 is an instance method
of C, so any instance of C can call it.

class C
def a
def b
puts "In C#b"
end
end

def x
  def self.y
    puts "In singleton method y"
  end
end

end

c = C.new
c.a # create b, using a C instance
d = C.new
d.b # call b on a different C instance

c.x
c.y # singleton method of c
d.y # error: d doesn't have y

David

--
Rails training from David A. Black and Ruby Power and Light:
INTRO TO RAILS (Jan 12-15) | ADVANCING WITH RAILS (Jan 19-22) *
Both in Fort Lauderdale, FL * Co-taught with Patrick Ewing
See http://www.rubypal.com for details
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2)

=end

Actions #13

Updated by Francoys_Proulx (Francois Proulx) over 15 years ago

=begin
Diogo Lisboa wrote:

On Wed, Nov 26, 2008 at 4:32 PM, Francoys wrote:

declaring variables inside a method that are accessibles to all the
nested methods.

This isn't possible though.

def foo
bar = 10
def gazonk
p bar
end
end

gazonk # => undefined local variable or method gazonk' foo # => nil gazonk # => undefined local variable or method bar'

This doesn't work because the chained method is in a whole new scope
which doesn't know anything about the outer method's local variables.

But, however odd this functionality is, I think it would be useful for
the enclosing method to inherit the outer scope. You'd get something
like named closures, and calling gazonk' after foo' would be able to
print 10.

However, this wouldn't be consistent, meaning, it should have to work
if you declared a local variable in a class definition and all the
methods would be aware of that; at this point, things get ugly.

I think the idea of 'named closure' could be interesting (I don't know
what consequences this would have, but sounds like a feature more than
a bug). It beats returning lambdas in an array.

Would you, enlightened ones, share your opinions on this? On the idea
of the local methods being a bug or feature, I don't think they count
much as a feature the way they currently are.

Diogo

Try this one:

def foo
@bar = 10
def gazonk
print @bar
end
gazonk
end

foo

Everything is an object in Ruby ...

<title></title> Diogo Lisboa wrote:
On Wed, Nov 26, 2008 at 4:32 PM, Francoys  wrote:
   
declaring variables inside a method that are accessibles to all the
 nested methods.
     
 This isn't possible though.

def foo
bar = 10
def gazonk
p bar
end
end

gazonk # => undefined local variable or method `gazonk'
 foo  # => nil
 gazonk # => undefined local variable or method `bar'
       

This doesn't work because the chained method is in a whole new scope
which doesn't know anything about the outer method's local variables.

But, however odd this functionality is, I think it would be useful for
the enclosing method to inherit the outer scope. You'd get something
like named closures, and calling gazonk' after foo' would be able to
print 10.

However, this wouldn't be consistent, meaning, it should have to work
if you declared a local variable in a class definition and all the
methods would be aware of that; at this point, things get ugly.

I think the idea of 'named closure' could be interesting (I don't know
what consequences this would have, but sounds like a feature more than
a bug). It beats returning lambdas in an array.

Would you, enlightened ones, share your opinions on this? On the idea
of the local methods being a bug or feature, I don't think they count
much as a feature the way they currently are.

Diogo

Try this one:

def foo
  @bar = 10
  def gazonk
    print @bar
  end
  gazonk
end

foo


Everything is an object in Ruby ...

=end

Actions #14

Updated by dblack (David Black) over 15 years ago

=begin
Hi --

On Sat, 29 Nov 2008, Francoys wrote:

Diogo Lisboa wrote:

On Wed, Nov 26, 2008 at 4:32 PM, Francoys wrote:

declaring variables inside a method that are accessibles to all the
nested methods.

This isn't possible though.

def foo
bar = 10
def gazonk
p bar
end
end

gazonk # => undefined local variable or method gazonk' foo # => nil gazonk # => undefined local variable or method bar'

This doesn't work because the chained method is in a whole new scope
which doesn't know anything about the outer method's local variables.

But, however odd this functionality is, I think it would be useful for
the enclosing method to inherit the outer scope. You'd get something
like named closures, and calling gazonk' after foo' would be able to
print 10.

However, this wouldn't be consistent, meaning, it should have to work
if you declared a local variable in a class definition and all the
methods would be aware of that; at this point, things get ugly.

I think the idea of 'named closure' could be interesting (I don't know
what consequences this would have, but sounds like a feature more than
a bug). It beats returning lambdas in an array.

Would you, enlightened ones, share your opinions on this? On the idea
of the local methods being a bug or feature, I don't think they count
much as a feature the way they currently are.

Diogo

Try this one:

def foo
@bar = 10
def gazonk
print @bar
end
gazonk
end

foo

That's very different, though, because you're redefining your inner
method every time any instance of the class calls the outer method,
and you're using instance variables so there's no closure effect.

class C
def x
@A (A A) = 1
def y
p @A (A A)
end
end
end

c = C.new
c.x
c.y # 1
d = C.new
d.y # nil

David

--
Rails training from David A. Black and Ruby Power and Light:
INTRO TO RAILS (Jan 12-15) | ADVANCING WITH RAILS (Jan 19-22) *
Both in Fort Lauderdale, FL * Co-taught with Patrick Ewing
See http://www.rubypal.com for details
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2)

=end

Actions #15

Updated by Francoys_Proulx (Francois Proulx) over 15 years ago

=begin
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 (A A), @b, @c = a,b,c
end
def foo1
op1(@A (A A), @b, @c)
# or perhaps: @A (A A), @b, @c = op1(@A (A 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 (A 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

=end

Actions #16

Updated by candlerb (Brian Candler) over 15 years ago

=begin
On Sat, Nov 29, 2008 at 04:22:15AM +0900, Francoys wrote:

But your Lambda's version is very tempting, but my experience with the
use of Proc come at the price of performance penalty.

Beware (a) premature optimisation, and (b) using your intuition to decide
where hotspots are. Even the most experienced programmers usually get it
wrong if they try to guess where to optimise. Profile first, optimise later.

In any case, Ruby is about writing programs which are elegant and easy to
maintain; performance is secondary. Don't fight the language. If you are
trying to write spaghetti Ruby just to gain a 5% performance benefit, then
you would be better off writing in a completely different language.


def foo4

@bar = 10

def gazonk
print @bar
end

gazonk
end

foo4

This doesn't work the way you expect.

What happens here is that every time you call foo4, you are actually
redefining the method 'gazonk' in the top level object. So now you have
the worst of all possible worlds; unnecessarily bad performance, and still
no sharing of local variables.

That is: in Ruby, "def xxx ... end" defines a method when the def statement
is actually executed. Normally you write these statements inside a class
statement, so they are only executed once (when the file is run). But if you
stick a def statement inside a loop, or inside a method body, then it will
redefine the method repeatedly.

However you can avoid the performance penalty by rewriting your code above
simply as:

def gazonk
print @bar
end

def foo4
@bar = 10
gazonk
end

This is perfectly fine and reasonable Ruby.

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

This will work fine without using instance variables. But since you're not
posting real code here, only dummy stuff, I can't be sure where you're going
wrong.

Perhaps in op1() you are reassigning @a_list to point to a different object.
(But in that case, there is no point passing in @a_list and friends as
arguments).

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 *.

Wrong.

Ruby's approach is different to other languages - perhaps you can call it
radical if you've not seen it before.

In Ruby, every value is an object reference. Absolutely every value. So:

def foo
puts foo.object_id
end

a = 1
foo(a) # pass a single object reference

a = [1,2,3]
foo(a) # pass a single object reference

In both calls to foo, a single object reference is passed. There is no
'cloning' of anything. The references are passed by value (copied, if you
like), but the objects themselves are not cloned.

I'm afraid I was as guilty as anyone when I first came to Ruby: jumping in
with "why doesn't Ruby do this" or "I expected it to do that" or "wouldn't
it be better if it did the other". My advice is: go with the flow. Relax,
expand your mind, open yourself to new concepts which may not be the same as
what you're familiar with. Learn how these may enhance your programming; by
all means compare and contrast with what you know, but don't reject what's
new out of hand. Sure, other languages may have advantages over Ruby, but
you may also find that you can do things in Ruby much more easily than you
could do before.

I'd also suggest this discussion would be better suited to ruby-talk rather
than ruby-core.

Regards,

Brian.

=end

Actions #17

Updated by murphy (Kornelius Kalnbach) over 15 years ago

=begin

Am 28.11.2008 um 16:31 schrieb Francoys :

Diogo Lisboa wrote:

On Wed, Nov 26, 2008 at 4:32 PM, Francoys
wrote:

declaring variables inside a method that are accessibles to all the
nested methods.

This isn't possible though.

def foo
bar = 10
def gazonk
p bar
end
end

gazonk # => undefined local variable or method gazonk' foo # => nil gazonk # => undefined local variable or method bar'

This doesn't work because the chained method is in a whole new scope
which doesn't know anything about the outer method's local variables.

But, however odd this functionality is, I think it would be useful
for
the enclosing method to inherit the outer scope. You'd get something
like named closures, and calling gazonk' after foo' would be able
to
print 10.

However, this wouldn't be consistent, meaning, it should have to work
if you declared a local variable in a class definition and all the
methods would be aware of that; at this point, things get ugly.

I think the idea of 'named closure' could be interesting (I don't
know
what consequences this would have, but sounds like a feature more
than
a bug). It beats returning lambdas in an array.

Would you, enlightened ones, share your opinions on this? On the idea
of the local methods being a bug or feature, I don't think they count
much as a feature the way they currently are.

Diogo

Try this one:

def foo
@bar = 10
def gazonk
print @bar
end
gazonk
end

foo

Everything is an object in Ruby ...
Except methods...sadly. def, class, module, alias etc. don't return
anything. It's hard to explain these things to Python or JavaScript
programmers.

[murphy]



Am 28.11.2008 um 16:31 schrieb Francoys <>:

Diogo Lisboa wrote:

On Wed, Nov 26, 2008 at 4:32 PM, Francoys > wrote:
   
declaring variables inside a method that are accessibles to all the
 nested methods.
     
This isn't possible though.

def foo
bar = 10
def gazonk
p bar
end
end

gazonk # => undefined local variable or method `gazonk'
 foo  # => nil
 gazonk # => undefined local variable or method `bar'
       
 This doesn't work because the chained method is in a whole new scope
 which doesn't know anything about the outer method's local variables.

But, however odd this functionality is, I think it would be useful for
the enclosing method to inherit the outer scope. You'd get something
like named closures, and calling gazonk' after foo' would be able to
print 10.

However, this wouldn't be consistent, meaning, it should have to work
if you declared a local variable in a class definition and all the
methods would be aware of that; at this point, things get ugly.

I think the idea of 'named closure' could be interesting (I don't know
what consequences this would have, but sounds like a feature more than
a bug). It beats returning lambdas in an array.

Would you, enlightened ones, share your opinions on this? On the idea
of the local methods being a bug or feature, I don't think they count
much as a feature the way they currently are.

Diogo

Try this one:

def foo
  @bar = 10
  def gazonk
    print @bar
  end
  gazonk
end

foo


Everything is an object in Ruby ...
Except methods...sadly. def, class, module, alias etc. don't return anything. It's hard to explain these things to Python or JavaScript programmers.

[murphy]
=end
Actions #18

Updated by rogerdpack (Roger Pack) over 15 years ago

=begin

Everything is an object in Ruby ...

Except methods...sadly. def, class, module, alias etc. don't return
anything. It's hard to explain these things to Python or JavaScript
programmers.
[murphy]

#instance_method does

-=r
http://betterlogic.com/roger/?p=537
http://betterlogic.com/roger/?p=708

=end

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0