Bug #797
closedbug or feature: local method ?
Added by Francoys_Proulx (Francois Proulx) almost 16 years ago. Updated over 13 years ago.
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
Updated by matz (Yukihiro Matsumoto) almost 16 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 redmine@ruby-lang.org 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
Updated by matz (Yukihiro Matsumoto) almost 16 years ago
- Status changed from Open to Closed
=begin
=end
Updated by pragdave (Dave Thomas) almost 16 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
Updated by matz (Yukihiro Matsumoto) almost 16 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 dave@pragprog.com 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
Updated by pragdave (Dave Thomas) almost 16 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
Updated by bitsweat (Jeremy Daer) almost 16 years ago
=begin
On Tue, Nov 25, 2008 at 12:20 PM, Ezra Zygmuntowicz ezmobius@gmail.com 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
Updated by Francoys_Proulx (Francois Proulx) almost 16 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
Updated by austin (Austin Ziegler) almost 16 years ago
=begin
On Wed, Nov 26, 2008 at 1:32 PM, Francoys francois.pr@videotron.ca 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 * halostatue@gmail.com * http://www.halostatue.ca/
* austin@halostatue.ca * http://www.halostatue.ca/feed/
* austin@zieglers.ca
=end
Updated by candlerb (Brian Candler) almost 16 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
Updated by Francoys_Proulx (Francois Proulx) almost 16 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
endthen 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 forfoo = 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
Updated by candlerb (Brian Candler) almost 16 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_linkdef foo1(x,y,z)
.....
enddef foo2(x,y,z)
......
enddef foo3(x,y,z)
.....
endle 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
endp( 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_linkdef foo1()
op1($a_list,$b_list,$c_list)
enddef foo2()
op2($a_list,$b_list,$c_list)
enddef foo3()
op2($a_list,$b_list,$c_list)
endfoo()
foo1()
foo2()
foo3()
endfoo()
p $a_list, $b_list, $c_listin 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_linkdef foo1()
op1(a_list,b_list,c_list)
enddef foo2() op2(a_list,b_list,c_list) end def foo3() op2(a_list,b_list,c_list) end
foo1()
foo2()
return foo3()
endp 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
Updated by dblack (David Black) almost 16 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
enddef foo2
def self.bar
:bar
end
end
endI 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
Updated by Francoys_Proulx (Francois Proulx) almost 16 years ago
=begin
Diogo Lisboa wrote:
On Wed, Nov 26, 2008 at 4:32 PM, Francoys francois.pr@videotron.ca 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
endgazonk # => 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 callinggazonk' 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:Try this one:On Wed, Nov 26, 2008 at 4:32 PM, Francoys <francois.pr@videotron.ca> 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
endgazonk # => 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 callinggazonk' 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
def foo
@bar = 10
def gazonk
print @bar
end
gazonk
end
foo
Everything is an object in Ruby ...
=end
Updated by dblack (David Black) almost 16 years ago
=begin
Hi --
On Sat, 29 Nov 2008, Francoys wrote:
Diogo Lisboa wrote:
On Wed, Nov 26, 2008 at 4:32 PM, Francoys francois.pr@videotron.ca 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
endgazonk # => 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 callinggazonk' 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
endfoo
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
Updated by Francoys_Proulx (Francois Proulx) almost 16 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
...
enddef 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
endNotice 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 even10.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
Updated by candlerb (Brian Candler) almost 16 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
endgazonk
endfoo4¶
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
Updated by murphy (Kornelius Kalnbach) almost 16 years ago
=begin
Am 28.11.2008 um 16:31 schrieb Francoys francois.pr@videotron.ca:
Diogo Lisboa wrote:
On Wed, Nov 26, 2008 at 4:32 PM, Francoys
francois.pr@videotron.ca 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
endgazonk # => 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 callinggazonk' 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
endfoo
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]
Except methods...sadly. def, class, module, alias etc. don't return anything. It's hard to explain these things to Python or JavaScript programmers.Diogo Lisboa wrote:
Try this one:On Wed, Nov 26, 2008 at 4:32 PM, Francoys <francois.pr@videotron.ca> 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
endgazonk # => 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 callinggazonk' 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
def foo
@bar = 10
def gazonk
print @bar
end
gazonk
end
foo
Everything is an object in Ruby ...
Updated by rogerdpack (Roger Pack) almost 16 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