(Static) Constructors/Destructors in Ruby


#1

Hello!

After reading the Pickaxe book I noticed it provides almost no
information about object lifecycle and no mention of destructors. As a
Java/C# guy my gut reaction was: Wouldnâ??t it be nice to have a
â??unintializeâ? method to be called when the object is being destroyed?

There seems to be some form of destructor (called finalizers) in the
ObjectSpace module, but it seems to be an afterthought rather that an
integral feature of the language.

Another thing I find very surprising for a language having such a rich
OO model is the lack of static constructors (available in C# and somehow
in Java) and static destructors (something I always wanted to have in
Java/C#).

Based on that I will appreciate your thoughts on why a language having
such advanced OO features is lacking in these areas and is there any way
to emulate these.

Thanks


#2

PrimaryKey wrote:

Hello!

After reading the Pickaxe book I noticed it provides almost no
information about object lifecycle and no mention of destructors. As a
Java/C# guy my gut reaction was: Wouldnâ??t it be nice to have a
â??unintializeâ? method to be called when the object is being destroyed?

Java does not have destructors either. finalize method is not guaranteed
to be called

Another thing I find very surprising for a language having such a rich
OO model is the lack of static constructors (available in C# and somehow
in Java) and static destructors (something I always wanted to have in
Java/C#).

Ruby has them. Every class definition is an executable code (public,
private, protected are methods) so you can alternate method definitions
with arbitrary code (in fact, this is much more powerful mechanism than
static blocks in Java and static constructors in C#)

lopex


#3

Does anyone know under what conditions the finalizer won’t be called?

On 3/31/06, Marcin Miel¿yñski removed_email_address@domain.invalid wrote:

to be called
static blocks in Java and static constructors in C#)

lopex


-Dan Nugent

Don’t Feel Like Typing? Send me a voicemail:
http://odeo.com/sendmeamessage/DanNugent


#4

PrimaryKey wrote:

There seems to be some form of destructor (called finalizers) in the
ObjectSpace module, but it seems to be an afterthought rather that an
integral feature of the language.

Actually, it is a very well thought out feature of the language. In
Java, the finalizer is run when the object is eligible for garbage
collection. But within the finalizer, you can create a new reference to
the object and make it ineligible for collection.

In Ruby, the finalizer is not run until after the object is collected.
Since the object itself is no longer around, there is no possibility of
even accidently creating a new reference to the object. It also means
that the finalizer can’t be an instance method (because the instance is
gone when the finalizer is run).

Another thing I find very surprising for a language having such a rich
OO model is the lack of static constructors (available in C# and somehow
in Java) and static destructors (something I always wanted to have in
Java/C#).

How would you use static constructors/destructors? Perhaps we can show
you Ruby equivalents.


– Jim W.


#5

PrimaryKey wrote:

Hello!

After reading the Pickaxe book I noticed it provides almost no
information about object lifecycle and no mention of destructors. As a
Java/C# guy my gut reaction was: Wouldn’t it be nice to have a
“unintialize” method to be called when the object is being destroyed?

There seems to be some form of destructor (called finalizers) in the
ObjectSpace module, but it seems to be an afterthought rather that an
integral feature of the language.

Not so much an afterthought as discouraged.

Here’s a good discussion about Ruby’s finalizers:
http://www.rubygarden.org/ruby?RubyFromCpp


#6

On Mar 31, 2006, at 2:58 PM, PrimaryKey wrote:

{
}

  1. I like the constructor/destructor symmetry in C++
  2. It can be helpful for meta-programming purposes. My impression is
    most languages try to implement the traditional OO tools on class
    (static) level

Thanks


Posted via http://www.ruby-forum.com/.

class AS400Server
@server = AS400Connection.new
def self.get_server
@server
end
end

As for a static deconstructor, can’t really help you, I don’t think
classes are really ever GCed until the very end, anyway. however, you
could do this:

class AS400Server
at_exit { @server.disconnect }
end


#7

How would you use static constructors/destructors? Perhaps we can show
you Ruby equivalents.


– Jim W.

Please consider the following (pseudo) C# example:

public class AS400Server
{
	static AS400 server;

	static AS400Server()
	{
		server = new AS400Connection("SERVERNAME");
	}

	static ~AS400Server()   // This is not real C#
	{
		server.disconnect();
	}

	static int GetServer()
	{
		return server;
	}
}

I know this probably can be emulated using a singleton, I still believe
having static destructors will be nice because:

  1. I like the constructor/destructor symmetry in C++
  2. It can be helpful for meta-programming purposes. My impression is
    most languages try to implement the traditional OO tools on class
    (static) level

Thanks


#8

I believe this is the case if the garbage collector never runs. That is,
if the program exits before it is necessary.
Also, there are situations in which objects are never released, so the
finalize method won’t be called then, either. If I recall correctly.

-Justin


#9

PrimaryKey wrote:

  static AS400 server;

  static int GetServer()
  {
  	return server;
  }

}

I would ask first: does having one class per connection (“SERVERAME”)
scale well? what if you need two servers…? This question isn’t really
off topic, because once you accept this possibility, it becomes very
natural in ruby to do this:

class AS400Server
def initialize(serv_name)
@serv_name = serv_name
end

def connect
# do something to connect to the server
yield self
ensure
# do something to disconnet
end
end

Then in your main code you might have:

def run_my_app
AS400Server.new(“SERVERNAME”).connect do |serv|
# do something with serv
end
end

or

THE_SERVER = AS400Server.new(“SERVERNAME”)
def run_my_app
THE_SERVER.connect do
# do something with THE_SERVER
end
end

Unless you exit with Kernel#exit! or the process is killed in a way that
ruby cannot catch (e.g., SIGKILL), the ensure clause will close the
server connection first. (Anyway, in the case of SIGKILL, a static
destructor would not be called either, right? Or can C# do that?)

(You can even roll the #connect method into initialize, if you want.
Passing the server object from yeild isn’t really necessary, but you may
need to reference it in the block.)


#10

Jim W. wrote:

In Ruby, the finalizer is not run until after the object is collected.
Since the object itself is no longer around, there is no possibility of
even accidently creating a new reference to the object. It also means
that the finalizer can’t be an instance method (because the instance is
gone when the finalizer is run).

This makes perfect sense since Ruby uses mark&sweep. But in Python is it
possible to supply del method which seems to be an instance one
(correct me if I’m wrong), but the moment of GC cannot be determined
anyways. And as rmagick mentioned, explicit destrutors are not needed
anyways.

lopex


#11

PrimaryKey wrote:

Please consider the following (pseudo) C# example:

I think Logan C.'s answer is hits pretty close to your intention
here. However, I have to comment because I’ve been retrofitting unit
tests in to a legacy (Java) code base this past week and I’ve come to
hate static initializers.

The code base does something similar to your example and the code is
impossible to unit test without some restructuring. Since the database
connection is made in static initializers, I can’t even load the class
without having the infrastructure for a database connection available.
Yuck!

I’ve come to consider complex static initializers (e.g. making DB
connections in the initilizer) a thing of “evil”.

Ok, rant over. :wink:

[…]
2. It can be helpful for meta-programming purposes. My impression is
most languages try to implement the traditional OO tools on class
(static) level

I’m not getting statement #2 above.

Thanks.


– Jim W.


#12

Hi.

PrimaryKey wrote:

Based on that I will appreciate your thoughts on why a language having
such advanced OO features is lacking in these areas and is there any way
to emulate these.

Actually, destructor in Java, i.e., finalize( ), does not well behave.
Moreover, using it properly is next to impossible. Have a look at:
http://developers.sun.com/learning/javaoneonline/2005/coreplatform/TS-3281.html

Here’s the recap:
(1) Java finalizer is not guranteed to run.
(2) Java finalizer is not executed in the main thread. Instead, it runs
in its own thread. Hence, synchronization mechanism for read/write
visibility and concurrency control is required.
(3) If java finalizer access a certain object which is already garbage
collected, then the object will resurrect. To avoid this situation, you
should not access garbage collected object while finalizing, but it is
not easy because there’s no certain order in garbage collection.

Instead of relying on finalize, you’d better use dispose pattern like:

class Foo
def dispose
# release all non-managed resources
end
end

You can find similar interface, IDisposable, in C#. The reason is that
people developed C# already found that writing destructor for releasing
unmanaged resources is not simple than writing explicit dispose method.

Sincerely,
Minkoo S.


#13

On 31 Mar 2006, at 20:58, PrimaryKey wrote:

I know this probably can be emulated using a singleton,

The singleton design pattern certainly can do that, and is easily
used in Ruby by including module “Singleton” (except for the
destruction part - although I expect a finaliser could do that for
you, but I’ve not used them myself).

When you started to talk about these, I thought you were after
'structors for a class, rather than an instance. These are, of
course, very easy in Ruby, as a class is just an object like any
other. In fact, you can have little factories that will pump out
classes, if you want.

I still believe
having static destructors will be nice because:

  1. I like the constructor/destructor symmetry in C++

Actually, I like the c++ destructors too. I’d say they are one of the
very few things that I miss about it :slight_smile: I quite often made use of a
“stack object”. It’s an object with no interface except for it’s
'structors. You would declare them “on the stack” in c++ (ie, without
using new), so they are local to a code block. They’re really useful
for doing setup within a code block and ensuring that teardown
happens when you exit it. They seem like a DRY way to specify the use
of a mode within a code block:

class StackObject
{
public:
StackObject() {do_setup_code();}
~StackObject() {do_teardown_code();}

private:
void do_setup_code();
void do_teardown_code();
};

And to use…

{
// Setup resource.
StackObject stack_object;

// Do stuff with the mode being setup by the stack object.

// Tear down happens automatically at block exit.

}

However, a very similar idea is possible in Ruby, and can be achieved
with passing code blocks…

def run_within_mode
setup_code
yield
ensure
teardown_code
end

And to use:

Here, the mode is not in use yet.

run_within_mode do
# Anything here is happening with the mode! Hooray!
end

And the mode’s gone again.

As well as ensuring the resource is cleaned up, both of these
approaches are exception safe too.

Cheers,
Ben


#14

def run_within_mode
run_within_mode do

Anything here is happening with the mode! Hooray!

end

And the mode’s gone again.

As well as ensuring the resource is cleaned up, both of these
approaches are exception safe too.

I like block idea, but must say that blocks can’t give full replacement
for
C++'s RAII ideom:

C++:

{
File f1,f2,f3;
Socket s1,s2;
Database d;
} //here all f1,f2,f3,s1,s2,d being closed

Ruby:

???

Cheers,
Ben

Victor.


#15

On 1 Apr 2006, at 11:10, Victor S. wrote:

} //here all f1,f2,f3,s1,s2,d being closed

Ruby:

???

:slight_smile: It’s such a fresh beautiful day outside… and here I am talking
tech, when spring is springing :slight_smile:

Ok, in Ruby, each of those resources could easily be turned in to a
method that will run a block. What you want to be able to do then, is
easily compose those methods in to one, and have that run something
within the context of resources being available?

Something along the lines of (unchecked code warning!)…?

def run_with_resources(*resources, &block)
if resources == []
yield
else
send(resources.slice(0)) {run_with_resources(*resources, &block)}
end
end

You can then do…

run_with_resources
(:file_handle, :db_connection, :socket_and_things, :other_groovy_bits) d
o
#Wooo - look at all these resources!
end

It wouldn’t be a big extension to collect up the resources passed in,
and pop them in a map, or something. I don’t think it would be hard
to give the resources arguments either.

Cheers,
Ben


#16

On 1 Apr 2006, at 11:25, Benjohn B. wrote:

:slight_smile: It’s such a fresh beautiful day outside… and here I am talking
tech, when spring is springing :slight_smile:

It really is!

else
send(resources.slice(0)) {run_with_resources(*resources, &block)}

That was supposed to be:
send(resources.slice!(0)) {run_with_resources(*resources, &block)}

The ! after slice is vital!


#17

C++'s RAII ideom:

???

:slight_smile: It’s such a fresh beautiful day outside… and here I am talking
tech, when spring is springing :slight_smile:

Hmmm… Not so beautiful/springy day in Kharkov, Ukraine :slight_smile:

else
#Wooo - look at all these resources!
end

It wouldn’t be a big extension to collect up the resources passed in,
and pop them in a map, or something. I don’t think it would be hard
to give the resources arguments either.

Yes, I know all those trick (I’m not a VERY newbie :slight_smile: - my point was
“blocks
not always good alternative for RAII”.

BTW, I recalled I saw some library at RAA, which does the stuff. But I
don’t
remember it’s name (because in real life it is not as necessary as in
dumb
examples :wink:

Cheers,
Ben

Victor.


#18

On 1 Apr 2006, at 11:36, Victor S. wrote:

Yes, I know all those trick (I’m not a VERY newbie :slight_smile: - my point
was “blocks
not always good alternative for RAII”.

:slight_smile: I thought it was quite clever, I was feeling very pleased with
myself :slight_smile:

BTW, I recalled I saw some library at RAA, which does the stuff.
But I don’t
remember it’s name (because in real life it is not as necessary as
in dumb
examples :wink:

Well, that’s the thing though, really :slight_smile:


#19

Victor S. wrote:

Hmmm… Not so beautiful/springy day in Kharkov, Ukraine :slight_smile:

Nor in Northern California. It’s so wet the sidewalks are turning green.

Ok, in Ruby, each of those resources could easily be turned in to a
method that will run a block. What you want to be able to do then, is
easily compose those methods in to one, and have that run something
within the context of resources being available?

Here’s an idea:

require ‘socket’

class ResourceMgr
def
@resources = resources
end

def cleanup
@resources.reverse_each do |resource, cleanup_method|
resource.send cleanup_method || :close
end
end
end

def with_resources
res = ResourceMgr.new
yield res
ensure
res.cleanup
end

rl_test = nil

with_resources do |res|
res[
f = File.open("/tmp/file", “w”),
s = UDPSocket.open,
[t = Thread.new {sleep}, :kill]
]

rl_test = [f,s,t]
p rl_test

use resources here

end

p rl_test

END

Output:

[#<File:/tmp/file>, #UDPSocket:0xb7dca598, [#<Thread:0xb7dca4e4
sleep>, :kill]]
[#<File:/tmp/file (closed)>, #UDPSocket:0xb7dca598,
[#<Thread:0xb7dca4e4 dead>, :kill]]


#20

Jim W. wrote:

  1. It can be helpful for meta-programming purposes. My impression is
    most languages try to implement the traditional OO tools on class
    (static) level

I’m not getting statement #2 above.

Please consider the evolution of the class-level language features:

  1. C++ - static member variables
  2. Java - static members and static initialization blocks
  3. C# - static members and static constructors

I think there is a clear pattern of implementing more and more of the
object-level OO features on class (static) level. I believe the next
logical step will be a language support for static destructors. As far
as meta-progamming is concerned the static features will beef up the
class level in the object-class-metaclass triad. Again, this is just the
personal opinion of a “evil” legacy(Java) programmer :slight_smile:

Thanks again,
Primary Key