nested defs, what if...

  • Thread starter Hugh Sasse Staff Elec Eng
  • Start date
H

Hugh Sasse Staff Elec Eng

This is too half-baked to be an RCR, but here goes...

At the moment we cannot write

class Thingy
def somefunc
def newfunc
...
end
end
end

OK, fair enough, somefunc is an instance method, so what would
newfunc get defined as? It could not be an instance method because
it might depend on variables having values which differ in another
instance.

So, my half-baked idea: let the above code be a shorthand for

class Thingy
def somefunc
class << self
def newfunc
...
end
end
end
end

This would have the [questionable] advantage that it would hide that
relatively obscure class << self syntax used in constructing
singletons, and it would be better tnan passing a string to instance
eval because it would get syntax highlighted by the editor.

It is not legal now, so old code would not break.

So, now I'll push this idea out and see if it sinks...

Hugh
 
A

Austin Ziegler

This is too half-baked to be an RCR, but here goes...

At the moment we cannot write

class Thingy
def somefunc
def newfunc
...
end
end
end

irb(main):001:0> class Thingy
irb(main):002:1> def somefunc
irb(main):003:2> def newfunc
irb(main):004:3> end
irb(main):005:2> end
irb(main):006:1> end
irb(main):007:0> Thingy.instance_methods.grep(/func/)
=> ["somefunc"]
irb(main):009:0> Thingy.new.somefunc
=> nil
irb(main):010:0> Thingy.instance_methods.grep(/func/)
=> ["newfunc", "somefunc"]

-austin
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: nested defs, what if..."

|So, my half-baked idea: let the above code be a shorthand for
|
|class Thingy
| def somefunc
| class << self
| def newfunc
| ...
| end
| end
| end
|end

I had the same half-baked idea before, but has not been sure how much
it is useful. If you come up a new insight, it might be happened.

matz.
 
H

Hugh Sasse Staff Elec Eng

irb(main):007:0> Thingy.instance_methods.grep(/func/)
=> ["somefunc"]
irb(main):009:0> Thingy.new.somefunc
=> nil
irb(main):010:0> Thingy.instance_methods.grep(/func/)
=> ["newfunc", "somefunc"]

OH!! This didn't work in the past. I never noticed it change.

I'll have to see what happens when it depends on variable values
then ...

Hugh (somewhat embarrassed)
 
H

Hugh Sasse Staff Elec Eng

Hi, [...]
I had the same half-baked idea before, but has not been sure how much
it is useful. If you come up a new insight, it might be happened.

matz.

Thanks, Matz. If I get struck by any "bolts of inspiration" I'll
let you know.
Thank you,
Hugh
 
B

Brian Schröder

This is too half-baked to be an RCR, but here goes...

At the moment we cannot write

class Thingy
def somefunc
def newfunc
...
end
end
end

irb(main):001:0> class Thingy
irb(main):002:1> def somefunc
irb(main):003:2> def newfunc
irb(main):004:3> end
irb(main):005:2> end
irb(main):006:1> end
irb(main):007:0> Thingy.instance_methods.grep(/func/)
=> ["somefunc"]
irb(main):009:0> Thingy.new.somefunc
=> nil
irb(main):010:0> Thingy.instance_methods.grep(/func/)
=> ["newfunc", "somefunc"]

But where is this usefull? It seems only complicated and inefficent to me
(Doesn't it create a new instance method on each call?):

class A
def a()
def b()
self
end
self
end
end
==>nil
A.new.b
NoMethodError: undefined method `b' for #<A:0x402c0834>
from (irb):2
A.new.a
==>#<A:0x402a9cb0>
A.new.a.b
==>#<A:0x4029bad4>
A.new.b
==>#<A:0x40295864>
 
T

trans. (T. Onoma)

On Thursday 02 December 2004 12:22 pm, Brian Schröder wrote:
| But where is this usefull? It seems only complicated and inefficent to me
| (Doesn't it create a new instance method on each call?):
|
| class A
| def a()
| def b()
| self
| end
| self
| end
| end
| ==>nil
| A.new.b
| NoMethodError: undefined method `b' for #<A:0x402c0834>
| from (irb):2
| A.new.a
| ==>#<A:0x402a9cb0>
| A.new.a.b
| ==>#<A:0x4029bad4>
| A.new.b
| ==>#<A:0x40295864>

It is interesting. Does this mean that an _object_ could dynamically change
the state of all objects of its class? I have to test....

class T
def a
def b
puts "Hello"
end
end
end => nil
t = T.new => #<T:0x4032cb14>
t2 = T.new => #<T:0x4032ae90>
t.b => NoMethodError: undefined method `b' for #<T:0x4032cb14>
t2.b => NoMethodError: undefined method `b' for #<T:0x4032ae90>
t.a => nil
t.b => nil
Hello
t2.b => nil
Hello

Yep. It sure does. This is very strange indeed. I wonder if you could write
extentions in this way.

class String
def use(x)
case x
when :chars
def chars
self.split(//)
end
when :tab
# ...
end
end
end

Of course, you have to instantiate a string first.

Well, it's an idea, but I don't think a very good one. In general I don't
think this is useful, and would rather obfuscate code if actually used. I
think what would be more useful is if such methods were local methods, like
local variables:

class A
def a
def b(x)
x + 1
end
10.times{ |i| print b(i) }
end
end

o = A.new
o.b => NoMethodError
A.a => 12345678910
o.b => NoMethodError

This would allow for embedded subroutines --much more useful.

T.
 
N

nobu.nokada

Hi,

At Fri, 3 Dec 2004 08:20:34 +0900,
trans. (T. Onoma) wrote in [ruby-talk:122265]:
Well, it's an idea, but I don't think a very good one. In general I don't
think this is useful, and would rather obfuscate code if actually used. I
think what would be more useful is if such methods were local methods, like
local variables:

I also have thought the idea, though haven't implemented it.
I'm still worndering whether this should be valid or error.

class A
def a(y)
def b(x)
x + y # `y' in a or `undefined local variable'?
end
10.times{ |i| print b(i) }
end
end
 
G

Gavin Sinclair

At Fri, 3 Dec 2004 08:20:34 +0900,
trans. (T. Onoma) wrote in [ruby-talk:122265]:
Well, it's an idea, but I don't think a very good one. In general I don't
think this is useful, and would rather obfuscate code if actually used. I
think what would be more useful is if such methods were local methods, like
local variables:
I also have thought the idea, though haven't implemented it.
I'm still worndering whether this should be valid or error.
class A
def a(y)
def b(x)
x + y # `y' in a or `undefined local variable'?
end
10.times{ |i| print b(i) }
end
end

Is there any difference between an "inner method" (with 'y' in a) and
a lambda?

I've happily used lambdas to define private functionality before, but
I'm concerned about efficiency:

class A
def a(y)
b = lambda { |x| x + y }
10.times { |i| print b(i) }
end
end

Does the lambda attached to b get regenerated with each call to a?

Gavin
 
N

nobu.nokada

Hi,

At Fri, 3 Dec 2004 14:00:44 +0900,
Gavin Sinclair wrote in [ruby-talk:122305]:
Is there any difference between an "inner method" (with 'y' in a) and
a lambda?

Actually, no. Just a syntax sugar, and it would be implemented
using a lambda. And another question; should b be visible from
other methods called from a?
I've happily used lambdas to define private functionality before, but
I'm concerned about efficiency:

class A
def a(y)
b = lambda { |x| x + y }
10.times { |i| print b(i) }
end
end

Does the lambda attached to b get regenerated with each call to a?

I guess so.
 
G

Gavin Sinclair

At Fri, 3 Dec 2004 14:00:44 +0900,
Gavin Sinclair wrote in [ruby-talk:122305]:
Is there any difference between an "inner method" (with 'y' in a) and
a lambda?
Actually, no. Just a syntax sugar, and it would be implemented
using a lambda. And another question; should b be visible from
other methods called from a?

I don't think so. I can't imagine a use case, and the _appearance_ of
the code is that b() is private to a().
I guess so.

So an inner method, which _looks_ static, would actually be
inefficiently regenerated each time? (You said the inner method would
be syntax sugar for a lambda.)

Gavin
 
T

trans. (T. Onoma)

Hi --

122305]:
| > > class A
| > > def a(y)
| > > def b(x)
| > > x + y # `y' in a or `undefined local variable'?
| > > end
| > > 10.times{ |i| print b(i) }
| > > end
| > > end
| >
| > Is there any difference between an "inner method" (with 'y' in a) and
| > a lambda?
|
| Actually, no. Just a syntax sugar, and it would be implemented
| using a lambda. And another question; should b be visible from
| other methods called from a?

First, it is debatable as to whether `y' should have an open scope like a
lambda. But I think "no". def a() cannot see vars outside its scope either,
so nor should def b(). This gives good inner namespace protection and
differentiates its functionality from a lambda. Second, b() should not be
visible from other methods just a local vars are not visible.

I am surprised to hear they would be implemented using lambdas. I was under
the impression that implementation of Procs and Methods are quite different.

| > I've happily used lambdas to define private functionality before, but
| > I'm concerned about efficiency:
| >
| > class A
| > def a(y)
| > b = lambda { |x| x + y }
| > 10.times { |i| print b(i) }
| > end
| > end
| >
| > Does the lambda attached to b get regenerated with each call to a?

Yes, I think so since lambdas are not singleton/multiton (could they be?) Of
course the fix is something like:

class A
def a(y)
@a_b ||= lambda { |x| x + y }
10.times { |i| print @a_b(i) }
end
end

But true inner methods would be the bomb for these use cases (IMHO).

T.
 
T

trans. (T. Onoma)

On Friday 03 December 2004 12:37 am, Gavin Sinclair wrote:
| So an inner method, which _looks_ static, would actually be
| inefficiently regenerated each time? (You said the inner method would
| be syntax sugar for a lambda.)

Yea, that's not good. They need to persist, bound to the local scope.

T.
 
K

Kevin Bullock

Well, it's an idea, but I don't think a very good one. In general I
don't
think this is useful, and would rather obfuscate code if actually
used. I
think what would be more useful is if such methods were local methods,
like
local variables:

class A
def a
def b(x)
x + 1
end
10.times{ |i| print b(i) }
end
end

o = A.new
o.b => NoMethodError
A.a => 12345678910
o.b => NoMethodError

This would allow for embedded subroutines --much more useful.

This would also make Ruby more like LISP, which allows any depth of
inner functions to be defined. Those inner functions are only in scope
in the defining function.

Ruby's blocks function this way right now, actually. That is, to
achieve the above effect, you could do:

class A
def a
b = proc do |x|
x + 1
end
10.times { |i| print b.call(i) }
end
end

o = A.new
==>#<A:0x49708>
o.b
NoMethodError: undefined method `b' for #<A:0x49708>
from (irb):10
o.a
12345678910 ==>10
o.b
NoMethodError: undefined method `b' for #<A:0x49708>
from (irb):13

In this example, b is a reference to a block, rather than a method, and
b is only in scope within a().

Embedded subroutines can indeed be useful, especially in recursive
methods that use an "interface method" and a "worker method" that takes
extra parameters. For example:

def fact( n )
def fact_iter( n, total )
if n == 1
total
else
fact_iter( n - 1, total * n )
end
end

fact_iter( n, 1 )
end

fact( 3 ) ==> 6

In this case, fact_iter() doesn't need to be visible to the outside
world; but the way Ruby currently works, the following can happen:

fact_iter( 3 ) ==> 6

The question becomes, though, whether or not fact_iter() is being
defined every time fact() is called. It shouldn't be hard to optimize
around this redefinition problem. (Does Ruby already do so?)

Pacem in terris / Mir / Shanti / Salaam / Heiwa
Kevin R. Bullock
 
M

Mauricio Fernández

Yes, I think so since lambdas are not singleton/multiton (could they be?) Of
course the fix is something like:

class A
def a(y)
@a_b ||= lambda { |x| x + y }
10.times { |i| print @a_b(i) }
end
end

Not quite...
class A; def a(y); @a_b ||= lambda { |x| x + y }; 10.times { |i|
print @a_b}; end end => nil
a = A.new
=> # said:
a.a(10) 10111213141516171819=> 10
a.a(1000)

10111213141516171819=> 10
But true inner methods would be the bomb for these use cases (IMHO).

They don't seem any more powerful than lambdas, just sugar.
They would offer some opportunities for optimization though.
 
B

Brian Schröder

[snip]
Well, it's an idea, but I don't think a very good one. In general I don't
think this is useful, and would rather obfuscate code if actually used. I
think what would be more useful is if such methods were local methods, like
local variables:

class A
def a
def b(x)
x + 1
end
10.times{ |i| print b(i) }
end
end

o = A.new
o.b => NoMethodError
A.a => 12345678910
o.b => NoMethodError

This would allow for embedded subroutines --much more useful.

I tried this in fact while learning ruby, and was disappointed, that it did not
work the way I expected. The last language before Ruby was Delphi (Object
Pascal) where you can have nested subroutines. I think they are a lot clearer
than having to flatten everything out.

Regards,

Brian
 
T

trans. (T. Onoma)

02:49PM +0900, trans. (T. Onoma) wrote:
| > Yes, I think so since lambdas are not singleton/multiton (could they be?)
| > Of course the fix is something like:
| >
| > class A
| > def a(y)
| > @a_b ||= lambda { |x| x + y }
| > 10.times { |i| print @a_b(i) }
| > end
| > end
|
| Not quite...
| >> class A; def a(y); @a_b ||= lambda { |x| x + y }; 10.times { |i|
| >> print @a_b}; end end
| => nil
| >> a = A.new
| => #<A:0x401fda10>
| >> a.a(10)
| 10111213141516171819=> 10
| >> a.a(1000)
| 10111213141516171819=> 10

Ah right. There's a gotchya. Try,

class A
def a(y)
@a_b ||= lambda { |x,y| x + y }
10.times { |i| print @a_b(i,y) }
end
end

I think this is another reason for having the inner defs with a protected
scope.

| > But true inner methods would be the bomb for these use cases (IMHO).
|
| They don't seem any more powerful than lambdas, just sugar.
| They would offer some opportunities for optimization though.

Depends on the meaning of "powerful". But see above. Scope isolation can be
advantageous. And, yes, optimization would be nice too.

T.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top