[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

canonical Array#append to hang hook

Rassat Nicolas

9/30/2007 7:51:00 PM

I have a class which inherit from Array. I want to perform some task
each time something is append to an instance of this class. The problem
is: there are so many way to append something to an array. For example:

class Narray < Array
alias_method :old_push, :push
def push(*obj)
p "pushing #{obj}"
old_push(*obj)
end
alias_method :old_append, :<<
def <<(obj)
p "<<ing #{obj}"
old_append(obj)
end
alias_method :old_bracket, :[]=
def []=(i,l=0)
p "[]=ing #{i}"
old_bracket(i,l)
end
alias_method :old_add, :+
def +(i)
p "+ing #{i}"
old_add(i)
end
end

a = Narray.new
a.push(1)
a << 2
a[a.length] = 3
a = a + [4]
p a

I forgot Array#insert, Array#fill and probably other...

Is there any Array#append function that can hooked to perform task every
time something is append to a?

Any solution is welcome.

LarsTico

PS: sorry for my poor frenchy english, but I hope you understand me.
--
Posted via http://www.ruby-....

15 Answers

Robert Klemme

10/1/2007 2:02:00 PM

0

2007/9/30, Rassat Nicolas <nicolas.rassat@free.fr>:
> I have a class which inherit from Array. I want to perform some task
> each time something is append to an instance of this class. The problem
> is: there are so many way to append something to an array. For example:
>
> class Narray < Array
> alias_method :old_push, :push
> def push(*obj)
> p "pushing #{obj}"
> old_push(*obj)
> end
> alias_method :old_append, :<<
> def <<(obj)
> p "<<ing #{obj}"
> old_append(obj)
> end
> alias_method :old_bracket, :[]=
> def []=(i,l=0)
> p "[]=ing #{i}"
> old_bracket(i,l)
> end
> alias_method :old_add, :+
> def +(i)
> p "+ing #{i}"
> old_add(i)
> end
> end
>
> a = Narray.new
> a.push(1)
> a << 2
> a[a.length] = 3
> a = a + [4]
> p a
>
> I forgot Array#insert, Array#fill and probably other...
>
> Is there any Array#append function that can hooked to perform task every
> time something is append to a?
>
> Any solution is welcome.

I'd probably consider not using inheritance but wrapping your Array in
some other class. That way you can expose the interface you want to
expose and esp. limit the way to modify the array.

Kind regards

robert

Joel VanderWerf

10/1/2007 8:19:00 PM

0

Rassat Nicolas wrote:
> I have a class which inherit from Array. I want to perform some task
> each time something is append to an instance of this class. The problem
> is: there are so many way to append something to an array. For example:
>
> class Narray < Array
...
> alias_method :old_add, :+
> def +(i)
> p "+ing #{i}"
> old_add(i)
> end
> end

It's not clear to me (though maybe it is clear to you) whether + should
be considered as a kind of append operation. Note that + doesn't modify
the array, but returns a new array. Furthermore, + doesn't return an
instance of NArray, but just an Array:

irb(main):001:0> class A < Array
irb(main):002:1> def +(x); super; end
irb(main):003:1> end
=> nil
irb(main):004:0> a = A.new
=> []
irb(main):005:0> (a + []).class
=> Array

However:

irb(main):008:0> (a.concat []).class
=> A

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Logan Capaldo

10/1/2007 8:31:00 PM

0

On 9/30/07, Rassat Nicolas <nicolas.rassat@free.fr> wrote:
> I have a class which inherit from Array. I want to perform some task
> each time something is append to an instance of this class. The problem
> is: there are so many way to append something to an array. For example:
>

class Narray
def initialize(a)
@array = a.dup.freeze
end

def method_missing(name, *args, &block)
@array.send(name, *args, &block)
rescue NoMethodError
super
rescue TypeError => e
if e.message =~ /can't modify frozen array/
a = @array.dup
p "#{name}ing"
r = a.send(name, *args, &block)
@array = a.freeze
r
else
raise e
end
end

def inspect
@array.inspect
end

def to_s
@array.to_s
end
end

narray = Narray.new [1,2,3]
narray.append 4
p narray
narray << 3
p narray
narray.fill(2)
p narray

Totally didn't test this

Rassat Nicolas

10/2/2007 11:54:00 AM

0

Answer to the three responses:


To Robert Klemme:

Sure I can do this but this way I lose every benefit of inheritance! And
I'll have to rewrite "accesor" function to access function to the
instance variable array. That is not very DRY.


To Joel VanderWerf:

Your remark about Array#+ is completly right. I just put it here to test
if Array#push or Array#<< were implementing using the Array#+ function.


To Logan Capaldo:

I got this error:
narray.rb:9:in `method_missing': undefined method `append' for [1,
2,3]:Narray (NoMethodError)
from narray.rb:32

But this is not the point. This way I'll catch every func, not just func
that insert something on the array. I would have to do something like my
example. Again, this is not really DRY.


Does anyone knows how insertion is implementing in the ruby core code or
should I dig the code by myself? This time is about inserting into an
array, but it can be over action; would it not be great to have some
hook function to solve easily this kind of problem?

To all you three, thanks for your answer
--
Posted via http://www.ruby-....

Austin Ziegler

10/2/2007 12:07:00 PM

0

On 10/2/07, Lars Ticot <nicolas.rassat@free.fr> wrote:
> To Robert Klemme:
> Sure I can do this but this way I lose every benefit of inheritance! And
> I'll have to rewrite "accesor" function to access function to the
> instance variable array. That is not very DRY.

No you don't. #method_missing and #respond_to? are your friends. Or
you can use Delegator.

class NRArray
def initialize(*args, &block)
@nrarray = if args.empty? and block.nil?
[]
elsif args.empty?
Array.new &block
else
Array.new(*args, &block)
end
end

def respond_to?(sym)
ok = super
ok = @nrarray.respond_to?(sym) unless ok
ok
end

def method_missing(sym, *args, &block)
puts "#{sym}ing #{args.inspect}"
@nrarray.send(sym, *args, &block)
end
end

(Note that NArray is a well-known numerical array extension, so Narray
is likely to be confusing if you need it.)

-austin
--
Austin Ziegler * halostatue@gmail.com * http://www.halo...
* austin@halostatue.ca * http://www.halo...feed/
* austin@zieglers.ca

Rassat Nicolas

10/2/2007 12:22:00 PM

0

Austin Ziegler wrote:
> On 10/2/07, Lars Ticot <nicolas.rassat@free.fr> wrote:
>> To Robert Klemme:
>> Sure I can do this but this way I lose every benefit of inheritance! And
>> I'll have to rewrite "accesor" function to access function to the
>> instance variable array. That is not very DRY.
>
> No you don't. #method_missing and #respond_to? are your friends. Or
> you can use Delegator.

yes but:

a = NRArray.new
a.push(2) # => "pushing [2]"
a.pop # => "poping []"

I don't want to catch the poping!

The delegator is an answer, like having an Array instance var. I lose
the inheritance benefit.

It would have been great if, Array#push, Array#<< and Array#insert,
would used the same Array#internal_insert in their implementation. So
hooking this one would give me a hook on the other one. Basicaly they
are all three doing insertion!

> (Note that NArray is a well-known numerical array extension, so Narray
> is likely to be confusing if you need it.)

Right! It was just the first name that came to me (N(ew)Array) when I
start thinking at this problem ;-)

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

Robert Klemme

10/2/2007 2:21:00 PM

0

2007/10/2, Lars Ticot <nicolas.rassat@free.fr>:
> To Robert Klemme:
>
> Sure I can do this but this way I lose every benefit of inheritance! And
> I'll have to rewrite "accesor" function to access function to the
> instance variable array. That is not very DRY.

Actually the only real difference is object identity IMHO. As has been
demonstrated there are easy to use tools that make delegation of
method invocations to the real Array really simple.

If you provide more insight into your use case then maybe even more /
better / easier solutions will come up. I am convinced that it is a
bad idea to inherit Array most of the time similarly to it being a bad
idea to inherit java.util.HashMap.

Kind regards

robert

Logan Capaldo

10/2/2007 2:45:00 PM

0

On 10/2/07, Lars Ticot <nicolas.rassat@free.fr> wrote:
> To Logan Capaldo:
>
> I got this error:
> narray.rb:9:in `method_missing': undefined method `append' for [1,
> 2,3]:Narray (NoMethodError)
> from narray.rb:32
>

Heh I'm silly. There actually is no Array#append method so that's what
should have happend. Delete the narray.append line and then try it
out, I think you'll find it's a pleasantly evil hack.

Rassat Nicolas

10/2/2007 5:33:00 PM

0

Robert Klemme wrote:
> 2007/10/2, Lars Ticot <nicolas.rassat@free.fr>:
>> To Robert Klemme:
>>
>> Sure I can do this but this way I lose every benefit of inheritance! And
>> I'll have to rewrite "accesor" function to access function to the
>> instance variable array. That is not very DRY.
>
> Actually the only real difference is object identity IMHO.

Right for me

> As has been
> demonstrated there are easy to use tools that make delegation of
> method invocations to the real Array really simple.

Right too. But they induced over cost (during coding time and execution
time)

> If you provide more insight into your use case then maybe even more /
> better / easier solutions will come up.

It's a work at really pre alpha stage (actually I am just starting to
think about how to do things). It's a kind of spreadsheet that works by
column. That should approximately look like

class Cell
# represent the content of a cell
# define some useful functions: format, is_number?,....
end

class Column
# represent the column as an array of Cell.
end

> I am convinced that it is a
> bad idea to inherit Array most of the time similarly to it being a bad
> idea to inherit java.util.HashMap.

To continue on my example, I want to check if cells that I add on my
column are number (just an example). Two possibilities:
- if Column inherit from Array I'll have to do something like in my
first example.
- if Column does not inherit from Array it will have to delegate Array's
function that I need (almost all function in Array)and the delegation
has a cost (see example at the end). Moreover, what if I want to use a
lib that don't rely only on duck typing and use some crapy things like
this?
def do_something(obj)
if obj.class == Array then
...
else
...
end
So the identity of object *is* important in some (bad?) situation. As an
example, Gtk lib (and probably others) does such things (I'll post
something on this and multiple inheritance in some time).

My column *is* an array. So I think it's pretty clear that it should be
derived from Array.

Thanks

Here is a quick and dirty test I made to see cost of delegating.
Suprisingly, delegating and forwarding are really slow. As slow as using
the method_missing (without error test). I would expect them to be as
quick as the "indirect" (class C) method.


require 'delegate'
require 'forwardable'
require 'benchmark'
include Benchmark

class A
def hello
end
end

class B < A
end

class C
def initialize
@a = A.new
end
def hello
@a.hello
end
end

class D < DelegateClass(A)
def initialize
a = A.new
super(a)
end
end

class E
extend Forwardable
def_delegator(:@a, :hello, :hello)
def initialize
@a=A.new
end
end

class F
def initialize
@a=A.new
end
def method_missing(name, *args, &block)
@a.send(name, *args, &block)
end
end

a = A.new
b = B.new
c = C.new
d = D.new
e = E.new
f = F.new

m=100000 # My computer is an old k6-400 so you probably have to increase
this!

bm(10) do |x|
x.report("direct ") { m.times{a.hello } }
x.report("inherit ") { m.times{b.hello } }
x.report("indirect") { m.times{c.hello } }
x.report("delegate") { m.times{d.hello } }
x.report("forward ") { m.times{e.hello } }
x.report("missing ") { m.times{f.hello } }
end

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

M561

5/3/2011 7:34:00 AM

0

On 02 May 2011, T. Keating <tkusenet@ktcnslt.com> posted some
news:i6qur6lji58qshkhgufvh63i3ur5mtu2cm@4ax.com:

> On Mon, 02 May 2011 20:35:54 +0200, "Brad Thurman" <bthurman@msn.com>
> wrote:
>
>>Of course the liberal establishment will claim draft-dodger
>>Obama
>
> President Obama was 11 years old(not eligible) when the draft law
> expired in ~March 1973 (Nixon campaign promise) as the US
> transitioned to a volunteer military.

Wrong, 1975. Gerald R. Ford, Proclamation 4360.

> Now go away Mr. Scum bag..

It must be blissful to be an ignorant liberal and drift through life in a
haze of Drano extracted methamphetamine smoke.

"On July 2, 1980, Democrat President Jimmy Carter signed Proclamation
4771, Registration Under the Military Selective Service Act, retroactively
re-establishing the Selective Service registration requirement for all
18?26 year old male citizens born on or after January 1, 1960. Only men
born between March 29, 1957, and December 31, 1959, were completely exempt
from Selective Service registration"

This was a big deal. Liberals all over the country wanted Carter hung by
his testicles from the Empire State Building for making the registration
retroactive. It was all over the schools, papers, radio and TV for
months. SSR cards were available in high schools. There were even paid
commercials from the government about it. There would be absolutely no
possible excuse for not knowing about it if you were an American. None.

As Obama claims to have been born on August 4, 1961, he would have been 19
years old and he was required by law to register. You be the judge. Did
he register as the law requires? Or, in 2008, did he knowingly and in
violation of federal law, falsely sign a crudely backdated document using
a form that did not exist at the supposed date of registration?

http://www.debbieschlussel.com/archives/obamaselectiveservice...

http://www.debbieschlussel.com/archives/Obamaselectiveservice...

http://www.debbieschlussel.com/4428/exclusive-did-next-commander...
falsify-selective-service-registration-never-actually-register-obamas-
draft-registration-raises-serious-questions/

Look up your registration status here:

If you had Obama's SSAN, you could look up his status. What? He has over
30 SSAN's verifiably associated with his name? Isn't that a violation of
federal law?

https://www.sss.gov/RegVer/wfVerific...

This service allows you to look up a man's Selective Service number, as
well as the date he registered. Enter a last name, social security number,
and date of birth for the registered man, and click on "Submit."

Only registrations of men born on or after January 1, 1960, can be
verified through this system. To obtain Selective Service information
about men born earlier, CLICK HERE and follow the instructions on our
"Records" page.

This service is operational seven days a week. It is not available when
system maintenance is scheduled from 2 a.m. to 4 a.m., U.S. Central Time,
Tuesday through Saturday.

Men who have registered remain eligible for federal student aid, most
federal jobs, and federal job training. Male non-citizens living in the
U.S. who are 18 through 25 must register to remain eligible for
citizenship.

Read the following very carefully and you'll understand why Obama is an
intentional draft dodger, forger, liar, and swears false oaths. Why this
man has not served time in jail for perjury escapes me.

Selective Service System: Fast Facts

http://www.sss.go...

WHEN TO REGISTER

The law requires virtually all male U.S. citizens (regardless of where
they live), and male immigrants residing in the U.S. (permanent resident
aliens), to register within 30 days of their 18th birthday. Therefore,
to be in full compliance with the law, a man turning 18 is required to
register during the period of time beginning 30 days before, until 30 days
after his 18th birthday...a 60-day window.

Late registrations are accepted, but not once a man reaches age 26. Men
who do not register within the 60-day window are technically in violation
of the law and should register as soon as possible.

A male non-citizen who first takes up permanent residence in the U.S. when
he is at least 18 years old, but not yet 26 years old, must register
within 30 days of becoming a resident. If he first enters the U.S. as a
resident when he is 26 years old or older, he does not register with
Selective Service because he is too old to register. Male non-citizens in
the U.S. temporarily (valid student or visitor visa, diplomatic corps,
etc.) do not register.


http://www.sss.gov/FSbe...

BENEFITS AND PROGRAMS LINKED TO REGISTRATION Printer Friendly Version

Registration is the law. A man who fails to register may, if prosecuted
and convicted, face a fine of up to $250,000 and/or a prison term of up to
five years.

Even if not tried, a man who fails to register with Selective Service
before turning age 26 may find that some doors are permanently closed.

See also Men over the age of eligibility to register.
See also What Does Selective Service Provide for America.

Register Now! - Register online.

STUDENT FINANCIAL AID
Men, born after December 31, 1959, who aren't registered with Selective
Service won't qualify for Federal student loans or grant programs. This
includes Federal Pell Grants, Federal Supplemental Educational Opportunity
Grants (FSEOG), Direct Stafford Loans/Plus Loans, National Direct Student
Loans, and College Work Study.

CITIZENSHIP
The U.S. Citizenship and Immigration Services (USCIS) makes registration
with Selective Service a condition for U.S. citizenship if the man first
arrived in the U.S. before his 26th birthday.

FEDERAL JOB TRAINING
The Workforce Investment Act (WIA) offers programs that can train young
men seeking vocational employment or enhancing their career. This program
is only open to those men who register with Selective Service. Only men
born after December 31, 1959, are required to show proof of registration.

FEDERAL JOBS
A man must be registered to be eligible for jobs in the Executive Branch
of the Federal government and the U.S. Postal Service. Proof of
registration is required only for men born after December 31, 1959.

Some states have added additional penalties for those who fail to
register. See State Legislation.

Selective Service wants young men to register. It does not want them to be
prosecuted or denied benefits. If a draft is ever needed, it must be as
fair as possible, and that fairness depends on having as many eligible men
as possible registered. In the event of a draft, for every man who fails
to register, another man would be required to take his place in service to
his country.


Semper Fi!