Python-style decorators

On 8/31/07, Trans [email protected] wrote:

I fail to grasp where exactly you hit that wall, I have this

X.foo #=> foo

This proves impossible to do in a modular fashion because you can’t
extend a class with a singleton class.

But you may well be right about the current case, hence the potential
solution I posted.

Still trying to get the problem
I know that you know (do I?) that you can do
module M
def foo; “foo” end
end
class X
extend M
end

where’s the catch?
R.

On Aug 31, 12:47 pm, “Robert D.” [email protected] wrote:

Still trying to get the problem
I know that you know (do I?) that you can do
module M
def foo; “foo” end
end
class X
extend M
end

where’s the catch?

When you want class-level methods that go along with your instance
methods.

module M
def self.foo
@foo ||= {}
end
def foo
self.class.foo
end
end

Class X
include M
end

X.new.foo #=> ERROR

If one could include singletons, the solution would be as simple as:

class X
extend(class << Foo; self; end)
end

But as things are you need some sort of “trick”.

T.

On Aug 31, 11:27 am, “Keith R.” [email protected] wrote:

[snip]

end
10 + @x
end

end

p X.new.try

If try were really bound to the instance of X, this would produce 13.
But it produces 15.

Fudge Nuts! Well, I knew something was a miss. I know Ruby too well to
expect that to work :wink:

And I don’t think Pit Captain could even wrangle up a solution to this
one. Oh well. Guess it’s back to the method_added or block notation.
Which is too bad, b/c not you have to make a choice between the
readability to the former and the reliability of the later.

T.

On 8/31/07, Trans [email protected] wrote:

extend M
end

If one could include singletons, the solution would be as simple as:

class X
extend(class << Foo; self; end)
end

But as things are you need some sort of “trick”.
Ok I think I got it, thx, I was indeed trying to make Keith’s
def self.fooized
def fooized.try
code work but did not see how this was related to the general problem
of yours. That is because I got confused what is defined where, well
this really is sometimes quite embarrassing, I was sure to get it
done, but no such luck … :frowning:
Thx
Robert

On Fri, Aug 31, 2007 at 08:18:38AM +0900, Keith R. wrote:

  1. An unbound method (such as what you get by calling
    foo.method(:bar).unbind) can only be bound to an object of the same
    type as the original receiver. For singleton methods, this means that
    they can only be bound to the very same object.

Nodewrap lets you do this, but it’s not safe:

irb(main):001:0> class Foo; def foo; puts “HERE”; end; end
=> nil
irb(main):002:0> class Bar; end
=> nil
irb(main):005:0> Bar.add_method(:bar, Foo.instance_method(:foo).body, 0)
=> nil
irb(main):006:0> Bar.new.bar
HERE
=> nil

Paul

Keith R. wrote:

I’d love to hear feedback about this library! If you have any comments
or questions, please let me know.

Depending on how you’ve implemented it, the declarative style is not
thread-safe. You would need to ensure that the decorators are only
aggregated in the current thread, rather than in the class/metaclass for
example, since they would step on each other in the latter case. This is
because aggregating decorators and eventually applying them to some
syntactic construct is not atomic; things can happen between each
aggregation and the eventual consumption.

The imperative version would be safer, since it could largely be made
atomic.

I like the idea in general though. I proposed (and roughly implemented)
something similar for JRuby to be able to compile to static Java
signatures, while still providing fully dynamic bodies:

class Foo
signature [String, Fixnum]
def bar(a, b)

end
end

This would compile to foo(RubyString a, RubyFixnum b) with appropriate
type checks and conversions, allowing us to provide a real Java method
signature. In JRuby, this would be implemented on a per-thread-basis, or
we’d use the imperative version:

signature :bar, [String, Fixnum]

  • Charlie

On 9/4/07, Charles Oliver N. [email protected] wrote:

Depending on how you’ve implemented it, the declarative style is not
thread-safe.

You’re right; it is not. But that doesn’t bother me too much.
Shared-state concurrency is usually a bad idea. Then again, ideally
this library would be correct under all circumstances including
multiple threads.

The real problem is that ruby provides no way to intercept method
definitions as they occur. The best you can do is notice that they
happen after the fact.

The best interface would be an add_method method that one could
override. The interpreter has an add_method function in C, but it’s
not exposed to ruby code.

kr

Hi,

At Wed, 5 Sep 2007 07:21:41 +0900,
Keith R. wrote in [ruby-talk:267626]:

Nodewrap lets you do this, but it’s not safe:

That’s just what I was looking for. I don’t understand why this isn’t
built in to ruby. I would use this feature if it didn’t add an
external dependency.

Because it’s too dangerous rather than unsafe.

Hi,

At Wed, 5 Sep 2007 09:31:12 +0900,
Nobuyoshi N. wrote in [ruby-talk:267662]:

Nodewrap lets you do this, but it’s not safe:

That’s just what I was looking for. I don’t understand why this isn’t
built in to ruby. I would use this feature if it didn’t add an
external dependency.

Because it’s too dangerous rather than unsafe.

…and you have to know too deep implementation details very
well, to use it.

On 8/7/07, Keith R. [email protected] wrote:

One notable difference between the public, private, protected notation
and these decorators is that these must appear immediately before each
method they should apply to. A decorator’s effects don’t stick around
beyond the very next method, so there’s no danger of having it go
unnoticed further down the file.

Hmmmm, I’m just catching up after being too busy for a few weeks to
drink from the firehose that is ruby-talk.

I just wrote this yesterday:
http://talklikeaduck.denhaven2.com/articles/2007/09/04/block-your-privates

After noticing that some folks like ot artifically indent methods
definitions after private and its friends, it occurred to me that it
might be nice if you could write

class Foo
private do
def method1
end

def method2
end

end

end

I ran into similar issues in trying to metahack an implementation of
this idea, although I did find a way to accomplish the same effect
albeit with somewhat less pretty code, see the article for the
details.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On Wed, Sep 05, 2007 at 07:21:41AM +0900, Keith R. wrote:

On 9/4/07, Paul B. [email protected] wrote:

Nodewrap lets you do this, but it’s not safe:

That’s just what I was looking for. I don’t understand why this isn’t
built in to ruby. I would use this feature if it didn’t add an
external dependency.

Consider: what would happen if I moved #close from the IO class to the
Array class?

Paul

On 9/4/07, Paul B. [email protected] wrote:

Nodewrap lets you do this, but it’s not safe:

That’s just what I was looking for. I don’t understand why this isn’t
built in to ruby. I would use this feature if it didn’t add an
external dependency.

kr

On 9/7/07, Paul B. [email protected] wrote:

Consider: what would happen if I moved #close from the IO class to the
Array class?

There are various reasonable ways to handle errors such as this.

At first, I would expect the same behavior that would result from
taking the ruby source code for the #close method and pasting it in to
the Array class. If #close isn’t written in ruby, then don’t allow it
to be moved.

kr

On Sep 5, 12:15 am, “Keith R.” [email protected] wrote:
[…]

The real problem is that ruby provides no way to intercept method
definitions as they occur. The best you can do is notice that they
happen after the fact.
what about
http://blog.ntecs.de/articles/2004/08/16/implementing-python-decorators-in-ruby
? This seem a very useful feature to have in ruby 2.0

On 9/16/07, Matteo G. [email protected] wrote:

what about http://blog.ntecs.de/articles/2004/08/16/implementing-python-decorators-in-ruby
? This seem a very useful feature to have in ruby 2.0

Interesting. As long as we’re willing to modify the ruby interpreter,
why not just implement real decorators? There are some problems with
my interface (and the one described on ntecs.de) that I was willing to
live with in a pure ruby implementation. First, it’s not very DRY as
each decorator needs logic to lookup and replace the method and return
its name. It’s also a little fragile. Most importantly, though,
replacing the method after it’s been defined isn’t as clean as
wrapping the method object right before it gets bound to a name. Any
method_added hooks will, unfortunately, be called twice.

I’m not personally going to try getting a ruby patch accepted.

kr