[ANN] (Real) Primitive Ruby Generics support

Discussion in 'Ruby' started by Isaac Devine, Dec 27, 2005.

  1. Isaac Devine

    Isaac Devine Guest

    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
     
    Isaac Devine, Dec 27, 2005
    #1
    1. Advertising

  2. Isaac Devine

    Guest

    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


    "Ruby for Rails", from Manning Publications, coming April 2006!
    http://www.manning.com/books/black
     
    , Dec 27, 2005
    #2
    1. Advertising

  3. On Dec 27, 2005, at 4:46 AM, 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
     
    James Edward Gray II, Dec 27, 2005
    #3
  4. 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/
     
    gabriele renzi, Dec 27, 2005
    #4
  5. 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/
     
    Florian Groß, Dec 28, 2005
    #5
  6. Isaac Devine

    Isaac Devine Guest

    On Wed, 28 Dec 2005 23:24:01 +0900
    Florian Gro=DF <> 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)?
     
    Isaac Devine, Dec 29, 2005
    #6
  7. Isaac Devine <> wrote:
    > On Wed, 28 Dec 2005 23:24:01 +0900
    > Florian Groß <> 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
     
    Robert Klemme, Dec 29, 2005
    #7
  8. Isaac Devine

    Guest

    --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 <> 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


    "Ruby for Rails", from Manning Publications, coming April 2006!
    http://www.manning.com/books/black
    --8323328-1447388271-1135857902=:18432--
    --8323328-1447388271-1135857902=:18432--
     
    , Dec 29, 2005
    #8
  9. 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/
     
    Florian Groß, Dec 29, 2005
    #9
  10. Isaac Devine

    Guest

    --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


    "Ruby for Rails", from Manning Publications, coming April 2006!
    http://www.manning.com/books/black
    --8323328-298484063-1135869616=:2688--
    --8323328-298484063-1135869616=:2688--
     
    , Dec 29, 2005
    #10
  11. wrote:

    >> 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).

    > How about strong typing via messages? :)


    I guess I should have said static typing. Though that is not exclusive
    too classes either. I guess the only right term is "class based typing"
    then?

    --
    http://flgr.0x42.net/
     
    Florian Groß, Dec 29, 2005
    #11
  12. T24gMTIvMjkvMDUsIFJvYmVydCBLbGVtbWUgPGJvYi5uZXdzQGdteC5uZXQ+IHdyb3RlOgo+IElz
    YWFjIERldmluZSA8aXNhYWMuZGV2aW5lQGdtYWlsLmNvbT4gd3JvdGU6Cj4gPiBBbm90aGVyIHdp
    c2ggaXMgZm9yIHBhdHRlcm4gbWF0Y2hpbmc6Cj4gPiAgIGdlbmVyaWNfbWV0aG9kIDpmb28sIDph
    LCA6YiA6YSBkbyAuLi4KPiA+IHdoZXJlIHdoZXJldmVyIDphIG9jY3VycyBpdCBtdXN0IGJlIHRo
    ZSBzYW1lIHR5cGUgc286Cj4gPiAgIGZvbyA0ICJhIiA0IHBhc3Nlcwo+ID4gYnV0Cj4gPiAgIGZv
    byAiYSIgNCA0IGZhaWxzLgo+Cj4gU291bmRzIGxpa2UgeW91IHdhbnRlZCB0byByZWltcGxlbWVu
    dCBzb21lIGZlYXR1cmVzIHZlcnkgY29tbW9uIHdpdGgKPiBmdW5jdGlvbmFsIGxhbmd1YWdlcyBp
    biBSdWJ5LiAgV2h5IGRvIHlvdSBkbyB0aGF0PwoKTWF5YmUgdGhpcyBpcyBiZWNhdXNlIHRoZXNl
    IGZlYXR1cmVzIGFyZSBmb3VuZCB0byBiZSB1c2VmdWwuCg==
     
    Ilmari Heikkinen, Dec 30, 2005
    #12
  13. Isaac Devine

    ToRA Guest

    Re: (Real) Primitive Ruby Generics support

    Florian Groß wrote:
    > wrote:
    >
    > >> 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).

    > > How about strong typing via messages? :)

    >
    > I guess I should have said static typing. Though that is not exclusive
    > too classes either. I guess the only right term is "class based typing"
    > then?

    Static typing means the type checking happens at "compile" time (or NOT
    during the execution of the program!). You mean Nominal typing
    (nominal as in name (using in this case classname)) as opposed to
    structural (messages / aka duck) typing. Strong typing means that you
    can't get undefined behaviour out of the system at runtime (all 'type
    errors' are caught, generally in this case by method missing errors
    getting thrown).

    As another poster said, this terminology needs to be used correctly
    otherwise people do get confused :)

    Tris
     
    ToRA, Jan 1, 2006
    #13
  14. Isaac Devine

    Gene Tani Guest

    Re: (Real) Primitive Ruby Generics support

    ToRA wrote:
    > Florian Groß wrote:
    > > wrote:
    > >
    > > >> 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).
    > > > How about strong typing via messages? :)

    > >
    > > I guess I should have said static typing. Though that is not exclusive
    > > too classes either. I guess the only right term is "class based typing"
    > > then?

    > Static typing means the type checking happens at "compile" time (or NOT
    > during the execution of the program!). You mean Nominal typing
    > (nominal as in name (using in this case classname)) as opposed to
    > structural (messages / aka duck) typing. Strong typing means that you
    > can't get undefined behaviour out of the system at runtime (all 'type
    > errors' are caught, generally in this case by method missing errors
    > getting thrown).
    >
    > As another poster said, this terminology needs to be used correctly
    > otherwise people do get confused :)
    >


    "Nominal/structural" typing, haven't seen that one before. Artima
    seems to have purged all their dogfights about what static/dynamic
    strong/weak typing means, but you can read google caches, e.g.

    http://66.102.7.104/search?q=cache:...tima.com strong typing&hl=en&client=firefox-a

    Seems to me that ruby developers can agree on what strong / dynamic
    typing means, but when you go out and encounter people from smalltalk,
    lisp, haskell, ML, java/C#, ... Also all those *nice* discussions
    about what overloading/polymorphism means, delegation/composition,
    pass by value/reference ;-{}
    > Tris
     
    Gene Tani, Jan 1, 2006
    #14
  15. Isaac Devine

    Hal Fulton Guest

    Re: (Real) Primitive Ruby Generics support

    Florian Gro=DF wrote:
    > ToRA wrote:
    >=20
    >> Static typing means the type checking happens at "compile" time (or NO=

    T
    >> during the execution of the program!). You mean Nominal typing
    >> (nominal as in name (using in this case classname)) as opposed to
    >> structural (messages / aka duck) typing. Strong typing means that you
    >> can't get undefined behaviour out of the system at runtime (all 'type
    >> errors' are caught, generally in this case by method missing errors
    >> getting thrown).

    >=20
    >=20
    > Already knew about dynamic <> static and strong <> weak.
    >=20
    > But nominal <> structural is what I was looking for in this case. Thank=

    s!
    >=20


    I have never heard these terms used this way, but it is interesting.

    Are those in common use by some group of people somewhere?


    Hal
     
    Hal Fulton, Jan 2, 2006
    #15
  16. Isaac Devine

    Hal Fulton Guest

    Re: (Real) Primitive Ruby Generics support

    Florian Gro=DF wrote:
    > Hal Fulton wrote:
    >=20
    >>> Already knew about dynamic <> static and strong <> weak.
    >>>
    >>> But nominal <> structural is what I was looking for in this case.=20
    >>> Thanks!

    >>
    >> I have never heard these terms used this way, but it is interesting.
    >>
    >> Are those in common use by some group of people somewhere?

    >=20
    >=20
    > At least the first two pairs ought to be unless I misremembered them.
    >=20


    Sure, I know those. It was the nominal/structural I was
    asking about.


    Hal
     
    Hal Fulton, Jan 2, 2006
    #16
  17. Isaac Devine

    ToRA Guest

    Re: (Real) Primitive Ruby Generics support

    Hey,

    Well I'm a uni student (with a loose interest in type-theory) and its
    cropped up in some literature I'm reading. Usually under the guise of
    structural sub-typing and nominal sub-typing; I recall some discussion
    on Lambda-the-ultimate on whether structural subtyping == duck typing.
    (http://lambda-the-ultimate.org/node/view/1201)

    Also see the wikipedia article on subtype
    (http://en.wikipedia.org/wiki/Subtype), certainly in published papers
    in the typing area these terms come up.

    HTH,

    Regards,

    Tris.
     
    ToRA, Jan 2, 2006
    #17
  18. Re: (Real) Primitive Ruby Generics support

    Hal Fulton ha scritto:

    >> Already knew about dynamic <> static and strong <> weak.
    >>
    >> But nominal <> structural is what I was looking for in this case. Thanks!
    >>

    >
    > I have never heard these terms used this way, but it is interesting.
    >
    > Are those in common use by some group of people somewhere?


    all the people that actually understand typing issues, it seem :)
    And with this I mean: lambda-the-ultimate.org and the people working
    with languages such as ML dialects, haskell and in general functional
    stuff with static checks. At least it seem to me.
     
    gabriele renzi, Jan 3, 2006
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. senthil
    Replies:
    5
    Views:
    1,439
    senthil
    Jan 24, 2004
  2. Juergen Berchtel
    Replies:
    1
    Views:
    6,095
    John C. Bollinger
    May 20, 2005
  3. Replies:
    7
    Views:
    624
    Victor Bazarov
    May 9, 2005
  4. Daniel Pitts
    Replies:
    7
    Views:
    518
  5. Soul
    Replies:
    0
    Views:
    550
Loading...

Share This Page