Intercept setting an instance variable

I'm developing some code that needs to intercept when an instance
variable is set for a class. It needs to be arbitrary; i.e., I don't
want to have to have code declare variables differently than they do now
and I don't want them to have to create mutator methods (since it needs
to intercept non-public values as well).

I tried overriding instance_variable_set but see that that's not how
Ruby actually sets values and is just a programmatic helper method for
working with an instance.

So, does anybody know how to intercept assigning values to instance
variables? Thanks.

···

--
Darryl L. Pierce <mcpierce@gmail.com>
http://mcpierce.blogspot.com/
Famous last words:
   "I wonder what happens if we do it this way?"

This may be impossible (though I'm happy to be proven wrong). Ruby
stores instance data inside C structures that are accessed
more-or-less directly from many places in the Ruby interpreter. See
Ruby Internals | PPT (slide 16
especially) or Pat Shaughnessy if
you want the nasty details.

What are you trying to accomplish? Maybe some smart person on this
list can help you come up with a different strategy.

- A

···

On Thu, Mar 19, 2015 at 10:14 AM, Darryl L. Pierce <mcpierce@gmail.com> wrote:

So, does anybody know how to intercept assigning values to instance
variables?

--
Alex Chaffee - alex@stinky.com
http://alexchaffee.com
http://codelikethis.com
http://twitter.com/alexch

You can't, at least not without some serious C-level hacking. There are no hooks for such a thing (there are hooked variables that you can trace, but they're all globals).

This is a big reason why my code has as few "@"s as possible. Wrapping an accessor method is a lot simpler than hooking into the runtime itself.

···

On Mar 19, 2015, at 07:14, Darryl L. Pierce <mcpierce@gmail.com> wrote:

I'm developing some code that needs to intercept when an instance
variable is set for a class. It needs to be arbitrary; i.e., I don't
want to have to have code declare variables differently than they do now
and I don't want them to have to create mutator methods (since it needs
to intercept non-public values as well).

You may want to look into Aspect Oriented Programming, unfortunately I
don't have any experience with AOP in ruby so I can't recommend any
frameworks.

···

On Thu, Mar 19, 2015 at 3:14 PM, Darryl L. Pierce <mcpierce@gmail.com> wrote:

I'm developing some code that needs to intercept when an instance
variable is set for a class. It needs to be arbitrary; i.e., I don't
want to have to have code declare variables differently than they do now
and I don't want them to have to create mutator methods (since it needs
to intercept non-public values as well).

I tried overriding instance_variable_set but see that that's not how
Ruby actually sets values and is just a programmatic helper method for
working with an instance.

So, does anybody know how to intercept assigning values to instance
variables? Thanks.

--
Darryl L. Pierce <mcpierce@gmail.com>
http://mcpierce.blogspot.com/
Famous last words:
   "I wonder what happens if we do it this way?"

buenos días espero te sirva.

My project (Qpid Proton) involves wrapping a C messaging library in Ruby
(and Perl, but that's another story).

With our current "reactive" APIs, we have a C engine called the reactor
that sends fires events on state changes. From the C code it has a
reference to Ruby objects (not actual objects, that's another story as
well) that it wants to notify on these events.

So, for example, I create an instance of Qpid::Proton::Connection. It
has a Ruby-wrapped reference to a C struct (its impl) and it's that impl
that gets notified by the reactor when the connection's state changes.

When that bubbles up into the Ruby VM space, I want to be able to
recreate that instance of Connection (since the original Ruby object may
have been garbage collected). So I want to store the state values for
that object in the Proton library's record store (third, and last, long
story).

In Python we're able to do this easily. The Python Connection class
extends a class called Wrapper that overrides __getattr__ and
__setattr__ and backs it with a dict that is stored in that record
store. So if you change state info on a Connection in Python, those
changes are stored and can be fetched later to recreate that Connection
object. (remember: the impl is a C struct and never gets destroyed even
when the Ruby or Python object that used it goes away)

Does that get across the problem I'm trying to solve?

···

On Thu, Mar 19, 2015 at 12:56:25PM -0400, Alex Chaffee wrote:

On Thu, Mar 19, 2015 at 10:14 AM, Darryl L. Pierce <mcpierce@gmail.com> wrote:
> So, does anybody know how to intercept assigning values to instance
> variables?

This may be impossible (though I'm happy to be proven wrong). Ruby
stores instance data inside C structures that are accessed
more-or-less directly from many places in the Ruby interpreter. See
Ruby Internals | PPT (slide 16
especially) or Pat Shaughnessy if
you want the nasty details.

What are you trying to accomplish? Maybe some smart person on this
list can help you come up with a different strategy.

--
Darryl L. Pierce <mcpierce@gmail.com>

Famous last words:
   "I wonder what happens if we do it this way?"

Hi Ryan, can you help to know how to understand code challenges?

···

Sent from my iPhone

On Mar 19, 2015, at 1:49 PM, Ryan Davis <ryand-ruby@zenspider.com> wrote:

On Mar 19, 2015, at 07:14, Darryl L. Pierce <mcpierce@gmail.com> wrote:

I'm developing some code that needs to intercept when an instance
variable is set for a class. It needs to be arbitrary; i.e., I don't
want to have to have code declare variables differently than they do now
and I don't want them to have to create mutator methods (since it needs
to intercept non-public values as well).

You can't, at least not without some serious C-level hacking. There are no hooks for such a thing (there are hooked variables that you can trace, but they're all globals).

This is a big reason why my code has as few "@"s as possible. Wrapping an accessor method is a lot simpler than hooking into the runtime itself.

muy bueno, gracias

···

El 19 de marzo de 2015, 16:19, jorge silva <jorgeg625@gmail.com> escribió:

buenos días espero te sirva.

Guia de Programacion en Ruby PDF | PDF

--
Equipo

EscenarioDeJuego <http://EscenarioDeJuego.blogspot.com.es/&gt;

···

2015-03-19 17:56 GMT+01:00 Alex Chaffee <alex@stinky.com>:

On Thu, Mar 19, 2015 at 10:14 AM, Darryl L. Pierce <mcpierce@gmail.com> > wrote:
> So, does anybody know how to intercept assigning values to instance
> variables?

This may be impossible (though I'm happy to be proven wrong). Ruby
stores instance data inside C structures that are accessed
more-or-less directly from many places in the Ruby interpreter. See
Ruby Internals | PPT (slide 16
especially) or Pat Shaughnessy if
you want the nasty details.

What are you trying to accomplish? Maybe some smart person on this
list can help you come up with a different strategy.

- A

--
Alex Chaffee - alex@stinky.com
http://alexchaffee.com
http://codelikethis.com
http://twitter.com/alexch

--
Equipo

EscenarioDeJuego <http://EscenarioDeJuego.blogspot.com.es/&gt;

Hrm, I hadn't quite thought of it like that; i.e., discouraging using @
instance variables in code that uses our library. I was hoping to make
the code work as unobtrusively as possible. But you make a great point
that, by encouraging this sort of pattern, it gives us more ability to
enhance the library over time.

···

On Thu, Mar 19, 2015 at 01:49:32PM -0700, Ryan Davis wrote:

> On Mar 19, 2015, at 07:14, Darryl L. Pierce <mcpierce@gmail.com> wrote:
>
> I'm developing some code that needs to intercept when an instance
> variable is set for a class. It needs to be arbitrary; i.e., I don't
> want to have to have code declare variables differently than they do now
> and I don't want them to have to create mutator methods (since it needs
> to intercept non-public values as well).

You can't, at least not without some serious C-level hacking. There are no hooks for such a thing (there are hooked variables that you can trace, but they're all globals).

This is a big reason why my code has as few "@"s as possible. Wrapping an accessor method is a lot simpler than hooking into the runtime itself.

--
Darryl L. Pierce <mcpierce@gmail.com>

Famous last words:
   "I wonder what happens if we do it this way?"

If you're just trying to get notified on method calls rather than, say,
manipulating the arguments and re-calling, would something like
Class: TracePoint (Ruby 2.1.1) work for you?

Ryan

···

On Thu, Mar 19, 2015 at 10:37 AM, Darryl L. Pierce <mcpierce@gmail.com> wrote:

On Thu, Mar 19, 2015 at 06:05:22PM +0100, Heliogábalo Santos wrote:
> Ruby Random Numbers and Strings - Black Bytes
>
> drop millions of allocations by using a linked list by tenderlove · Pull Request #1188 · rubygems/rubygems · GitHub

Sorry, how do either of these links relate to the question?

--
Darryl L. Pierce <mcpierce@gmail.com>
http://mcpierce.blogspot.com/
Famous last words:
   "I wonder what happens if we do it this way?"

I don't have a ton of direct experience with TracePoint or the Ruby source
- but might you be able to trace :c_call events and look for calls to
rb_iv_set (
https://github.com/ruby/ruby/blob/724012a23d8274543002eb42ef71d87308481d40/variable.c#L2645\),
which appears to be how Ruby implements setting instance variables?

···

On Thu, Mar 19, 2015 at 11:03 AM, Darryl L. Pierce <mcpierce@gmail.com> wrote:

On Thu, Mar 19, 2015 at 10:39:13AM -0700, Ryan Mitchell wrote:
> If you're just trying to get notified on method calls rather than, say,
> manipulating the arguments and re-calling, would something like
> http://ruby-doc.org/core-2.1.1/TracePoint.html work for you?

Not method calls, but assignments and updates to instance variables on
an object; i.e., like how, in Python, __getattr__ is invoked whenever an
object's attributes are changed.

--
Darryl L. Pierce <mcpierce@gmail.com>
http://mcpierce.blogspot.com/
Famous last words:
   "I wonder what happens if we do it this way?"

Sorry, how do either of these links relate to the question?

···

On Thu, Mar 19, 2015 at 06:05:22PM +0100, Heliogábalo Santos wrote:

Ruby Random Numbers and Strings - Black Bytes

https://github.com/rubygems/rubygems/pull/1188

--
Darryl L. Pierce <mcpierce@gmail.com>

Famous last words:
   "I wonder what happens if we do it this way?"

Not method calls, but assignments and updates to instance variables on
an object; i.e., like how, in Python, __getattr__ is invoked whenever an
object's attributes are changed.

···

On Thu, Mar 19, 2015 at 10:39:13AM -0700, Ryan Mitchell wrote:

If you're just trying to get notified on method calls rather than, say,
manipulating the arguments and re-calling, would something like
http://ruby-doc.org/core-2.1.1/TracePoint.html work for you?

--
Darryl L. Pierce <mcpierce@gmail.com>

Famous last words:
   "I wonder what happens if we do it this way?"

Interesting suggestion. However, at least initially, it's not doing
that. I think what's going on is too far below what TracePoint can
handle. I used the following code but don't see the assignment call
being displayed:

===[start]===
module Wrapper

  def self.included(base)
    puts "Wrapper.included"
    trace = TracePoint.new(:c_call) do |tp|
      puts "tp: event=#{tp.event} inspect=#{tp.inspect}"
    end
    trace.enable
  end

end

class TestClass
  include Wrapper

  attr_accessor :test1
  attr_accessor :test2

  def initialize
    puts "Initializing test1"
    @test1 = "1"
    puts "Initializing test2"
    @test2 = "2"
  end
end

test = TestClass.new
puts "Assigning test 1"
test.test1 = "5"
puts "Assigning test 2"
test.test2 = "Darryl"
===[end]===

···

On Thu, Mar 19, 2015 at 11:20:28AM -0700, Ryan Mitchell wrote:

I don't have a ton of direct experience with TracePoint or the Ruby source
- but might you be able to trace :c_call events and look for calls to
rb_iv_set (
https://github.com/ruby/ruby/blob/724012a23d8274543002eb42ef71d87308481d40/variable.c#L2645\),
which appears to be how Ruby implements setting instance variables?

--
Darryl L. Pierce <mcpierce@gmail.com>

Famous last words:
   "I wonder what happens if we do it this way?"

Not with such a vague question. And don't hijack threads.

···

On Mar 19, 2015, at 14:44, Kay <ddadekunle@gmail.com> wrote:

Hi Ryan, can you help to know how to understand code challenges?

just trying to help, dont panic. Sorry my ignorance Master.

···

2015-03-19 18:37 GMT+01:00 Darryl L. Pierce <mcpierce@gmail.com>:

On Thu, Mar 19, 2015 at 06:05:22PM +0100, Heliogábalo Santos wrote:
> Ruby Random Numbers and Strings - Black Bytes
>
> https://github.com/rubygems/rubygems/pull/1188

Sorry, how do either of these links relate to the question?

--
Darryl L. Pierce <mcpierce@gmail.com>
http://mcpierce.blogspot.com/
Famous last words:
   "I wonder what happens if we do it this way?"

--
Equipo

EscenarioDeJuego <http://EscenarioDeJuego.blogspot.com.es/&gt;

There are a lot of positive side-effects to using that pattern. First, you can instrument anything quite easily. Second, you can switch to lazy-initializing or caching w/o batting an eye. Refactorings and all sorts of things are enabled by it.

Direct cvar/ivar access is pretty much an antipattern in my book. I still use it here and there, but I try not to.

···

On Mar 20, 2015, at 07:06, Darryl L. Pierce <mcpierce@gmail.com> wrote:

Hrm, I hadn't quite thought of it like that; i.e., discouraging using @
instance variables in code that uses our library. I was hoping to make
the code work as unobtrusively as possible. But you make a great point
that, by encouraging this sort of pattern, it gives us more ability to
enhance the library over time.

Unsubscribe

···

Sent from my iPhone

On Mar 19, 2015, at 1:40 PM, Heliogábalo Santos <jonitjuego@gmail.com> wrote:

just trying to help, dont panic. Sorry my ignorance Master.

2015-03-19 18:37 GMT+01:00 Darryl L. Pierce <mcpierce@gmail.com>:

On Thu, Mar 19, 2015 at 06:05:22PM +0100, Heliogábalo Santos wrote:
> http://goo.gl/uhkwyu
>
> drop millions of allocations by using a linked list by tenderlove · Pull Request #1188 · rubygems/rubygems · GitHub

Sorry, how do either of these links relate to the question?

--
Darryl L. Pierce <mcpierce@gmail.com>
http://mcpierce.blogspot.com/
Famous last words:
   "I wonder what happens if we do it this way?"

--
Equipo
EscenarioDeJuego

And I'm asking you how it would apply to my situation.

···

On Thu, Mar 19, 2015 at 06:40:27PM +0100, Heliogábalo Santos wrote:

just trying to help, dont panic. Sorry my ignorance Master.

--
Darryl L. Pierce <mcpierce@gmail.com>

Famous last words:
   "I wonder what happens if we do it this way?"