Calling define_finalizer from within C?

Hi,

I've got the following bit of C code;
   static VALUE do_destroy(...) { ...; return Qnil; }

   cObjectSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
   rb_include_module(cFoo, cObjectSpace);
   
   /* ... somewhere inside constructor... */
   p = rb_proc_new(do_destroy, obj);
   fprintf(stderr, "created new proc; class %s\n", rb_obj_classname(p));
   rb_funcall(obj, rb_intern("define_finalizer"), 1, p);

Basically, I need to define a finalizer from within a constructor, but I'm
running into the following problems:

1) define_finalizer throws an exception:
ArgumentError: tried to create Proc object without a block
I'm not sure what would cause that. The proc object should have a block..

2) At least in irb, calling define_finalizer within a class, and passing
it self as the first arg, causes nothing to happen. Is define_finalizer
the proper way to do this sort of thing, or is there a better way? Note
that I don't want to use Data_Make_Struct's free callback, as I need this
to be overridable by users of the class.

Hi,

At Mon, 18 Oct 2004 15:54:24 +0900,
Andres Salomon wrote in [ruby-talk:116931]:

Hi,

I've got the following bit of C code;
   static VALUE do_destroy(...) { ...; return Qnil; }

   cObjectSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
   rb_include_module(cFoo, cObjectSpace);
   
   /* ... somewhere inside constructor... */
   p = rb_proc_new(do_destroy, obj);
   fprintf(stderr, "created new proc; class %s\n", rb_obj_classname(p));
   rb_funcall(obj, rb_intern("define_finalizer"), 1, p);

Basically, I need to define a finalizer from within a constructor, but I'm
running into the following problems:

1) define_finalizer throws an exception:
ArgumentError: tried to create Proc object without a block
I'm not sure what would cause that. The proc object should have a block..

Use rb_iterate().

  static VALUE mObjectSpace;

  static void
  define_final(VALUE obj)
  {
      rb_funcall(mObjectSpace, rb_intern("define_finalizer"), 1, p);
  }

  static VALUE
  do_initialize(VALUE obj)
  {
      rb_iterate(define_final, obj, do_destroy, Qnil);
      return Qnil;
  }

  void
  Init_foo()
  {
      mObjectSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
  }

2) At least in irb, calling define_finalizer within a class, and passing
it self as the first arg, causes nothing to happen. Is define_finalizer
the proper way to do this sort of thing, or is there a better way? Note
that I don't want to use Data_Make_Struct's free callback, as I need this
to be overridable by users of the class.

Do you mean like this?

  ObjectSpace.define_finalizer(self) do |id|
    # ...
  end

If so, the object is referred as self from the finalizer so
that it never get freed.

Since not sure what you want really, I cannot tell what is
"better". At least, finalizers are different from destructors.

···

--
Nobu Nakada

[...]

2) At least in irb, calling define_finalizer within a class, and passing
it self as the first arg, causes nothing to happen. Is define_finalizer
the proper way to do this sort of thing, or is there a better way? Note
that I don't want to use Data_Make_Struct's free callback, as I need this
to be overridable by users of the class.

Do you mean like this?

  ObjectSpace.define_finalizer(self) do |id|
    # ...
  end

I mean like this:
    class Foo
        include ObjectSpace
        def initialize
            define_finalizer(self, proc { |a| puts 'inside Foo' })
        end
    end

It seems like it needs to be outside of the class, for some reason. The
following works:
    x = Foo.new
    include ObjectSpace
    define_finalizer(x, proc { |a| puts 'outside Foo' })

I'm trying to understand why the finalizer defined in the constructor
never gets called.

If so, the object is referred as self from the finalizer

so that it

never get freed.

In both my examples above, the object is referred to by the finalizer; I
don't see what the difference is, from the GC's perspective (assuming it
is the GC that's keeping the finalizer from being called).

Since not sure what you want really, I cannot tell what is
"better". At least, finalizers are different from destructors.

Different how? Conceptually (according to the pickaxe 1st ed), they
appear to be similar; a method called when the object is destroyed. The
only difference I can see are scope issues, as apparently
finalizers may not be defined within a class.

···

On Mon, 18 Oct 2004 18:11:59 +0900, nobu.nokada wrote:

It seems like it needs to be outside of the class, for some reason. The
following works:

write it like this

    x = Foo.new
    include ObjectSpace
    define_finalizer(x, proc { |a| puts 'outside Foo' })

       define_finalizer(x, proc { |a| puts "outside Foo #{x}" })

Guy Decoux

Nevermind; I just happened upon
<Captcha, which explained
everything wonderfully. Thanks for your help.

···

On Mon, 18 Oct 2004 10:59:28 -0400, Andres Salomon wrote:

Since not sure what you want really, I cannot tell what is
"better". At least, finalizers are different from destructors.

Different how? Conceptually (according to the pickaxe 1st ed), they
appear to be similar; a method called when the object is destroyed. The
only difference I can see are scope issues, as apparently
finalizers may not be defined within a class.