Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Ruby (http://www.velocityreviews.com/forums/f66-ruby.html)
-   -   [ANN] (Real) Primitive Ruby Generics support (http://www.velocityreviews.com/forums/t827296-ann-real-primitive-ruby-generics-support.html)

Isaac Devine 12-27-2005 09:59 AM

[ANN] (Real) Primitive Ruby Generics support
 
Hi all,

I have been hacking away to create a simple library that adds
generics-like qualities to ruby. At the moment you can define methods
with type-matches, defaults if no match and different number of
argument matches. Currently thinking about adding pattern-matching
support from eigenclass blog. Depends on ruby facets.

Usage examples (Tests) are at the bottom.
Any suggestions, comments, flames ;-) ?

thanks,
Isaac Devine
P.S. BSD licensed. (don't know about the bit from why's guide though...)

--------------generics.rb--------------
# This file contains all you need to add generics to any ruby class :)
# ie.
# class Sample
# include Generics
# generic_method :name, Types do
# CODE
# end
## Default case
# generic_method :name do
# CODE
# end
# end
require 'mega/inheritor'

# This Object stuff from Why's Metaprogramming guide
class Object
# The hidden singleton lurks behind everyone
def metaclass; class << self; self; end; end
def meta_eval &blk; metaclass.instance_eval &blk; end

# Adds methods to a metaclass
def meta_def name, &blk
meta_eval { define_method name, &blk }
end

# Defines an instance method within a class
def class_def name, &blk
class_eval { define_method name, &blk }
end
end
# End Why's Stuff.

module Generics
class_inherit do
# Get a metaclass for this class
def metaclass; class << self; self; end; end

# metaprogramming code for generic_method
def generic_method(method_name, *types, &blk )
# have a class instance hash which holds the following:
# { :method_name => { type_name => block, type_name => block } }
# initialize it here...
class_eval {
# define the class generic_signatures if they don't exist
@generic_signatures = Hash.new if not
defined?(@generic_signatures) # define the generic method's signatures
if they don't exist @generic_signatures[method_name] = Hash.new unless
@generic_signatures.has_key?(method_name)
def self.generic_signatures
return @generic_signatures
end
}

# check to see if we are the default
if types.empty?
class_eval {
@generic_signatures[method_name].default = blk
}
else # got a typelist?
# create the type "string"
specific_method_name = types.join("_").to_sym
class_eval {
@generic_signatures[method_name][specific_method_name] = blk
}
end

# define the class method that does the dispatch to
# the appropiate block.
class_def(method_name) do |*args|
type_sig_arr = args.collect { |a| a.class }
type_sig = type_sig_arr.join('_').to_sym
self.class.generic_signatures[method_name][type_sig].call(*args)
end
end

end
end

class Test
include Generics
generic_method :get, String do |arg|
puts "In String... -- #{arg}"
end

generic_method :get, Fixnum do |arg|
puts "In Fixnum... -- #{arg}"
end
end

class Test2
include Generics
generic_method :two_args, String, Fixnum do |arg1, arg2|
puts "got a String and Fixnum"
end
generic_method :two_args, String, String do |arg1, arg2|
puts "got two Strings"
end
end
# does having a method that accepts two different numbers
# of arguments work?
class TestVariable
include Generics
generic_method :test_method, String do |arg1|
puts "single argument"
end

generic_method :test_method, String, Fixnum do |arg1,arg2|
puts "two arguments"
end
end

class TestDefault
include Generics

generic_method :test, String do |arg|
puts "in String!"
end

generic_method :test do |arg|
puts "The rest!"
end
end



dblack@wobblini.net 12-27-2005 10:46 AM

Re: [ANN] (Real) Primitive Ruby Generics support
 
Hi --

On Tue, 27 Dec 2005, Isaac Devine wrote:

> Hi all,
>
> I have been hacking away to create a simple library that adds
> generics-like qualities to ruby. At the moment you can define methods
> with type-matches, defaults if no match and different number of
> argument matches. Currently thinking about adding pattern-matching
> support from eigenclass blog. Depends on ruby facets.
>
> Usage examples (Tests) are at the bottom.
> Any suggestions, comments, flames ;-) ?


Call classes classes, not types :-)

Call singleton classes singleton classes, not metaclasses or
eigenclasses :-)


David

--
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!
http://www.manning.com/books/black



James Edward Gray II 12-27-2005 01:56 PM

Re: [ANN] (Real) Primitive Ruby Generics support
 
On Dec 27, 2005, at 4:46 AM, dblack@wobblini.net wrote:

> On Tue, 27 Dec 2005, Isaac Devine wrote:
>
>> eigenclass blog

>
> Call singleton classes singleton classes, not metaclasses or
> eigenclasses :-)


Just to be clear, the original post wasn't inventing terminology, it
was referring to a blog:

http://eigenclass.org/

James Edward Gray II




gabriele renzi 12-27-2005 04:31 PM

Re: [ANN] (Real) Primitive Ruby Generics support
 
Isaac Devine ha scritto:
> Hi all,
>
> I have been hacking away to create a simple library that adds
> generics-like qualities to ruby. At the moment you can define methods
> with type-matches, defaults if no match and different number of
> argument matches. Currently thinking about adding pattern-matching
> support from eigenclass blog. Depends on ruby facets.
>
> Usage examples (Tests) are at the bottom.
> Any suggestions, comments, flames ;-) ?
>
> thanks,
> Isaac Devine


I think you could be intererested in the StrongTyping module
http://raa.ruby-lang.org/project/strongtyping/

Florian Groß 12-28-2005 02:24 PM

Re: [ANN] (Real) Primitive Ruby Generics support
 
Isaac Devine wrote:

> I have been hacking away to create a simple library that adds
> generics-like qualities to ruby. At the moment you can define methods
> with type-matches, defaults if no match and different number of
> argument matches.


Been there, done that:

http://ruby-contract.rubyforge.org/

New ideas are very welcome.

--
http://flgr.0x42.net/




Isaac Devine 12-29-2005 03:13 AM

Re: [ANN] (Real) Primitive Ruby Generics support
 
On Wed, 28 Dec 2005 23:24:01 +0900
Florian Gro=DF <florgro@gmail.com> wrote:
> > I have been hacking away to create a simple library that adds
> > generics-like qualities to ruby. At the moment you can define
> > methods with type-matches, defaults if no match and different
> > number of argument matches.

>=20
> Been there, done that:
>=20
> http://ruby-contract.rubyforge.org/
>=20
> New ideas are very welcome.
>=20


Thanks! I've quickly looked at the ruby-doc for that. It's seems to
only be able to specific "contracts" for classes, with method
signatures as a subset. What my goal for generics is to be able to
choose what code to execute based on method/class parameter types.
ie.
converting :
def foo(arg)
if arg.kind_of? String=20
puts "it is a string! reverse it! #{arg.reverse}"
elsif arg.kind_of? Fixnum
puts "Fixnum! double it! #{2*arg}"
end
end

into:

generic_method :foo, String do |arg|
puts "it is a string! reverse it! #{arg.reverse}"
end

generic_method :foo, Fixnum do |arg|
puts "Fixnum! double it! #{2*arg}"
end

In the future I would like to be able to extend this to classes as
well. One implication of this we will be the ability to get rid of
"adapter" classes when joining heirachys. One example would be adding
support to reading from a String when a class can only read from a File.

ie.
generic_class :SomeClass, String do
def getline
...
end

Another wish is for pattern matching:
generic_method :foo, :a, :b :a do ...
where wherever :a occurs it must be the same type so:
foo 4 "a" 4 passes
but=20
foo "a" 4 4 fails.

Looking at the rdoc some code in that could be very helpful - such as
Contact.adapt.=20

thanks,
Isaac

P.S. I have an updated version which generates methods instead of
lookup + some extras. Nobody mind if I post it to the ml later(ie no
negative)?



Robert Klemme 12-29-2005 11:06 AM

Re: [ANN] (Real) Primitive Ruby Generics support
 
Isaac Devine <isaac.devine@gmail.com> wrote:
> On Wed, 28 Dec 2005 23:24:01 +0900
> Florian Groß <florgro@gmail.com> wrote:
>>> I have been hacking away to create a simple library that adds
>>> generics-like qualities to ruby. At the moment you can define
>>> methods with type-matches, defaults if no match and different
>>> number of argument matches.

>>
>> Been there, done that:
>>
>> http://ruby-contract.rubyforge.org/
>>
>> New ideas are very welcome.
>>

>
> Thanks! I've quickly looked at the ruby-doc for that. It's seems to
> only be able to specific "contracts" for classes, with method
> signatures as a subset. What my goal for generics is to be able to
> choose what code to execute based on method/class parameter types.
> ie.
> converting :
> def foo(arg)
> if arg.kind_of? String
> puts "it is a string! reverse it! #{arg.reverse}"
> elsif arg.kind_of? Fixnum
> puts "Fixnum! double it! #{2*arg}"
> end
> end
>
> into:
>
> generic_method :foo, String do |arg|
> puts "it is a string! reverse it! #{arg.reverse}"
> end
>
> generic_method :foo, Fixnum do |arg|
> puts "Fixnum! double it! #{2*arg}"
> end


That's not generics but overloading. I'm sorry, but with these things it's
really important to use teminology properly otherwise you'll likely cause a
lot of misunderstandings.

> In the future I would like to be able to extend this to classes as
> well. One implication of this we will be the ability to get rid of
> "adapter" classes when joining heirachys. One example would be adding
> support to reading from a String when a class can only read from a
> File.
>
> ie.
> generic_class :SomeClass, String do
> def getline
> ..
> end


IMHO this is a bad example because you can turn a String into a StringIO
which supports IO like behavior. If some method works on an IO instance it
almost always works on a StringIO, too.

> Another wish is for pattern matching:
> generic_method :foo, :a, :b :a do ...
> where wherever :a occurs it must be the same type so:
> foo 4 "a" 4 passes
> but
> foo "a" 4 4 fails.


Sounds like you wanted to reimplement some features very common with
functional languages in Ruby. Why do you do that?

> P.S. I have an updated version which generates methods instead of
> lookup + some extras. Nobody mind if I post it to the ml later(ie no
> negative)?


If you really intend to go further down that road I suggest you create a
project on rubyforge (or merge with an existing project).

I'm sorry to be so discouraging but this seems like yet another attempt to
retrofit other languages' features to Ruby instead of using it the way it
is.

Kind regards

robert


dblack@wobblini.net 12-29-2005 12:05 PM

Re: [ANN] (Real) Primitive Ruby Generics support
 
--8323328-1447388271-1135857902=:18432
Content-Type: MULTIPART/MIXED; BOUNDARY="8323328-1447388271-1135857902=:18432"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

--8323328-1447388271-1135857902=:18432
Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE

Hi --

On Thu, 29 Dec 2005, Isaac Devine wrote:

> On Wed, 28 Dec 2005 23:24:01 +0900
> Florian Gro=DF <florgro@gmail.com> wrote:
>>> I have been hacking away to create a simple library that adds
>>> generics-like qualities to ruby. At the moment you can define
>>> methods with type-matches, defaults if no match and different
>>> number of argument matches.

>>
>> Been there, done that:
>>
>> http://ruby-contract.rubyforge.org/
>>
>> New ideas are very welcome.
>>

>
> Thanks! I've quickly looked at the ruby-doc for that. It's seems to
> only be able to specific "contracts" for classes, with method
> signatures as a subset. What my goal for generics is to be able to
> choose what code to execute based on method/class parameter types.


Keep in mind that type !=3D class in Ruby. I think what you're
describing is class/module ancestry (the kind of thing you can test
with kind_of?) rather than type.

Type is, in a sense, circular: an object's type is essentially "the
type which is the type of objects which do what this object does".
Among other things, that means that for practical purposes objects can
be of multiple types.

The usual way for objects to identify themselves as suitable for a
given purpose is by their type -- that is, by the criterion of what
messages they understand. Class membership can give you a likely
answer to this, but not a definite one. Depending on kind_of? can
also limit your ability to make objects of different classes all
converge on a particular capability. It tends to discourage thinking
in terms of type and object-centered programming possibilities,
including duck typing.

Anyway -- you can of course use kind_of? all you like :-) But keep in
mind that it's not a type-test.


David

--=20
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!
http://www.manning.com/books/black
--8323328-1447388271-1135857902=:18432--
--8323328-1447388271-1135857902=:18432--



Florian Groß 12-29-2005 02:20 PM

Re: [ANN] (Real) Primitive Ruby Generics support
 
Isaac Devine wrote:

> Thanks! I've quickly looked at the ruby-doc for that. It's seems to
> only be able to specific "contracts" for classes, with method
> signatures as a subset.


Hm, actually it provides a way of using unit tests for checking types,
but will still let you do strong typing (via classes) and duck typing
(via messages).

It then defines a way of adding type annotations to methods. Where types
still means contract/class/message etc.

> [...] choose what code to execute based on method/class parameter types.
> [...] support to reading from a String when a class can only read from a File.
> [...] Another wish is for pattern matching: [...]
>
> Looking at the rdoc some code in that could be very helpful - such as
> Contact.adapt.


Basically at the moment I do type annotations for methods. So you could
for example specify that you have a method that needs a Symbol and the
Contract library would make sure that an exception will be raised for
Fixnums -- it would however automatically invoke .to_sym (because there
is an adaption route to Symbol for that) so Strings would work as well.

The problem with this is that all these conversions are explicit and
that you can't define custom conversions that will just apply in the
scope of your methods or classes. It's hard to find a good balance this
way, because too much automatic conversion can very easily cause very
surprising results.

I've not yet coded up multi method dispatch (which seems to be your
primary goal for now), but it would be possible. For now you would still
need to do the dispatching yourself by using ruby-contract's methods for
checking whether your arguments match given types and then doing
whatever you want to happen.

Pattern matching is interesting as well, but I can't think of a good
implementation right now.

If you can come up with ways of integrating the functionality that you
want in a clean way into ruby-contract then I'd be pleased to merge it.
But even if it is hard to integrate this into ruby-contract's API feel
free to build on the functionality it already has.

I tried hard to have unit tests with high coverage so reading through
them might give you a bit more feeling of what is already there and how
it can be used.

--
http://flgr.0x42.net/




dblack@wobblini.net 12-29-2005 03:20 PM

Re: [ANN] (Real) Primitive Ruby Generics support
 
--8323328-298484063-1135869616=:2688
Content-Type: MULTIPART/MIXED; BOUNDARY="8323328-298484063-1135869616=:2688"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

--8323328-298484063-1135869616=:2688
Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE

Hi --

On Thu, 29 Dec 2005, Florian Gro=DF wrote:

> Isaac Devine wrote:
>
>> Thanks! I've quickly looked at the ruby-doc for that. It's seems to
>> only be able to specific "contracts" for classes, with method
>> signatures as a subset.=20

>
> Hm, actually it provides a way of using unit tests for checking types, bu=

t=20
> will still let you do strong typing (via classes) and duck typing (via=20
> messages).


How about strong typing via messages? :-)


David

--=20
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!
http://www.manning.com/books/black
--8323328-298484063-1135869616=:2688--
--8323328-298484063-1135869616=:2688--




All times are GMT. The time now is 10:06 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.