Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Module philosophy

Reply
Thread Tools

Module philosophy

 
 
Leslie Viljoen
Guest
Posts: n/a
 
      06-04-2008
Sorry to beat a dead horse, but to confirm: the only way to mix a
module into an already
existing class it to reopen it with something (ugly) like this:

class String; include Crc; end

(1) Is that right?

And then to mix a module into an instantiated object, you can use
extend, and that
modifies the one object. (2) Philosophically, is there any reason why
extend can't be used
in the same way on classes? (ie. String.extend(Crc))


One other question (3), below is an example of my SelfCrc module. This module
works well when included into String, but extend doesn't work because that
only modifies the one object and .crc16_ok? below tries to call .get_crc16
on a new string that it creates, which fails.

I can modify it to work like so:

def crc16_ok?
first_part = self[0..-3]
first_part.extend(SelfCrc)
first_part.get_crc16 == get_terminating_crc16
end

...is that the right way to make this module work properly? Or are
some modules just not suitable for extend?


module SelfCrc

# Returns the CCITT CRC16 for the current object
#
def get_crc16
@@crctab ||= CrcTab.new
@@crctab.get(self)
end

# Converts the last two characters of this string to
# a numeric CRC and returns it
#
def get_terminating_crc16
(self[-2, 1][0] << + (self[-1, 1][0])
end

# Calculates a CRC for the string, converts it into two
# characters and adds them to the end of the string
#
def add_terminating_crc16!
replace(self + get_crc16.to_s16)
end

# Removes the last two characters from the string
#
def remove_terminating_crc16!
replace(self[0..-3])
end

# Extracts two characters from the end of the string, converts
# them to a numeric CRC and compares that CRC to the CRC of
# the rest of the string. Returns true if the CRC is correct.
#
def crc16_ok?
self[0..-3].get_crc16 == get_terminating_crc16
end
end



Thanks!

Leslie

 
Reply With Quote
 
 
 
 
Stefano Crocco
Guest
Posts: n/a
 
      06-04-2008
On Wednesday 04 June 2008, Leslie Viljoen wrote:
> modifies the one object. (2) Philosophically, is there any reason why
> extend can't be used
> in the same way on classes? (ie. String.extend(Crc))


Because String.extend(Crc) would add the instance methods of the Crc module as
class methods of String, not as instance methods. This would mean you could
do:

String.method_defined_in_crc

but not

"hello".method_defined_in_crc

If you don't like the idea of reopening the class, you can use include with
send:

String.send :include, Crc

Stefano


 
Reply With Quote
 
 
 
 
Robert Klemme
Guest
Posts: n/a
 
      06-04-2008
On 4 Jun., 15:49, Leslie Viljoen <(E-Mail Removed)> wrote:
> Sorry to beat a dead horse, but to confirm: the only way to mix a
> module into an already
> existing class it to reopen it with something (ugly) like this:
>
> class String; include Crc; end
>
> (1) Is that right?
>
> And then to mix a module into an instantiated object, you can use
> extend, and that
> modifies the one object. (2) Philosophically, is there any reason why
> extend can't be used
> in the same way on classes? (ie. String.extend(Crc))


You need to be able to distinguish between importing class methods and
importing instance methods (see Stefano's reply).

> One other question (3), below is an example of my SelfCrc module. This module
> works well when included into String, but extend doesn't work because that
> only modifies the one object and .crc16_ok? below tries to call .get_crc16
> on a new string that it creates, which fails.
>
> I can modify it to work like so:
>
> def crc16_ok?
> first_part = self[0..-3]
> first_part.extend(SelfCrc)
> first_part.get_crc16 == get_terminating_crc16
> end
>
> ..is that the right way to make this module work properly? Or are
> some modules just not suitable for extend?


If your module expects to be present in all instances of the class
then including is the only reasonable way to do it IMHO.

I can think of a number of other designs which would not have this
issue but since I do not exactly know what your module does
(especially CrcTab which could be a kind of cache) I am reluctant to
enumerate them.

Assuming that you want to store strings along with their CRC's I'd
rather have a separate class that has a String and a CRC. That seems
more natural to me. This would also avoid the issue that you cannot
easily determine whether a String does contain its CRC or not etc.

Kind regards

robert
 
Reply With Quote
 
David Masover
Guest
Posts: n/a
 
      06-04-2008
On Wednesday 04 June 2008 08:49:48 Leslie Viljoen wrote:
> Sorry to beat a dead horse, but to confirm: the only way to mix a
> module into an already
> existing class it to reopen it with something (ugly) like this:
>
> class String; include Crc; end
>
> (1) Is that right?


Short answer: You'll have to mess with it dynamically, but that is far from
the only syntax to do so. Other obvious ones:

String.class_eval { include Crc }
String.send :include, Crc

And there are always stranger things like:

"foo".class.class_eval { include Crc }

> And then to mix a module into an instantiated object, you can use
> extend, and that
> modifies the one object.


Yes, but keep in mind: "include"ing a module into a class will affect all
existing and future instances of that class, and of any subclasses. So you're
probably not going to extend if you include.

> (2) Philosophically, is there any reason why
> extend can't be used
> in the same way on classes? (ie. String.extend(Crc))


As others have said, they do different things -- include adds instance methods
to a class, and extend adds methods to an object.

It's a tricky concept, but remember that classes are objects, too. So:

some_string.extend(Crc) # will define some_string.crc16_ok?
String.extend(Crc) # will define String.crc16_ok?

So, extend works on the actual object you use it on, and include works on any
instances of it. You could do this, for example:

Class.send :include, Crc
# Now all classes will have a crc16_ok? class method, for example:
String.crc16_ok?

That's probably not what you want.

> ...is that the right way to make this module work properly? Or are
> some modules just not suitable for extend?


I think that comes down to personal philosophy -- I haven't seen (or
used) 'extend' a whole lot. It seems most useful when you'd only want to
apply it to a single object, and then, I'd usually use instance_eval instead.

On the other hand, including it into String means you're affecting all
Strings, and polluting String's method namespace. It means that no one else
can define String#get_crc16.

The other way would be to use a separate class -- either something which
contains both a String and a CRC (as Robert suggested), or something which
inherits from String.

And either way, depending on how much work you want to do, you could always
override all methods on String which return a String, and force them to
either return an extended String, or return a CrcString, depending on how you
decide to do it.

 
Reply With Quote
 
Leslie Viljoen
Guest
Posts: n/a
 
      06-04-2008
Holy macaroni, thanks for these replies!

What I am trying to accomplish here is the optional modification of
core classes. So my CRC lib can handle useful calculations, and
optionally add convenient methods to String and Fixnum too.

That way people can have the convenience if they like, but they must
explicitly authorise it with String.send(:include ..). It seems like a
good plan to me, but the lack of a public String.include() method
makes me think this is a very rare plan.

These strings with CRC's on the ends are coming in from sockets, and I
have to check them, extract them, use them and then put CRC's on the
end of the replies before sending them out. In this case it's quite
nice to do:

begin
msg, sender = @socket.recvfrom(1500)
end while (!msg.crc16_ok?)
msg.remove_terminating_crc16!
...

- but it's true that I might forget to remove that crc. So perhaps
decend from String like you say:

begin
msg, sender = @socket.recvfrom(1500)
msg = CrcString(msg)
end while (!msg.crc16_ok?)
(now use msg directly)

- and I'd know immediately if I'd forgotten to construct the CrcString
because crc16_ok? would fail.


And then a third option would be to modify Socket:
class Socket
def recv_checked(n)
CrcString(recvfrom(n))
end
end

..which I'd again attempt by providing a module that I'd
Socket.send(:include, CrcSocket)

Or once again I could override both String and Socket to make
CrcString and CrcSocket which returns CrcStrings. You're never short
on options with Ruby!

Les









On 6/4/08, David Masover <(E-Mail Removed)> wrote:
> On Wednesday 04 June 2008 08:49:48 Leslie Viljoen wrote:
>> Sorry to beat a dead horse, but to confirm: the only way to mix a
>> module into an already
>> existing class it to reopen it with something (ugly) like this:
>>
>> class String; include Crc; end
>>
>> (1) Is that right?

>
> Short answer: You'll have to mess with it dynamically, but that is far from
> the only syntax to do so. Other obvious ones:
>
> String.class_eval { include Crc }
> String.send :include, Crc
>
> And there are always stranger things like:
>
> "foo".class.class_eval { include Crc }
>
>> And then to mix a module into an instantiated object, you can use
>> extend, and that
>> modifies the one object.

>
> Yes, but keep in mind: "include"ing a module into a class will affect all
> existing and future instances of that class, and of any subclasses. So
> you're
> probably not going to extend if you include.
>
>> (2) Philosophically, is there any reason why
>> extend can't be used
>> in the same way on classes? (ie. String.extend(Crc))

>
> As others have said, they do different things -- include adds instance
> methods
> to a class, and extend adds methods to an object.
>
> It's a tricky concept, but remember that classes are objects, too. So:
>
> some_string.extend(Crc) # will define some_string.crc16_ok?
> String.extend(Crc) # will define String.crc16_ok?
>
> So, extend works on the actual object you use it on, and include works on
> any
> instances of it. You could do this, for example:
>
> Class.send :include, Crc
> # Now all classes will have a crc16_ok? class method, for example:
> String.crc16_ok?
>
> That's probably not what you want.
>
>> ...is that the right way to make this module work properly? Or are
>> some modules just not suitable for extend?

>
> I think that comes down to personal philosophy -- I haven't seen (or
> used) 'extend' a whole lot. It seems most useful when you'd only want to
> apply it to a single object, and then, I'd usually use instance_eval
> instead.
>
> On the other hand, including it into String means you're affecting all
> Strings, and polluting String's method namespace. It means that no one else
> can define String#get_crc16.
>
> The other way would be to use a separate class -- either something which
> contains both a String and a CRC (as Robert suggested), or something which
> inherits from String.
>
> And either way, depending on how much work you want to do, you could always
> override all methods on String which return a String, and force them to
> either return an extended String, or return a CrcString, depending on how
> you
> decide to do it.
>
>



--
[we need your code-fu] : www.zadic.co.za

 
Reply With Quote
 
Marc Heiler
Guest
Posts: n/a
 
      06-04-2008
> It seems like a good plan to me, but the lack of a
> public String.include() method makes me think this is a
> very rare plan.


It might be rare because in reality this is not so much a
problem IMHO, despite some people claiming it could be. (I had
an angry IRC "discussion" with a C# proponent over this, I
really dislike people iterating about the "danger" of concepts
despite others applying them for many years without any
problem ... )

What could be nice is to store different "states" of ruby classes
and restore to them at user's will. (Or additionally restore the
"start" the state of slowly "evolved" ruby classes as well).

I mean both standard classes (more important) and user-built
ones (less important, IMHO). It is interesting to see that
someone like the sandbox of _why was more an afterthought
than an initial design idea. I think there is plenty of
more room in this direction, who knows... maybe in a few
years. Ruby is like the OOP language that goes towards
new paradigms - with class derived objects - the most easiest.

Ruby is great but it is not perfect for everyone or every
use case. And since 99% of new languages will have crappy
syntax, the most likely language to beat Ruby will be ...

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

 
Reply With Quote
 
David Masover
Guest
Posts: n/a
 
      06-04-2008
On Wednesday 04 June 2008 13:53:26 Leslie Viljoen wrote:
> Holy macaroni, thanks for these replies!
>
> What I am trying to accomplish here is the optional modification of
> core classes. So my CRC lib can handle useful calculations, and
> optionally add convenient methods to String and Fixnum too.


Probably included, then, rather than extended.

> That way people can have the convenience if they like, but they must
> explicitly authorise it with String.send(:include ..). It seems like a
> good plan to me, but the lack of a public String.include() method
> makes me think this is a very rare plan.


Generally, people don't expect to have to do more than a require to have the
library ready to use. So I'd do that yourself, somewhere in the library file.

 
Reply With Quote
 
Leslie Viljoen
Guest
Posts: n/a
 
      06-04-2008
Perhaps people don't have this problem very often, but I once spent
three days puzzling over a Rails app that worked fine on my computer,
but not at the web host. A library had been installed by the host that
created a class that was require'd somewhere down the line. That class
had the same name as one of my models, and it totally killed my app.

Having a dynamic base environment works fine until there's a clash. As
the code base grows, so do the chances of a clash and also the
difficulty in finding it.


On 6/4/08, David Masover <(E-Mail Removed)> wrote:
> On Wednesday 04 June 2008 13:53:26 Leslie Viljoen wrote:
>> Holy macaroni, thanks for these replies!
>>
>> What I am trying to accomplish here is the optional modification of
>> core classes. So my CRC lib can handle useful calculations, and
>> optionally add convenient methods to String and Fixnum too.

>
> Probably included, then, rather than extended.
>
>> That way people can have the convenience if they like, but they must
>> explicitly authorise it with String.send(:include ..). It seems like a
>> good plan to me, but the lack of a public String.include() method
>> makes me think this is a very rare plan.

>
> Generally, people don't expect to have to do more than a require to have the
> library ready to use. So I'd do that yourself, somewhere in the library
> file.
>
>



--
[we need your code-fu] : www.zadic.co.za

 
Reply With Quote
 
Donald Ball
Guest
Posts: n/a
 
      06-04-2008
On Wed, Jun 4, 2008 at 3:20 PM, Leslie Viljoen <(E-Mail Removed)> wrote:
> Perhaps people don't have this problem very often, but I once spent
> three days puzzling over a Rails app that worked fine on my computer,
> but not at the web host. A library had been installed by the host that
> created a class that was require'd somewhere down the line. That class
> had the same name as one of my models, and it totally killed my app.
>
> Having a dynamic base environment works fine until there's a clash. As
> the code base grows, so do the chances of a clash and also the
> difficulty in finding it.


I had a similar experience a while back wherein I inadvertently
overrode a method defined by ActiveRecord somewhere. At the time, I
wondered if it might be a good idea to have the ruby interpreter warn
when a method was overridden, unless either the original method was
flagged as silently over-ridable (e..g Object.to_s) or the overriding
method was flagged as intentional (e.g. overriding
ActiveRecord::Base.find). It's almost certainly not worth the hassle
even if the approach is sound, but after spending some hours digging
through the darker corners of the ActiveRecord code, it seemed like an
awfully attractive notion.

- donald

 
Reply With Quote
 
Leslie Viljoen
Guest
Posts: n/a
 
      06-04-2008
ruby -w does warn on method redefinitions!

On 6/4/08, Donald Ball <(E-Mail Removed)> wrote:
> On Wed, Jun 4, 2008 at 3:20 PM, Leslie Viljoen <(E-Mail Removed)>
> wrote:
>> Perhaps people don't have this problem very often, but I once spent
>> three days puzzling over a Rails app that worked fine on my computer,
>> but not at the web host. A library had been installed by the host that
>> created a class that was require'd somewhere down the line. That class
>> had the same name as one of my models, and it totally killed my app.
>>
>> Having a dynamic base environment works fine until there's a clash. As
>> the code base grows, so do the chances of a clash and also the
>> difficulty in finding it.

>
> I had a similar experience a while back wherein I inadvertently
> overrode a method defined by ActiveRecord somewhere. At the time, I
> wondered if it might be a good idea to have the ruby interpreter warn
> when a method was overridden, unless either the original method was
> flagged as silently over-ridable (e..g Object.to_s) or the overriding
> method was flagged as intentional (e.g. overriding
> ActiveRecord::Base.find). It's almost certainly not worth the hassle
> even if the approach is sound, but after spending some hours digging
> through the darker corners of the ActiveRecord code, it seemed like an
> awfully attractive notion.
>
> - donald
>
>



--
[we need your code-fu] : www.zadic.co.za

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
local class philosophy puzzlecracker Java 12 01-25-2006 08:23 PM
philosophy : ! vs false ronron Java 31 02-16-2005 09:46 PM
The philosophy of exception. zaemin Java 7 12-03-2003 09:15 AM
Philosophy Roedy Green Java 1 09-10-2003 10:33 AM
Philosophy: Developers shouldn't write applications? - Cotsec Forms David Ford Java 0 08-16-2003 03:58 AM



Advertisments