PHWinfo banniere

Titres
PORTAIL ANNUAIRE ARTICLES COMPARATEUR HÉBERGEURS DEVIS FORUMS RÉDUCTEUR D'URL
Précédent   PHWinfo > Autres forums > Forum Programmation & Conception > comp.lang.ruby > Parametric module or injecting code via class method?
S'inscrire FAQ Membres Recherche Messages du jour Marquer les forums comme lus
Parametric module or injecting code via class method?

Réponse
 
LinkBack Outils de la discussion
Vieux 13/03/2008, 02h14   #1
Trans
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Parametric module or injecting code via class method?

Which approach is better: parametric module or an injecting class
method.

# Generates identity/key methods based on specified attributes.
#
# include EquateOn(:a, :b)
#
# is equivalent to including a module containing:
#
# def ==(other)
# self.a == other.a && self.b == other.b
# end
#
# def eql?(other)
# self.a.eql?(other.a) && self.b.eql?(other.b)
# end
#
# def hash()
# self.a.hash ^ self.b.hash
# end
#

def EquateOn(*fields)
code = ""
code << "def ==(o) " << fields.map {|f| "self.#{f} ==
o.#{f}" }.join(" && ") << " end\n"
code << "def eql?(o) " << fields.map {|f| "self.#{f}.eql?
(o.#{f})" }.join(" && ") << " end\n"
code << "def hash() " << fields.map {|f|
"self.#{f}.hash" }.join(" ^ ") << " end\n"
mod = Module.new
mod.module_eval( code )
mod
end

- Or -

# Generates identity/key methods based on specified attributes.
#
# equate_on :a, :b
#
# _is equivalent to_
#
# def ==(o)
# self.a == o.a && self.b == o.b
# end
#
# def eql?(o)
# self.a.eql?(o.a) && self.b.eql?(o.b)
# end
#
# def hash()
# self.a.hash ^ self.b.hash
# end

def equate_on(*fields)
code = ""
code << "def ==(o) " << fields.map {|f| "self.#{f} ==
o.#{f}" }.join(" && ") << " end\n"
code << "def eql?(o) " << fields.map {|f| "self.#{f}.eql?
(o.#{f})" }.join(" && ") << " end\n"
code << "def hash() " << fields.map {|f|
"self.#{f}.hash" }.join(" ^ ") << " end\n"
class_eval( code )
fields
end

T.

  Réponse avec citation
Vieux 13/03/2008, 09h42   #2
Robert Klemme
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Parametric module or injecting code via class method?

2008/3/13, Trans <transfire@gmail.com>:
> Which approach is better: parametric module or an injecting class
> method.


Are you writing a book on best practices? There seem to be quite a
few of these questions recently. :-))

> # Generates identity/key methods based on specified attributes.
> #
> # include EquateOn(:a, :b)
> #
> # is equivalent to including a module containing:
> #
> # def ==(other)
> # self.a == other.a && self.b == other.b
> # end
> #
> # def eql?(other)
> # self.a.eql?(other.a) && self.b.eql?(other.b)
> # end
> #
> # def hash()
> # self.a.hash ^ self.b.hash
> # end
> #
>
> def EquateOn(*fields)
> code = ""
> code << "def ==(o) " << fields.map {|f| "self.#{f} ==
> o.#{f}" }.join(" && ") << " end\n"
> code << "def eql?(o) " << fields.map {|f| "self.#{f}.eql?
> (o.#{f})" }.join(" && ") << " end\n"
> code << "def hash() " << fields.map {|f|
> "self.#{f}.hash" }.join(" ^ ") << " end\n"
> mod = Module.new
> mod.module_eval( code )
> mod
> end
>
> - Or -
>
> # Generates identity/key methods based on specified attributes.
> #
> # equate_on :a, :b
> #
> # _is equivalent to_
> #
> # def ==(o)
> # self.a == o.a && self.b == o.b
> # end
> #
> # def eql?(o)
> # self.a.eql?(o.a) && self.b.eql?(o.b)
> # end
> #
> # def hash()
> # self.a.hash ^ self.b.hash
> # end
>
> def equate_on(*fields)
> code = ""
> code << "def ==(o) " << fields.map {|f| "self.#{f} ==
> o.#{f}" }.join(" && ") << " end\n"
> code << "def eql?(o) " << fields.map {|f| "self.#{f}.eql?
> (o.#{f})" }.join(" && ") << " end\n"
> code << "def hash() " << fields.map {|f|
> "self.#{f}.hash" }.join(" ^ ") << " end\n"
> class_eval( code )
> fields
> end


I opt for the second solution because the anonymous module does not
have any reuse effects - unless you cache it based on field names. :-)

Kind regards

robert

--
use.inject do |as, often| as.you_can - without end

  Réponse avec citation
Vieux 13/03/2008, 18h09   #3
Trans
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Parametric module or injecting code via class method?



On Mar 13, 4:42 am, "Robert Klemme" <shortcut...@googlemail.com>
wrote:
> 2008/3/13, Trans <transf...@gmail.com>:
>
> > Which approach is better: parametric module or an injecting class
> > method.

>
> Are you writing a book on best practices? There seem to be quite a
> few of these questions recently. :-))


Ha... I probably should be! But right now I'm just working through
some old "TODO" questions in Facets.

> > # Generates identity/key methods based on specified attributes.
> > #
> > # equate_on :a, :b
> > #
> > # _is equivalent to_
> > #
> > # def ==(o)
> > # self.a == o.a && self.b == o.b
> > # end
> > #
> > # def eql?(o)
> > # self.a.eql?(o.a) && self.b.eql?(o.b)
> > # end
> > #
> > # def hash()
> > # self.a.hash ^ self.b.hash
> > # end

>
> > def equate_on(*fields)
> > code = ""
> > code << "def ==(o) " << fields.map {|f| "self.#{f} ==
> > o.#{f}" }.join(" && ") << " end\n"
> > code << "def eql?(o) " << fields.map {|f| "self.#{f}.eql?
> > (o.#{f})" }.join(" && ") << " end\n"
> > code << "def hash() " << fields.map {|f|
> > "self.#{f}.hash" }.join(" ^ ") << " end\n"
> > class_eval( code )
> > fields
> > end

>
> I opt for the second solution because the anonymous module does not
> have any reuse effects - unless you cache it based on field names. :-)


And if we do cache based on field names?

T.

  Réponse avec citation
Vieux 13/03/2008, 18h23   #4
Robert Klemme
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Parametric module or injecting code via class method?

2008/3/13, Trans <transfire@gmail.com>:
>
>
> On Mar 13, 4:42 am, "Robert Klemme" <shortcut...@googlemail.com>
> wrote:
> > 2008/3/13, Trans <transf...@gmail.com>:

>
> >
> > > Which approach is better: parametric module or an injecting class
> > > method.

> >
> > Are you writing a book on best practices? There seem to be quite a
> > few of these questions recently. :-))

>
>
> Ha... I probably should be! But right now I'm just working through
> some old "TODO" questions in Facets.


LOL

> > > # Generates identity/key methods based on specified attributes.
> > > #
> > > # equate_on :a, :b
> > > #
> > > # _is equivalent to_
> > > #
> > > # def ==(o)
> > > # self.a == o.a && self.b == o.b
> > > # end
> > > #
> > > # def eql?(o)
> > > # self.a.eql?(o.a) && self.b.eql?(o.b)
> > > # end
> > > #
> > > # def hash()
> > > # self.a.hash ^ self.b.hash
> > > # end

> >
> > > def equate_on(*fields)
> > > code = ""
> > > code << "def ==(o) " << fields.map {|f| "self.#{f} ==
> > > o.#{f}" }.join(" && ") << " end\n"
> > > code << "def eql?(o) " << fields.map {|f| "self.#{f}.eql?
> > > (o.#{f})" }.join(" && ") << " end\n"
> > > code << "def hash() " << fields.map {|f|
> > > "self.#{f}.hash" }.join(" ^ ") << " end\n"
> > > class_eval( code )
> > > fields
> > > end

> >
> > I opt for the second solution because the anonymous module does not
> > have any reuse effects - unless you cache it based on field names. :-)

>
>
> And if we do cache based on field names?


Aw, com' on. Interesting additional question: should order matter?
I'd say probably yes, but that will reduce reuse of cached entries.

Kind regards

robert


PS: if you run out of tasks (I know, won't happen) - I just discovered
this site:
http://www.virginmedia.com/movies/dv...ator/index.php

--
use.inject do |as, often| as.you_can - without end

  Réponse avec citation
Vieux 13/03/2008, 19h05   #5
Trans
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Parametric module or injecting code via class method?



On Mar 13, 1:23 pm, "Robert Klemme" <shortcut...@googlemail.com>
wrote:
> 2008/3/13, Trans <transf...@gmail.com>:
>
>
>
>
>
> > On Mar 13, 4:42 am, "Robert Klemme" <shortcut...@googlemail.com>
> > wrote:
> > > 2008/3/13, Trans <transf...@gmail.com>:

>
> > > > Which approach is better: parametric module or an injecting class
> > > > method.

>
> > > Are you writing a book on best practices? There seem to be quite a
> > > few of these questions recently. :-))

>
> > Ha... I probably should be! But right now I'm just working through
> > some old "TODO" questions in Facets.

>
> LOL
>
>
>
> > > > # Generates identity/key methods based on specified attributes.
> > > > #
> > > > # equate_on :a, :b
> > > > #
> > > > # _is equivalent to_
> > > > #
> > > > # def ==(o)
> > > > # self.a == o.a && self.b == o.b
> > > > # end
> > > > #
> > > > # def eql?(o)
> > > > # self.a.eql?(o.a) && self.b.eql?(o.b)
> > > > # end
> > > > #
> > > > # def hash()
> > > > # self.a.hash ^ self.b.hash
> > > > # end

>
> > > > def equate_on(*fields)
> > > > code = ""
> > > > code << "def ==(o) " << fields.map {|f| "self.#{f} ==
> > > > o.#{f}" }.join(" && ") << " end\n"
> > > > code << "def eql?(o) " << fields.map {|f| "self.#{f}.eql?
> > > > (o.#{f})" }.join(" && ") << " end\n"
> > > > code << "def hash() " << fields.map {|f|
> > > > "self.#{f}.hash" }.join(" ^ ") << " end\n"
> > > > class_eval( code )
> > > > fields
> > > > end

>
> > > I opt for the second solution because the anonymous module does not
> > > have any reuse effects - unless you cache it based on field names. :-)

>
> > And if we do cache based on field names?

>
> Aw, com' on. Interesting additional question: should order matter?
> I'd say probably yes, but that will reduce reuse of cached entries.


I explored the cache idea a bit more, and it made me see why a Module
approach appealed to me over the injection method, but generating
parametric modules, even if cached seemed somehow wrong too. I derived
this instead:

module EquateOn

def ==(o)
equate_fields.all?{ |f| send(f) == o.send(f) }
end

def eql?(o)
equate_fields.all?{ |f| send(f).eql?(o.send(f)) }
end

def hash
equate_fields.inject(0){ |memo, f| memo ^ send(f).hash }
end

end

def EquateOn(*fields)
define_method(:equate_fields){ fields }
return EquateOn
end

Much better, but I still wonder if it is enough to be preferable over
the a er method.

T.



  Réponse avec citation
Vieux 13/03/2008, 20h35   #6
ara howard
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Parametric module or injecting code via class method?


On Mar 12, 2008, at 7:14 PM, Trans wrote:

> Which approach is better: parametric module or an injecting class
> method.


i would say neither and both. it's saner to decouple them and then
recouple - giving the best of both worlds with the same amount of code:


cfp2:~ > cat a.rb
module Equate
module Methods
def equate a, b
module_eval <<-code
def ==(other)
self.#{ a } == other.#{ a } && self.#{ b } == other.#{ b }
end
def eql?(other)
self.#{ a }.eql?(other.#{ a }) && self.#{ b }.eql?
(other.#{ b })
end
def hash()
self.#{ a }.hash ^ self.#{ b }.hash
end
code
end
end

def Equate.included other
other.send :extend, Methods
end

def Equate.on a, b
Module.new{
include Equate
equate a, b
}
end
end

class C < Struct.new(:a, :b)
include Equate.on(:a, :b)
end

p C[4,2] == C[4,2] #=> true
p C[4,2] == C[4,3] #=> false

class D < Struct.new(:a, :b)
include Equate
equate :a, :b
end

p D[4,2] == D[4,2] #=> true
p D[4,2] == D[4,3] #=> false



cfp2:~ > ruby a.rb
true
false
true
false



a @ http://codeforpeople.com/
--
share your knowledge. it's a way to achieve immortality.
h.h. the 14th dalai lama



  Réponse avec citation
Vieux 13/03/2008, 23h17   #7
Robert Klemme
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Parametric module or injecting code via class method?

On 13.03.2008 20:35, ara howard wrote:
> On Mar 12, 2008, at 7:14 PM, Trans wrote:
>
>> Which approach is better: parametric module or an injecting class
>> method.

>
> i would say neither and both. it's saner to decouple them and then
> recouple - giving the best of both worlds with the same amount of code:
>
>
> cfp2:~ > cat a.rb
> module Equate
> module Methods
> def equate a, b
> module_eval <<-code
> def ==(other)
> self.#{ a } == other.#{ a } && self.#{ b } == other.#{ b }
> end
> def eql?(other)
> self.#{ a }.eql?(other.#{ a }) && self.#{ b }.eql?
> (other.#{ b })
> end
> def hash()
> self.#{ a }.hash ^ self.#{ b }.hash
> end
> code
> end
> end
>
> def Equate.included other
> other.send :extend, Methods
> end
>
> def Equate.on a, b
> Module.new{
> include Equate
> equate a, b
> }
> end
> end
>
> class C < Struct.new(:a, :b)
> include Equate.on(:a, :b)
> end
>
> p C[4,2] == C[4,2] #=> true
> p C[4,2] == C[4,3] #=> false
>
> class D < Struct.new(:a, :b)
> include Equate
> equate :a, :b
> end
>
> p D[4,2] == D[4,2] #=> true
> p D[4,2] == D[4,3] #=> false
>
>
>
> cfp2:~ > ruby a.rb
> true
> false
> true
> false


Using a Struct generated class as base class is a bad example IMHO
because those classes do already have the equation properties.

At the moment the only advantage I see in using modules is avoidance of
namespace pollution. Personally I'd just have a method in class Module
equate_on which defines methods as shown.

Btw, while we're at it, I'd also like order_on which defines <=> based
on fields given. :-)

Kind regards

robert

  Réponse avec citation
Vieux 14/03/2008, 00h42   #8
ara howard
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Parametric module or injecting code via class method?


On Mar 13, 2008, at 4:20 PM, Robert Klemme wrote:

> Using a Struct generated class as base class is a bad example IMHO
> because those classes do already have the equation properties.


heh - yeah bad example. i just used struct to avoid defining atts 'a'
and 'b' and an initializer - i think the example stands with that
though.

> At the moment the only advantage I see in using modules is avoidance
> of namespace pollution. Personally I'd just have a method in class
> Module equate_on which defines methods as shown.



well namspace pollution is no small thing! the other huge advantage
is that running rdoc over something like

class C
module ClassMethods
end
end

is about a billion times better than running it over

class C
singleton_class.module_eval ....

not to mention grep et all.


the other huge advantage of using modules is subtle: if you start out
with code such as

module M

def self.included other
add_equate_method_to other
end

end

and, over the course of your project end up with

module M
X = 4
Y = 2
end


then the result of

class C
include M
end

is that X and Y are dumped into C *even though the included block was
purposely setup to define what happens logically for module
inclusion*. by carving out the target of inclusion one can do

module M
module Methods
end

def self.included other
other.extend Methods
end
end

and dump constants into M to your heart's content without
inadvertently dumping them into every class that wanted a little class
method.

this last bit i just recently have been using - but born out from long
debugging session ;-)

cheers.

a @ http://drawohara.com/
--
sleep is the best meditation.
h.h. the 14th dalai lama




  Réponse avec citation
Réponse


Outils de la discussion

Règles de messages
Vous ne pouvez pas créer de nouvelles discussions
Vous ne pouvez pas envoyer des réponses
Vous ne pouvez pas envoyer des pièces jointes
Vous ne pouvez pas modifier vos messages

Les balises BB sont activées : oui
Les smileys sont activés : oui
La balise [IMG] est activée : oui
Le code HTML peut être employé : non
Trackbacks are oui
Pingbacks are oui
Refbacks are oui


Fuseau horaire GMT +1. Il est actuellement 22h34.


Édité par : vBulletin® version 3.7.2
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.2.0 RC5 Tous droits réservés.
Version française #16 par l'association vBulletin francophone
PHWinfo est un site Éducation Sans Frontières
Ad Management by RedTyger
©Tous droits réservés par les parties respectives
Page generated in 0,27524 seconds with 16 queries