Anyone playing with higher order messaging in ruby?

Discussion in 'Ruby' started by Christoffer Lernö, Mar 14, 2007.

  1. For example, something that I often want to do is:

    array.each { |entry| entry.do_something(1, "a") }

    If you know you're doing things like this a lot, there is an obvious
    shortcut:

    class Array

    class Forwarder
    def initialize(array)
    @array = array
    end
    def method_missing(symbol, *args)
    @array.each { |entry| entry.__send__(symbol, *args) }
    end
    end

    def each_do
    Forwarder.new(self)
    end

    end

    Now you can do:

    array.each_do.do_something(1, "a")


    In a more generalized case, you want to use a block to act as a class.

    module Trampolines
    class Trampoline
    def initialize(block)
    @block = block
    end
    def method_missing(symbol, *args, &block)
    args << block if block
    @block.call(symbol, *args)
    end
    end
    end

    def trampoline(&block)
    raise "Missing block" unless block
    Trampolines::Trampoline.new(block)
    end


    Here we could define


    class Array
    def each_do2
    trampoline { |symbol, *args| each { |o| o.__send__(symbol,
    *args) } }
    end
    end

    Which would work the same way as the previous code.


    But you could also do things like

    def wait(time)
    trampoline do |method, *args|
    # queue_event executes the block after time seconds
    queue_event(time) { self.__send__(method, *args) }
    end
    end

    And write code like:

    wait(5).shutdown("Shutdown in seconds")
    wait(10).shutdown("Shutdown in 5 seconds")
    wait(15).shutdown_now

    Instead of wrapping it in blocks.


    Other people must have played around with this.

    I'd like to learn more about using these methods, so are there any
    links and sites people could share with me?


    /Christoffer
    Christoffer Lernö, Mar 14, 2007
    #1
    1. Advertising

  2. On Mar 14, 2007, at 20:04 , Christoffer Lern=F6 wrote:

    > In a more generalized case, you want to use a block to act as a class.
    >
    > module Trampolines
    > class Trampoline
    > def initialize(block)
    > @block =3D block
    > end
    > def method_missing(symbol, *args, &block)
    > args << block if block
    > @block.call(symbol, *args)
    > end
    > end
    > end
    >
    > def trampoline(&block)
    > raise "Missing block" unless block
    > Trampolines::Trampoline.new(block)
    > end


    This code adds methods to all enumerables.

    module Enumerable
    %w(each collect select reject).each do |method|
    class_eval "def #{method}_do; trampoline { |m, b, *a| #{method} =20
    { |o| o.__send__(m, *a, &b) } }; end"
    end
    end

    For example

    ["a", "b", "c"].reject_do[/a/] # =3D> ["b", "c"]
    ["a", "b", "c"].collect_do.capitalize #=3D> ["A", "B", "C"]

    =20
    =20=
    Christoffer Lernö, Mar 14, 2007
    #2
    1. Advertising

  3. On 14 Mar 2007, at 19:57, Jason Roelofs wrote:

    > I haven't personally messed with this kind of stuff but code like
    > this just
    > makes me love Ruby even more. These types of, well DSL is really
    > the best
    > way to describe it, in such little code, makes Ruby such a blast to
    > program
    > in, and it's readable too!


    I think I must be getting too old, or I'm being a spring time Scrouge...

    While it's neat, and it's cool Ruby can do that stuff, I've got to
    ask "Why?".

    I've come across this used in DSLs, but I generally think, "I'm sure
    you're going to get in to trouble down the line. Why don't you just
    use the regular syntax?"

    I don't really see that it makes for an especially more concise
    program, and really, it just seems to be introducing a different
    syntax that's kind of crow bared in as an overloading of the current
    syntax and semantics: as such, it doesn't seem to act in an expected
    way. Frankly, it all seems reminiscent of some of the c++ template
    techniques which, while terribly clever, don't generally seem to
    actually achieve a lot that can't be done more simply in other ways;
    and introduce so much complexity that even a seriously good coder's
    complexity budget is nearly all used up with a very small problem.

    No, you're right, I am getting old ;-)
    Benjohn Barnes, Mar 14, 2007
    #3
  4. On Mar 14, 2007, at 23:48 , Benjohn Barnes wrote:

    >
    > On 14 Mar 2007, at 19:57, Jason Roelofs wrote:
    >
    >> I haven't personally messed with this kind of stuff but code like
    >> this just
    >> makes me love Ruby even more. These types of, well DSL is really
    >> the best
    >> way to describe it, in such little code, makes Ruby such a blast
    >> to program
    >> in, and it's readable too!

    >
    > I think I must be getting too old, or I'm being a spring time
    > Scrouge...
    >
    > While it's neat, and it's cool Ruby can do that stuff, I've got to
    > ask "Why?".
    >
    > I've come across this used in DSLs, but I generally think, "I'm
    > sure you're going to get in to trouble down the line. Why don't you
    > just use the regular syntax?"
    >
    > I don't really see that it makes for an especially more concise
    > program, and really, it just seems to be introducing a different
    > syntax that's kind of crow bared in as an overloading of the
    > current syntax and semantics: as such, it doesn't seem to act in an
    > expected way. Frankly, it all seems reminiscent of some of the c++
    > template techniques which, while terribly clever, don't generally
    > seem to actually achieve a lot that can't be done more simply in
    > other ways; and introduce so much complexity that even a seriously
    > good coder's complexity budget is nearly all used up with a very
    > small problem.
    >
    > No, you're right, I am getting old ;-)


    For code like this:

    subscribers.send_message:)chat, @current_user, chat_text)

    Instead of

    subscribers.each { |s| s.add_to_queue:)send_message, [:chat,
    @current_user, chat_text]) }

    It is also useful for transactions, where you can define a trampoline
    like this (writing this code in my mail program, it probably has bugs):

    def transaction
    queue = []
    $exec = trampoline { |method, *args| @queue << [method, args] }
    yield
    queue.each do |method, args|
    __send__(method, *args)
    end
    end

    def exec
    $exec
    end


    Now you write code like this

    transaction do
    do_something
    exec.start_system1
    do_something_else
    raise "Some error" if (something_failed)
    exec.start_system2
    end

    If the transaction works, both start_system1 and start_system2 is
    called. Otherwise neither happens.

    It helps making the code straightforward, especially if the
    start_system calls are IO or similar that is difficult to reverse.


    /Christoffer
    Christoffer Lernö, Mar 15, 2007
    #4
  5. On 3/14/07, Benjohn Barnes <> wrote:
    >
    > On 14 Mar 2007, at 19:57, Jason Roelofs wrote:
    >
    > > I haven't personally messed with this kind of stuff but code like
    > > this just
    > > makes me love Ruby even more. These types of, well DSL is really
    > > the best
    > > way to describe it, in such little code, makes Ruby such a blast to
    > > program
    > > in, and it's readable too!

    >
    > I think I must be getting too old, or I'm being a spring time Scrouge...
    >
    > While it's neat, and it's cool Ruby can do that stuff, I've got to
    > ask "Why?".
    >
    > I've come across this used in DSLs, but I generally think, "I'm sure
    > you're going to get in to trouble down the line. Why don't you just
    > use the regular syntax?"


    Yes it's powerful, and it's useful, but it needs to be done with
    thought and care. We used to call similar things like this in
    Smalltalk "stupid Smalltalk tricks." It's like any other tool, it can
    be used for good or evil, it's the workman who determines this.

    I just blogged about some of the ramifications of this this morning.
    (see my signature for the URL of my blog).

    Rails makes use of this and similar techniques a lot. Two examples,
    which I've recently encountered reading the rails code:

    1) Named routes. Normally you set up routes which represent mappings
    between urls and actions and their parameters with the connect method
    of an internal class called ActionController::Routing::RouteSet in
    code like this, in your config/routs.rb file:

    ActionController::Routing::Routes.draw do | map |
    map.connect ':controller/xyz/:arg1/:arg2'
    end

    Routes are used both to map an incoming url to an controller, action
    and parameters, and also to map the other way to generate a url.
    Routes defined above are anonymous, when asked to generate a url it
    picks which route to use itself. But you can also name routes so that
    you can explicitly give a particular route to use when generating a
    url. Let's say you want to
    name that route above xyz. To do this you use the method xyz instead
    of connect:

    map.xyz 'controller/xyz/:arg1/:arg1'

    which does the same thing as above but also defines a helper method
    called xyz_url.

    Of course the mechanism used to do this is to catch :xyz with
    method_missing and turn it into a call to named_route passing the name
    :)xyz) and any other parameters, which in turn invokes connect and
    then creates the helper.

    2) mime content negotiation

    An action might be able to respond to a request with more than one
    mime-type. An HTTP request can give a prioritized lists of mime-types
    which the client will accept. The way to handle this negotiation in
    an action is to use the respond_to method you might have code in an
    action like:

    respond_to do |wants|
    wants.html { redirect_to(person_list_url) }
    wants.js
    wants.xml { render :xml => @person.to_xml:)include => @company) }
    end

    What this code says is something like:
    if the requester wants html redirect to the person_list_url
    if the requester wants java script perform the normal rendering
    for javascript (such as look for an rjs template with the right name
    and render that)
    etc.

    It's kind of like a case statement, except what really happens also
    depends on which of those alternatives came first in the requests list
    of acceptable types.

    Now what happens under the covers is that the respond_to method
    creates an ActionController::MimeResponds::Responder object which
    becomes map in the code above. Then it yields to the block. The html
    method adds html to the list of available mime types, along with the
    block, or as in the case of the invocation of the js method where no
    block is given, a default block. Then once the block given to
    respond_to returns, the Responder is asked to respond by executing the
    first block found using the list of requested mime-types.

    In Rails 1.2, ActionController::MimeResponds:Responder uses
    method__missing to support new mime types not 'baked in' to Rails.

    These are just two examples from Rails, there are many more.

    It's good to read such carefully crafted code and understand the
    techniques and the possibilities, but I'd caution about getting too
    carried away with such things before you are ready, and most folks
    thing they are ready before they really are. <G>

    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
    Rick DeNatale, Mar 15, 2007
    #5
  6. Christoffer Lernö

    Robert Dober Guest

    --------------------- 8< ---------------------

    module Enumerable
    class MapProxy
    def initialize obj
    @obj = obj
    end #def initialize obj
    def method_missing name, *args, &blk
    @obj.map do
    | ele |
    ele.send name, *args, &blk
    end
    end #def method_missing name, *args, &blk
    end #class MapProxy

    alias_method :aliased_map, :map
    def map *args, &blk
    return MapProxy.new( self ) if args.length.zero? && blk.nil?
    aliased_map *args, &blk
    end #def map *args, &blk
    end #module Enumerable

    ---------------- 8< --------------------

    This is from a thread of 2006-09-27 posted the 28th, looks familiar
    it was about "for or against the magic dot notation" but the
    functionality is the same :)

    the French say: "Les grands esprits se resemblent", but my modesty
    forbids any translations ;)

    Cheers
    Robert
    Robert Dober, Mar 15, 2007
    #6
  7. On Thu, Mar 15, 2007 at 04:04:01AM +0900, Christoffer Lern? wrote:
    > For example, something that I often want to do is:
    >
    > array.each { |entry| entry.do_something(1, "a") }


    If do_something doesn't take any arguments then there's the hack which
    allows

    array.each(&:do_something)

    See http://pragdave.pragprog.com/pragdave/2005/11/symbolto_proc.html

    > If you know you're doing things like this a lot, there is an obvious
    > shortcut:
    >
    > class Array
    >
    > class Forwarder
    > def initialize(array)
    > @array = array
    > end
    > def method_missing(symbol, *args)
    > @array.each { |entry| entry.__send__(symbol, *args) }
    > end
    > end
    >
    > def each_do
    > Forwarder.new(self)
    > end
    >
    > end
    >
    > Now you can do:
    >
    > array.each_do.do_something(1, "a")


    or just:

    module Enumberable
    def each_do(meth, *args, &blk)
    each { |item| item.send(meth, *args, &blk) }
    end
    end

    array.each_do:)do_something, 1, "a")

    which has the advantage that do_something can take a block too, if you wish.

    B.
    Brian Candler, Mar 16, 2007
    #7
  8. On 15.03.2007 21:28, Rick DeNatale wrote:
    > 2) mime content negotiation
    >
    > An action might be able to respond to a request with more than one
    > mime-type. An HTTP request can give a prioritized lists of mime-types
    > which the client will accept. The way to handle this negotiation in
    > an action is to use the respond_to method you might have code in an
    > action like:
    >
    > respond_to do |wants|
    > wants.html { redirect_to(person_list_url) }
    > wants.js
    > wants.xml { render :xml => @person.to_xml:)include =>
    > @company) }
    > end
    >
    > What this code says is something like:
    > if the requester wants html redirect to the person_list_url
    > if the requester wants java script perform the normal rendering
    > for javascript (such as look for an rjs template with the right name
    > and render that)
    > etc.
    >
    > It's kind of like a case statement, except what really happens also
    > depends on which of those alternatives came first in the requests list
    > of acceptable types.


    That is no difference to case statements: with those, order matters as well:

    >> x="foo"

    => "foo"
    >> case x
    >> when /fo/; puts 1
    >> when /oo/; puts 2
    >> else puts 0
    >> end

    1
    => nil
    >> case x
    >> when /oo/; puts 2
    >> when /fo/; puts 1
    >> else puts 0
    >> end

    2
    => nil

    I think the major difference (apart from syntactical aspects) is the
    execution time. Of course this could also be mimicked with a case
    statement by returning a Proc but the Rails version looks much more elegant.

    > It's good to read such carefully crafted code and understand the
    > techniques and the possibilities, but I'd caution about getting too
    > carried away with such things before you are ready, and most folks
    > thing they are ready before they really are. <G>


    Agreed. ;-)

    Kind regards

    robert
    Robert Klemme, Mar 16, 2007
    #8
  9. On Mar 16, 2007, at 07:25 , Brian Candler wrote:

    >> If you know you're doing things like this a lot, there is an obvious
    >> shortcut:
    >>
    >> class Array
    >>
    >> class Forwarder
    >> def initialize(array)
    >> @array = array
    >> end
    >> def method_missing(symbol, *args)
    >> @array.each { |entry| entry.__send__(symbol, *args) }
    >> end
    >> end
    >>
    >> def each_do
    >> Forwarder.new(self)
    >> end
    >>
    >> end
    >>
    >> Now you can do:
    >>
    >> array.each_do.do_something(1, "a")

    >
    > or just:
    >
    > module Enumberable
    > def each_do(meth, *args, &blk)
    > each { |item| item.send(meth, *args, &blk) }
    > end
    > end
    >
    > array.each_do:)do_something, 1, "a")
    >
    > which has the advantage that do_something can take a block too, if
    > you wish.


    Well, actually you might want to pass around the result of each_do to
    something else, this is why I believe that in most cases the former
    version is preferable.

    Consider a chat server where @clients = [connection1, connection2...]

    assuming each connection has a method like "broadcast_chat", the code
    looks like this:

    @clients.each_do.broadcast_chat(incoming_chat)

    I like it because it feels clear what is happening and that this is
    the same as

    @clients.each { |c| c.broadcast_chat(incoming_chat) }

    Here

    @cliente.each_do:)broadcast_chat, incoming_chat)

    is not as obvious when it comes to detemining what is the action and
    what is the data.
    Christoffer Lernö, Mar 16, 2007
    #9
  10. On Mar 14, 2007, at 23:48 , Benjohn Barnes wrote:

    > On 14 Mar 2007, at 19:57, Jason Roelofs wrote:
    >
    >> I haven't personally messed with this kind of stuff but code like
    >> this just
    >> makes me love Ruby even more. These types of, well DSL is really
    >> the best
    >> way to describe it, in such little code, makes Ruby such a blast
    >> to program
    >> in, and it's readable too!

    >
    > I think I must be getting too old, or I'm being a spring time
    > Scrouge...
    >
    > While it's neat, and it's cool Ruby can do that stuff, I've got to
    > ask "Why?".


    And another example:

    # A chat server where @clients = [connection1, connection2...]
    # message = "Hello"
    # sender = "Bob"

    # With normal each:
    packet = BroadcastChatPacket.new("#{sender} says: #{message}")
    @clients.each { |c| c.broadcast(packet) }

    # With each_do:
    @clients.each_do.broadcast(BroadcastChatPacket.new("#{sender} says: #
    {message}"))

    Eliminating the need for the temporary variable.

    /Christoffer
    Christoffer Lernö, Mar 16, 2007
    #10
  11. Christoffer Lernö

    Robert Dober Guest

    On 3/16/07, Christoffer Lern=F6 <> wrote:
    > On Mar 14, 2007, at 23:48 , Benjohn Barnes wrote:
    >
    > > On 14 Mar 2007, at 19:57, Jason Roelofs wrote:
    > >
    > >> I haven't personally messed with this kind of stuff but code like
    > >> this just
    > >> makes me love Ruby even more. These types of, well DSL is really
    > >> the best
    > >> way to describe it, in such little code, makes Ruby such a blast
    > >> to program
    > >> in, and it's readable too!

    > >
    > > I think I must be getting too old, or I'm being a spring time
    > > Scrouge...
    > >
    > > While it's neat, and it's cool Ruby can do that stuff, I've got to
    > > ask "Why?".

    >
    > And another example:
    >
    > # A chat server where @clients =3D [connection1, connection2...]
    > # message =3D "Hello"
    > # sender =3D "Bob"
    >
    > # With normal each:
    > packet =3D BroadcastChatPacket.new("#{sender} says: #{message}")
    > @clients.each { |c| c.broadcast(packet) }
    >
    > # With each_do:
    > @clients.each_do.broadcast(BroadcastChatPacket.new("#{sender} says: #
    > {message}"))
    >
    > Eliminating the need for the temporary variable.
    >

    Do I understand correctly when I remark that a new BroadcastChatPacket
    instance is created or each iterator call in #each_do.broadcast,

    If not than it is just the same as
    @clients.each{ |c| c.broadcast BCP.new... }

    in this context I do not really see the practical interest though I
    *obviously* like that style as I have shown above.

    Well 6 months is a long time, but no I still like this magic dot notation.

    Cheers
    Robert
    > /Christoffer
    >
    >



    --=20
    You see things; and you say Why?
    But I dream things that never were; and I say Why not?
    -- George Bernard Shaw
    Robert Dober, Mar 16, 2007
    #11
  12. On Mar 16, 2007, at 13:21 , Robert Dober wrote:

    > On 3/16/07, Christoffer Lern=F6 <> wrote:
    >> And another example:
    >>
    >> # A chat server where @clients =3D [connection1, connection2...]
    >> # message =3D "Hello"
    >> # sender =3D "Bob"
    >>
    >> # With normal each:
    >> packet =3D BroadcastChatPacket.new("#{sender} says: #{message}")
    >> @clients.each { |c| c.broadcast(packet) }
    >>
    >> # With each_do:
    >> @clients.each_do.broadcast(BroadcastChatPacket.new("#{sender} says: #
    >> {message}"))
    >>
    >> Eliminating the need for the temporary variable.
    >>

    > Do I understand correctly when I remark that a new BroadcastChatPacket
    > instance is created or each iterator call in #each_do.broadcast,


    No, each_do will only create BroadcastChatPacket once.

    /Christoffer
    Christoffer Lernö, Mar 16, 2007
    #12
  13. Christoffer Lernö wrote:
    > On Mar 14, 2007, at 20:04 , Christoffer Lern� wrote:
    >
    >> end
    >> end
    >> end
    >>
    >> def trampoline(&block)
    >> raise "Missing block" unless block
    >> Trampolines::Trampoline.new(block)
    >> end

    >
    > This code adds methods to all enumerables.
    >
    > module Enumerable
    > %w(each collect select reject).each do |method|
    > class_eval "def #{method}_do; trampoline { |m, b, *a| #{method}
    > { |o| o.__send__(m, *a, &b) } }; end"
    > end
    > end


    Looks to me that it's easier to extend the Forwarder a bit and implement
    this like this:

    class Forwarder
    def initialize(obj, method)
    @obj = obj
    @method = method
    end
    def method_missing(symbol, *args)
    @obj.__send__( @method) { |entry| entry.__send__(symbol, *args) }
    end
    end

    module Enumerable
    %w(each collect select reject).each do |method|
    class_eval "def #{method}_do; Forwarder.new(self, :#{method}) end"
    end
    end


    it's a shame the builtins do not work like this already. And while it's
    possible to overwrite the "collect", "select" and "reject" in
    Enumerable, to overwrite the "each" you'd (AFAIK) have to touch all the
    individual classes.

    I should not have to name something I only use once:

    list.each { |x| x.whatever() }

    Jenda

    --
    Posted via http://www.ruby-forum.com/.
    Jenda Krynicky, Mar 16, 2007
    #13
  14. Christoffer Lernö

    Gary Wright Guest

    On Mar 16, 2007, at 1:32 PM, Jenda Krynicky wrote:
    > it's a shame the builtins do not work like this already. And while
    > it's
    > possible to overwrite the "collect", "select" and "reject" in
    > Enumerable, to overwrite the "each" you'd (AFAIK) have to touch all
    > the
    > individual classes.


    Somewhat related....

    In Ruby 1.9 iterating methods (I couldn't think of a better term) such
    as each, map, and so on return an Enumerator object if a block isn't
    provided. This makes it easier to add the magic dot behavior:

    class Enumerable::Enumerator
    def method_missing(*args, &block)
    each { |x| x.send(*args, &block ) }
    end
    end

    [1,-2,3,-4].map.abs # [1,2,3,4]
    [1,-2,3,-4].map.abs.map.succ # [2,3,4,5]
    %w{mon tue wed}.map.capitalize # ["Mon", "Tue", "Wed"]`

    This works because Enumerable::Enumerator#each returns the original
    collection (instead of the iterator) when a block is provided.

    [1,2].each.class # Enumerator
    [1,2].each.each.class # Enumerator
    [1,2].each.each {}.class # Array


    Gary Wright
    Gary Wright, Mar 16, 2007
    #14
  15. Christoffer Lernö

    Robert Dober Guest

    On 3/16/07, Christoffer Lern=F6 <> wrote:
    >
    > On Mar 16, 2007, at 13:21 , Robert Dober wrote:
    >
    > > On 3/16/07, Christoffer Lern=F6 <> wrote:
    > >> And another example:
    > >>
    > >> # A chat server where @clients =3D [connection1, connection2...]
    > >> # message =3D "Hello"
    > >> # sender =3D "Bob"
    > >>
    > >> # With normal each:
    > >> packet =3D BroadcastChatPacket.new("#{sender} says: #{message}")
    > >> @clients.each { |c| c.broadcast(packet) }
    > >>
    > >> # With each_do:
    > >> @clients.each_do.broadcast(BroadcastChatPacket.new("#{sender} says: #
    > >> {message}"))
    > >>
    > >> Eliminating the need for the temporary variable.
    > >>

    > > Do I understand correctly when I remark that a new BroadcastChatPacket
    > > instance is created or each iterator call in #each_do.broadcast,

    >
    > No, each_do will only create BroadcastChatPacket once.
    >
    > /Christoffer
    >
    >

    Sure got confused it is evaluated in method_missing only once, good,
    thx for clarifying, I see the practical benefit now too.

    Robert


    --=20
    You see things; and you say Why?
    But I dream things that never were; and I say Why not?
    -- George Bernard Shaw
    Robert Dober, Mar 16, 2007
    #15
  16. On 3/14/07, Christoffer Lern=F6 <> wrote:
    > For example, something that I often want to do is:
    >
    > array.each { |entry| entry.do_something(1, "a") }
    >
    > [...]
    >
    > Other people must have played around with this.
    >
    > I'd like to learn more about using these methods, so are there any
    > links and sites people could share with me?
    >
    >
    > /Christoffer
    >


    I wrote this some time ago:

    class Message
    def initialize(message, *args)
    @message, @args =3D message, args
    end

    def call(x, *args)
    x.send @message, *(@args + args)
    end

    def to_proc
    lambda { |*args| call(*args) }
    end
    end

    Now you can do:

    puts [*0..100].select(&Message.new:)>, 50)).inspect
    puts [*0..100].inject(&Message.new:)+))
    puts %w(Once upon a time).map(&Message.new:)upcase)).inspect
    puts Message.new:)index, /[aeiou]/, -3).call("hello")
    puts %w(1 2 3 4 5).map(&Message.new:)to_i)).map(&Message.new:)class)).ins=
    pect

    The &Message.new syntax is a bit verbose, so you could alias it:

    def _(msg, *args)
    Message.new(msg, *args)
    end

    And then it runs smooth:

    puts [*0..100].select(&_:)>, 50)).inspect

    I don't know if this helps. It does do away with the need for
    method_missing or changing core classes or stuff like that. I don't
    know how useful it is, because I've never used it for anything
    serious. If it was to be really useful, it should've been incorporated
    into the language and standard libraries.

    --=20
    - Simen
    Simen Edvardsen, Mar 16, 2007
    #16
  17. On 3/15/07, Robert Dober <> wrote:

    > the French say: "Les grands esprits se resemblent", but my modesty
    > forbids any translations ;)


    Usually rendered in English as "Great minds think alike."

    Then again I had a good friend from England some years ago who never
    failed to follow that phrase with "or fools fail to differ!" <G>

    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
    Rick DeNatale, Mar 16, 2007
    #17
  18. Christoffer Lernö

    Robert Dober Guest

    On 3/16/07, Rick DeNatale <> wrote:
    > On 3/15/07, Robert Dober <> wrote:
    >
    > > the French say: "Les grands esprits se resemblent", but my modesty
    > > forbids any translations ;)

    >
    > Usually rendered in English as "Great minds think alike."
    >
    > Then again I had a good friend from England some years ago who never
    > failed to follow that phrase with "or fools fail to differ!" <G>

    I can still learn from your modesty :))
    But sigh Rick you see nobody cares for my code I will have to sell it
    to Microsoft ;)
    And as an eventual side remark - after the defeat at Twickenham ARGHHH
    - it is good to know that Englishmen can have friends too. <ducking>
    no <digging a hole>
    but what do I fear? they have the best humor of the world, really,
    like e.g. Monthy Ruby's

    ... ok I guess I need some sleep now.

    Robert
    >
    > --
    > Rick DeNatale
    >
    > My blog on Ruby
    > http://talklikeaduck.denhaven2.com/
    >
    >



    --
    You see things; and you say Why?
    But I dream things that never were; and I say Why not?
    -- George Bernard Shaw
    Robert Dober, Mar 16, 2007
    #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. Jonathan Bartlett

    Higher-Order Programming in C

    Jonathan Bartlett, Mar 31, 2005, in forum: C Programming
    Replies:
    4
    Views:
    289
    Jonathan Bartlett
    Apr 4, 2005
  2. Mark Fink
    Replies:
    3
    Views:
    267
    Arnaud Delobelle
    Dec 22, 2010
  3. Nickolay Kolev

    Higher Order Functions

    Nickolay Kolev, Jul 31, 2005, in forum: Ruby
    Replies:
    5
    Views:
    129
    Nickolay Kolev
    Aug 8, 2005
  4. Victor \Zverok\ Shepelev

    Higher-order messaging in Ruby

    Victor \Zverok\ Shepelev, Oct 11, 2006, in forum: Ruby
    Replies:
    0
    Views:
    108
    Victor \Zverok\ Shepelev
    Oct 11, 2006
  5. zslevi

    Higher order ruby

    zslevi, Jan 14, 2009, in forum: Ruby
    Replies:
    12
    Views:
    281
    Brian Candler
    Jan 19, 2009
Loading...

Share This Page