(Static) Constructors/Destructors in Ruby

M

Mauricio Fernandez

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.

The finalizers will be run on exit

ObjectSpace.define_finalizer(a = "", lambda{ puts "EXECUTED" })
END{ puts "leaving" }
puts "hi"
RUBY_VERSION # => "1.8.4"
# >> hi
# >> leaving
# >> EXECUTED

But you can bypass them with Kernel#exit!

batsman@tux-chan:~/mess/current$ cat exit_bang.rb
ObjectSpace.define_finalizer(a = "", lambda{ puts "EXECUTED" })
END{ puts "leaving" }
puts "hi"
puts RUBY_VERSION
exit!
batsman@tux-chan:~/mess/current$ ruby exit_bang.rb
hi
1.8.4
 
C

Collins, Justin

------_=_NextPart_001_01C65690.49FAC7D9
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

To clarify, I was talking about Java.

-Justin

-----Original Message-----
From: Mauricio Julio Fern=E1ndez Pradier on behalf of Mauricio Fernandez
Sent: Sun 4/2/2006 4:31 AM
To: ruby-talk ML
Subject: Re: (Static) Constructors/Destructors in Ruby
=20
I believe this is the case if the garbage collector never runs. That = is,=20
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.

The finalizers will be run on exit

ObjectSpace.define_finalizer(a =3D "", lambda{ puts "EXECUTED" })
END{ puts "leaving" }
puts "hi"
RUBY_VERSION # =3D> "1.8.4"
# >> hi
# >> leaving
# >> EXECUTED

But you can bypass them with Kernel#exit!

batsman@tux-chan:~/mess/current$ cat exit_bang.rb=20
ObjectSpace.define_finalizer(a =3D "", lambda{ puts "EXECUTED" })
END{ puts "leaving" }
puts "hi"
puts RUBY_VERSION
exit!
batsman@tux-chan:~/mess/current$ ruby exit_bang.rb=20
hi
1.8.4

--=20
Mauricio Fernandez - http://eigenclass.org - singular Ruby



------_=_NextPart_001_01C65690.49FAC7D9--
 
P

Primary Key

Jim said:
I'm still unclear on how static methods do anything to support
meta-progarmming. Perhaps an example might prove illuminating.

I am not sure this will be compelling enough, but here we go:

require 'dbi'

class Connection
@@driver = 'DBI:ADO:provider=SQLOLEDB;Data Source=...;Initial
Catalog=...;User Id=...;Password=...;trusted_connection=yes'

def initialize
@dbh = DBI.connect(@@driver)
@is_closed=false
end

def close
@dbh.disconnect
@is_closed=true
end

def closed?
@is_closed
end

# MSSQL Server specific
def columns(table_name)
table_name = table_name.to_s if table_name.is_a?(Symbol)
table_name = table_name.split('.')[-1] unless table_name.nil?
sql = "SELECT COLUMN_NAME as ColName, COLUMN_DEFAULT as DefaultValue,
DATA_TYPE as ColType, " +
"COL_LENGTH('#{table_name}', COLUMN_NAME) as Length,
COLUMNPROPERTY(OBJECT_ID('#{table_name}'), " +
"COLUMN_NAME, 'IsIdentity') as IsIdentity, NUMERIC_SCALE as Scale "
+
"FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '#{table_name}'"
columns = []
result = @dbh.select_all(sql)
result.each { |field| columns << field }
columns
end
end

class MyClass
# Static "constructor"
def self.create(table)
@@table = table
@@connection = Connection.new

columns = @@connection.columns(table)
columns.each { |column|
property = 'fld'+column[0]
self.class_eval(%Q[
def #{property}
@#{property}
end
def #{property}=(value)
@#{property} = value
end
])
}
end

# Static "destructor"
def self.destroy()
@@connection.close unless @@connection.closed?
end
end

MyClass.create('USERS')

table1 = MyClass.new
table2 = MyClass.new

table1.methods.each {|m| puts m if m =~ /^fld/ }

MyClass.destroy
 
R

Robert Klemme

Primary said:
Jim said:
I'm still unclear on how static methods do anything to support
meta-progarmming. Perhaps an example might prove illuminating.

I am not sure this will be compelling enough, but here we go:

require 'dbi'

class Connection
@@driver = 'DBI:ADO:provider=SQLOLEDB;Data Source=...;Initial
Catalog=...;User Id=...;Password=...;trusted_connection=yes'

def initialize
@dbh = DBI.connect(@@driver)
@is_closed=false
end

def close
@dbh.disconnect
@is_closed=true
end

def closed?
@is_closed
end

# MSSQL Server specific
def columns(table_name)
table_name = table_name.to_s if table_name.is_a?(Symbol)
table_name = table_name.split('.')[-1] unless table_name.nil?
sql = "SELECT COLUMN_NAME as ColName, COLUMN_DEFAULT as DefaultValue,
DATA_TYPE as ColType, " +
"COL_LENGTH('#{table_name}', COLUMN_NAME) as Length,
COLUMNPROPERTY(OBJECT_ID('#{table_name}'), " +
"COLUMN_NAME, 'IsIdentity') as IsIdentity, NUMERIC_SCALE as Scale "
+
"FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '#{table_name}'"
columns = []
result = @dbh.select_all(sql)
result.each { |field| columns << field }
columns
end
end

class MyClass
# Static "constructor"
def self.create(table)
@@table = table
@@connection = Connection.new

columns = @@connection.columns(table)
columns.each { |column|
property = 'fld'+column[0]
self.class_eval(%Q[
def #{property}
@#{property}
end
def #{property}=(value)
@#{property} = value
end
])
}
end

# Static "destructor"
def self.destroy()
@@connection.close unless @@connection.closed?
end
end

MyClass.create('USERS')

table1 = MyClass.new
table2 = MyClass.new

table1.methods.each {|m| puts m if m =~ /^fld/ }

MyClass.destroy

IMHO this is a bad example. Doing things behind the scenes makes code
complex and unreadable. I'd expect a method named "create" to actually
return something - typically something newly created. Instead you store
state in a class variable which isn't thread safe - and not needed as
far as I can see. Especially with database connections it's usually a
bad idea to use them implicit because explicitly marking transaction
boundaries is important.

With "ensure" and the typical block idioms (like with File#open) I don't
see how destructors would actually improve the language. Especially if
you think about file descriptors it's far better to clearly mark their
life cycle (by using File.open("foo") do |io| ... end) instead of having
them closes at *some* point in time (i.e. when GC decides to get rid of
the object) because that can cause all sorts of problems (from shortage
of available file descriptors to opening a file again that hasn't yet
been closed).

Kind regards

robert
 

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,774
Messages
2,569,599
Members
45,170
Latest member
Andrew1609
Top