Forum: Ruby New magical version of Symbol.to_proc

Posted by Dr Nic (nicwilliams)
on 2006-09-28 15:16
[Posted at 
http://drnicwilliams.com/2006/09/28/new-magical-version-of-symbolto_proc/]

Before the magic, letâ??s go through a Beginnerâ??s Guide to Mapping, then 
Advanced Guide to Symbol.to_proc, and THEN, the magical version. Its 
worth it. Its sexy, nifty AND magical all at once.

* Beginnerâ??s Guide to Mapping

>> list = [â??1â?²,  â??2â?², â??3â?²]
=> ["1â?³, "2â?³, "3â?³]
>> list.map {|item| item.to_i}
=> [1, 2, 3]

Here we're invoking to_i on each item of the list and returning the 
result into a new list. That's map/collect for you.

* Advanced Guide to Symbol.to_proc

After doing that a few times, you start wishing there was simpler 
syntax. Enter: Symbol.to_proc

>> list.map &:to_i
=> [1, 2, 3]

It works. Just enjoy it. (see article for links on why it works)

* Magical version of Symbol.to_proc

Quite frankly, thatâ??s still a lot of syntax. Plus, I normally forget to 
added parentheses around the &:to_i, and then latter I want to invoke 
another method on the result, so I need to add the parentheses which is 
a painâ?¦ anyway. I thought of something niftier and dare I say, more 
magical.

How about this syntax:

>> list.to_is
=> [1, 2, 3]

By passing the plural version of a method, the array automagically 
performs the above mapping on itself using the singular version of the 
method.

Sexy! And here's more examples:

>> (1..10).to_a.to_ss
=> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
>> (1..10).to_a.days
=> [86400, 172800, 259200, 345600, 432000, 518400, 604800, 691200, 
777600, 864000]
>> [2,'two', :two].classes
=> [Fixnum, String, Symbol]
>> [2,'two', :two].classes.names
=> ["Fixnum", "String", "Symbol"]
>> [2,'two', :two].classes.names.lengths
=> [6, 6, 6]

So much happy syntax in one place!

I've got the library that gives you this syntax here: 
http://drnicwilliams.com/2006/09/28/new-magical-version-of-symbolto_proc/ 
(at the bottom)

Nic
Posted by Dr Nic (nicwilliams)
on 2006-09-28 15:18
Note: the Symbol.to_proc is currently in the Rails libraries 
(active_support gem) but will be added into Ruby 1.9 one day in the 
future.
Posted by unknown (Guest)
on 2006-09-28 15:47
(Received via mailing list)
Hi --

On Thu, 28 Sep 2006, Dr Nic wrote:

>>> list.map &:to_i
> => [1, 2, 3]
>
> It works. Just enjoy it. (see article for links on why it works)

It's not my favorite construct; it's a bit ugly and terse in a bad
way.  You mentioned elsewhere that this is going to be in 1.9, though
I remember Matz rejecting an RCR for:

   list.map(:to_i)

and &:to_i seems worse :-)

> => [6, 6, 6]
>
> So much happy syntax in one place!

Actually the reason this is kind of cool is not the syntax but the
semantics.  It's much more expressive than any number of &:->()...
things that have been proposed -- and looks better.  (There may be
some connection there too.)

I wonder, though, whether it would be too easy for it to trample on
other method names.  I guess that's true of anything -- you'd just
have to make sure you didn't have two conceptions of some plural
thing.


David
Posted by Dr Nic (nicwilliams)
on 2006-09-28 16:00
> Actually the reason this is kind of cool is not the syntax but the
> semantics.  It's much more expressive than any number of &:->()...
> things that have been proposed -- and looks better.  (There may be
> some connection there too.)

Agreed - its very nice semantically too. It has much more meaning than 
.map(&:method_name) I think.

> I wonder, though, whether it would be too easy for it to trample on
> other method names.  I guess that's true of anything -- you'd just
> have to make sure you didn't have two conceptions of some plural
> thing.

The method_missing code will perform "super" first to ensure that any 
per-existing dynamic methods on the Array are evaluated first. Then it 
attempts to call the method on the collection items. If they return a 
NoMethodError then the original error object is returned. I think that's 
cleanest.

But yes, its a buyer-beware situation. So - "Smart Buyers Only"!
Posted by Robert Dober (Guest)
on 2006-09-28 16:07
(Received via mailing list)
<snip>
> > => ["Fixnum", "String", "Symbol"]
> I wonder, though, whether it would be too easy for it to trample on
> other method names.  I guess that's true of anything -- you'd just
> have to make sure you didn't have two conceptions of some plural
> thing.


I agree, *cool* and *somehow dangerous*, I would very conservatively 
propose
a proxy method, similiar in spirit to BDD's rspec#is

%w{the meaning of 42}.map.length => [3, too_long_to_count, 2, 2]

or maybe not overload #map without params for that purpose?

Just an idea of course ;)

BTW Using English semantics for Ruby semantics does seem
+ interesting
+ avantguarde
- intolerant
- too dangerous
- too early

it is great people doing this, I would hate having it in the core 
though.
Robert
--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein
Posted by Robert Dober (Guest)
on 2006-09-28 16:08
(Received via mailing list)
Arrrrghh
I was quoting David; who was quoting Nic, sorry for my mistake
Robert
Posted by unknown (Guest)
on 2006-09-28 16:16
(Received via mailing list)
Hi --

On Thu, 28 Sep 2006, Robert Dober wrote:

>> >>> [2,'two', :two].classes.names
>> 
>
> or maybe not overload #map without params for that purpose?

I personally dislike "magic dot" stuff like that.  True, it's not
really magic, since map can return some kind of enumerator that knows
about the array and is ready to do something to it.  But it still has
the look and feel of a kind of secret system for communicating what's
wanted, rather than something that really makes sense when read left
to right.

That's why I prefer Dr. Nic's plurals thing, though it definitely has
the disadvantage of entering into murky territority in terms of method
naming.


David
Posted by Dr Nic (nicwilliams)
on 2006-09-28 16:24
Robert Dober wrote:
> I agree, *cool* and *somehow dangerous*, I would very conservatively 
> propose
> a proxy method, similiar in spirit to BDD's rspec#is
> 
> %w{the meaning of 42}.map.length => [3, too_long_to_count, 2, 2]
> 
> or maybe not overload #map without params for that purpose?

I like this idea too - something that allows you to pick which iterator 
method to use (that is: select, each, map)

Implementable syntax might be:

%w{the meaning of 42}.map_length

Where the Array.method_missing could parse it as:

          re = /(map|collect|select|each)_([\\w\\_]+)/
          if (match = method.to_s.match(re))
            puts match.inspect
            iterator, callmethod = match[1..2]
            puts [iterator, callmethod]
            return self.send(iterator) {|item| item.send callmethod}
          end

Cute. I've added it to the library.
Posted by Dr Nic (nicwilliams)
on 2006-09-28 16:30
Ahh. Removed trace and fixed the regular expression:

          re = /(map|collect|select|each|reject)_([\\w\\_]+\\??)/
          if (match = method.to_s.match(re))
            iterator, callmethod = match[1..2]
            return self.send(iterator) {|item| item.send callmethod}
          end

Now supports reject

For example:

>> list = [nil, 1, 2, nil, 4]
=> [nil, 1, 2, nil, 4]
>> list.reject_nil?
=> [1, 2, 4]

Cool.
Posted by Simen Edvardsen (Guest)
on 2006-09-28 16:54
(Received via mailing list)
On 9/28/06, dblack@wobblini.net <dblack@wobblini.net> wrote:
> >> > => [86400, 172800, 259200, 345600, 432000, 518400, 604800, 691200,
> >> Actually the reason this is kind of cool is not the syntax but the
> > I agree, *cool* and *somehow dangerous*, I would very conservatively propose
> wanted, rather than something that really makes sense when read left
> to right.
>
> That's why I prefer Dr. Nic's plurals thing, though it definitely has
> the disadvantage of entering into murky territority in terms of method
> naming.
>

I like the idea of being able to treat messages like some kind of
object and manipulating stuff with them somewhat like this, so just
yesterday I made a mutated version of Symbol#to_proc, the "first
class" message:

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

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

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

if $0 == __FILE__
  # Example
  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)).inspect
end

$ ruby message.rb
[51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
5050
["ONCE", "UPON", "A", "TIME"]
4
[Fixnum, Fixnum, Fixnum, Fixnum, Fixnum]

The syntax isn't as terse, but it does have the advantage of not
interfering with existing methods (and you could just write a kernel
method as a shortcut if you like).
Posted by unknown (Guest)
on 2006-09-28 17:02
(Received via mailing list)
Hi --

On Thu, 28 Sep 2006, Dr Nic wrote:

>> have to make sure you didn't have two conceptions of some plural
>> thing.
>
> The method_missing code will perform "super" first to ensure that any
> per-existing dynamic methods on the Array are evaluated first. Then it
> attempts to call the method on the collection items. If they return a
> NoMethodError then the original error object is returned. I think that's
> cleanest.

I'm not sure that's working the way you think it is.  When you call
super in method_missing, it's calling Object#method_missing, which
really just lives to be overridden.  (Or is there some other layer
added in there somewhere?)  Also, if a dynamic method of the same name
has been defined on the array, then method_missing won't get called in
the first place :-)


David
Posted by Trans (Guest)
on 2006-09-28 17:08
(Received via mailing list)
Simen Edvardsen wrote:

> The syntax isn't as terse, but it does have the advantage of not
> interfering with existing methods (and you could just write a kernel
> method as a shortcut if you like).

Which would look like:

 if $0 == __FILE__
   # Example
   puts [*0..100].select(&message(:>, 50)).inspect
   puts [*0..100].inject(&message(:+))
   puts %w(Once upon a time).map(&message(:upcase)).inspect
   puts message(:index, /[aeiou]/, -3).call("hello")
   puts %w(1 2 3 4
5).map(&message(:to_i)).map(&message(:class)).inspect
 end

Not too shabby. But still I think terseness is the major advantage of
the Symbol#to_proc or the Magic Dot notation (like that name btw). OTOH
this might have other advantages.

T.
Posted by Robert Dober (Guest)
on 2006-09-28 17:48
(Received via mailing list)
I just could not resist, I am still amazed - after 20 years of Ruby
experience 8-], how easily things can be done, when did I say Ty the 
last
time Matz? Probably 20 years ago!!!

Ty Matz!!!

for those who like the notation,  very, very lazily tested, but 
amazingly
simple, probably rather slow etc....

--------------------- 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< --------------------
Cheers
Robert
--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein
Posted by Dr Nic (nicwilliams)
on 2006-09-28 18:23
unknown wrote:
> I'm not sure that's working the way you think it is.  When you call
> super in method_missing, it's calling Object#method_missing, which
> really just lives to be overridden.  (Or is there some other layer
> added in there somewhere?)  Also, if a dynamic method of the same name
> has been defined on the array, then method_missing won't get called in
> the first place :-)
> David

I've got it all bundled in a module, so it could be applied to another 
class that did have a meaningful method_missing, but for Array your 
point is valid.

By "dynamic method" I mean methods like find_by_<attr_name> in 
ActiveRecord - methods that are accepted by the method_missing but don't 
exist, rather than methods that are dynamically added to the class at 
some point. Sorry if that's the wrong name for them.

Having said all that, I don't think this is working for associations on 
ActiveRecords (which are just Arrays). I'm still investigating, but 
perhaps rails adds its own method_missing that is negating this one?

Nic
Posted by Hal Fulton (Guest)
on 2006-09-29 01:48
(Received via mailing list)
dblack@wobblini.net wrote:
> 
> I personally dislike "magic dot" stuff like that.  True, it's not
> really magic, since map can return some kind of enumerator that knows
> about the array and is ready to do something to it.  But it still has
> the look and feel of a kind of secret system for communicating what's
> wanted, rather than something that really makes sense when read left
> to right.
> 

Agreed. That is similar to the reason I hate the flip-flop
operator (syntax, not semantics) and even worse, junctions.


Hal
Posted by Trans (Guest)
on 2006-09-29 07:31
(Received via mailing list)
Hal Fulton wrote:
> Agreed. That is similar to the reason I hate the flip-flop
> operator (syntax, not semantics) and even worse, junctions.

I understand the general feeling you express. But is the reason really
just in the reading? I suspect there's more to it. What really lies at
the core of this uncomfortable feeling? I think maybe is has more to do
with comprehension of the general pattern. That is to ask, what is this
"magic dot" notation really? Maybe if we understood it better we would
not feel  so uncomfortable with it --or at the very least, maybe we
would truly understand why we rightly feel so.

In thinking about it, it seems to me that "magic-dotting" is simply
using a form of Object Adapter Design Pattern. (see
http://en.wikipedia.org/wiki/Adapter_pattern). I think there is a
tendency to over look this and think more in terms of retroactive
application of the subsequent method call. That means were focusing on
the ultimate action, and so it seems odd then b/c we are thinking of
'.x.y' in 'obj.x.y' as a single message when clearly we see there are
two messages actually being sent. That unsettles us. But as I suggest,
if we see it for what it really is --an adapter, then it makes perfect
sense, and doesn;t seem so magical after all (except that it still
offers some nicely terse syntax).

T.
Posted by Dr Nic (nicwilliams)
on 2006-09-29 08:38
Trans wrote:
> But as I suggest,
> if we see it for what it really is --an adapter, then it makes perfect
> sense, and doesn;t seem so magical after all (except that it still
> offers some nicely terse syntax).

I agree - it is very nice syntax.

Nic
Posted by Robert Dober (Guest)
on 2006-09-29 09:15
(Received via mailing list)
On 9/29/06, Dr Nic <drnicwilliams@gmail.com> wrote:
>
> --
> Posted via http://www.ruby-forum.com/.
>
> I'll have a look at T's link but it is a truely interesting discussion.
It is for the first time that I hear that very honorable members of the
community dislike this feature.
For me it was the most intreaging of Ruby at all (at the beginning)
I recall my old Python code

something.get_other().do_stuff().transform()

Terrible, it is only now that I realize that the concept of writing code
like this might be flawed, there are OTOH strong indications that it is 
not
so flawed too. E.g. lots of programing conventions asking for methods to
return objects.
Now, to complicate things even more, very often that object is "self",
personally I find the idea to return other objects, especially proxy 
objects
to self, very intriguing, the idea came to me when I looked at the BDD 
video
cast.

Cheers
Robert


--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein
Posted by Dr Nic (nicwilliams)
on 2006-09-29 09:27
Robert Dober wrote:
> On 9/29/06, Dr Nic <drnicwilliams@gmail.com> wrote:
>>
>> --
>> Posted via http://www.ruby-forum.com/.
>>
>> I'll have a look at T's link but it is a truely interesting discussion.

You're quoting techniques need some practise! I don't think I said that 
:)

> It is for the first time that I hear that very honorable members of the
> community dislike this feature.
> For me it was the most intreaging of Ruby at all (at the beginning)
> I recall my old Python code
> 
> something.get_other().do_stuff().transform()
> 
> Terrible, it is only now that I realize that the concept of writing code
> like this might be flawed, there are OTOH strong indications that it is 
> not
> so flawed too. E.g. lots of programing conventions asking for methods to
> return objects.
> Now, to complicate things even more, very often that object is "self",
> personally I find the idea to return other objects, especially proxy 
> objects
> to self, very intriguing, the idea came to me when I looked at the BDD 
> video cast.

In Smalltalk all methods return self unless they return something else, 
thus inferring that something.get_other().do_stuff().transform() (using 
Smalltalk syntax :) is common.

In JQuery - the javascript library - everything is centered around a 
"jquery" object which holds 1+ dom objects in it. All methods on the 
jQuery object should return that same set of objects (via the jQuery 
object container) so that you can chain method calls.

The idea of returning a proxy object (in the Magic Dot example of 
.map.lengths) was very nifty. It works the normal way AND works in the 
magical way.

The more and more examples I see and concoct myself like this the more I 
am happy to give up the core assumptions of "object oriented 
programming" etc, and adopt "happy syntax programming". Syntax that 
reads nicely and makes sense as to what it will do and what it will 
return.

Now if I could just get the code I originally wrote to work on 
ActiveRecord associations I'd be such a happy camper. I'm in love with 
that syntax.

Nic
Posted by Dr Nic (nicwilliams)
on 2006-09-29 09:28
Dr Nic wrote:
> You're quoting techniques need some practise! I don't think I said that 
> :)

My ability to spell needs some practise.

"Your" instead of "You're"... doh!
Posted by Robert Dober (Guest)
on 2006-09-29 11:23
(Received via mailing list)
On 9/29/06, Dr Nic <drnicwilliams@gmail.com> wrote:
> You're quoting techniques need some practise! I don't think I said that
> :)


Indeed, indeed,  I deleted the "Trans wrote", I am very bad at that, 
sorry
for the confusion

> > so flawed too. E.g. lots of programing conventions asking for methods to
>
> In JQuery - the javascript library - everything is centered around a
> "jquery" object which holds 1+ dom objects in it. All methods on the
> jQuery object should return that same set of objects (via the jQuery
> object container) so that you can chain method calls.
>
> The idea of returning a proxy object (in the Magic Dot example of
> .map.lengths) was very nifty. It works the normal way AND works in the
> magical way.


Thx ;) credits go to BDD of course

The more and more examples I see and concoct myself like this the more I
> am happy to give up the core assumptions of "object oriented
> programming" etc, and adopt "happy syntax programming". Syntax that
> reads nicely and makes sense as to what it will do and what it will
> return.


You are heading for the future, I'll try to keep up with your ideas.

Now if I could just get the code I originally wrote to work on
> ActiveRecord associations I'd be such a happy camper. I'm in love with
> that syntax.
>
> Nic
>
> --
> Posted via http://www.ruby-forum.com/.
>
>
Robert

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein
Posted by unknown (Guest)
on 2006-09-29 12:56
(Received via mailing list)
Hi --

On Fri, 29 Sep 2006, Dr Nic wrote:

> Trans wrote:
>> But as I suggest,
>> if we see it for what it really is --an adapter, then it makes perfect
>> sense, and doesn;t seem so magical after all (except that it still
>> offers some nicely terse syntax).
>
> I agree - it is very nice syntax.

The ship has clearly sailed on the magic dot, but for the record let
me explain what I don't like about it.

My problem with something like this:

   x.should.be.equal.to(y)

(and I don't mean to parody RSpec; that's a made-up example but I
think it's pretty close) is that it uses method calling *syntax* for
method and/or argument name *semantics*.  To my eye it's basically
just clustering a bunch of words together that pertain to what's going
on, and connecting them with dots in a kind of imitation of spaces or
underscores.

It's very hard to know what "x.should.be" returns.  I can figure it
out, of course.  But it has a tone of "don't worry about what's
actually happening; just read the dot-connected words like a string",
which makes me uncomfortable.

(Actually I think RSpec itself now allows underscores to formulate
method names.)

I do understand how the "magic dot" works.  It works just like every
other dot :-)  I just think there are better-fitted ways to do most of
these things.

array.lengths, for example :-)

Anyway, just to save some bandwidth:

   * I really do understand how it works :-)
   * I do know that all method chaining has a bit of this quality.
   * I'm not trying or expecting to stop anyone from doing it; I'm
       just discussing the possible drawbacks.


David
Posted by unknown (Guest)
on 2006-09-29 12:58
(Received via mailing list)
Hi --

On Fri, 29 Sep 2006, Robert Dober wrote:

>> Nic
> something.get_other().do_stuff().transform()
>
> Terrible, it is only now that I realize that the concept of writing code
> like this might be flawed, there are OTOH strong indications that it is not
> so flawed too. E.g. lots of programing conventions asking for methods to
> return objects.

I don't think anyone objects to method-chaining in every case.  My
dislike is for method chaining that, to my eye and brain, is just a
way of composing a longer method name (or something that could be done
by passing in arguments representing conditions) with dots.

Your.mileage.may.vary :-)


David
Posted by Dr Nic (nicwilliams)
on 2006-09-29 13:09
> My problem with something like this:
> 
>    x.should.be.equal.to(y)
> 
> It's very hard to know what "x.should.be" returns.  I can figure it
> out, of course.  But it has a tone of "don't worry about what's
> actually happening; just read the dot-connected words like a string",
> which makes me uncomfortable.

This would be readable assuming that "should" on x meant something. If I 
saw this I'd guess its like "assert".

But, assuming that your list of words DID mean something, then it has to 
be more readable to newcomers (and yourself in 12 mths time) than the 
possible equivalent:

x.each {|an_x| assert_equal y, x}

or to rephrase the example, perhaps:

x.should {|an_x| an_x.be :equal, :to, y}

The magic dot gives you left-to-right readability, whereas the above 
makes you figure out whats happening in the closure first, then go back 
to the x.each part to see where an_x comes from.

Still, you'd have to create an appropriate proxy class for each message 
you want to support. That could be a pain.

All good fun though :)
Posted by unknown (Guest)
on 2006-09-29 13:34
(Received via mailing list)
Hi --

On Fri, 29 Sep 2006, Dr Nic wrote:

> saw this I'd guess its like "assert".
>
> But, assuming that your list of words DID mean something, then it has to
> be more readable to newcomers (and yourself in 12 mths time) than the
> possible equivalent:

The intent is very clear, I think.  I just don't like the construct
:-)

> x.each {|an_x| assert_equal y, x}
>
> or to rephrase the example, perhaps:
>
> x.should {|an_x| an_x.be :equal, :to, y}

I think my example, in (say) TestUnit, would be more like:

   assert_equal(y,x)

But as I said, the magic dot example was made up, so I can't really
push the point of what it would be equal to in other terms.

> The magic dot gives you left-to-right readability, whereas the above
> makes you figure out whats happening in the closure first, then go back
> to the x.each part to see where an_x comes from.

I can't really comment without hooking my eyes up to a machine and
seeing where they go :-)  But there's no necessity to backtrack once
you've seen x.each {|an_x|, from the point of view of understanding
the code.  Mind you, the magic dot doesn't require backtracking
either.


David
Posted by Robert Dober (Guest)
on 2006-09-29 15:14
(Received via mailing list)
>
>
> David wrote
>
> I don't think anyone objects to method-chaining in every case.  My
> dislike is for method chaining that, to my eye and brain, is just a
> way of composing a longer method name (or something that could be done
> by passing in arguments representing conditions) with dots.
>
> Your.mileage.may.vary :-)


I.see.your.point.emphasis_start.now.emphasis_end
Now that would be abuse of course, mixing content and presentation.

David I am sincerely sorry that my posts -always a bit odd, always a bit
funny [ in both senses of the word ] - have given you the impression 
that I
wanted you to explain something.

I am, and all other regular readers are, well aware that your Ruby level 
is
way above mine and even I understand the magic dot notation :)

As a matter of fact I took your concerns, and Tom's [ I'll come back to 
that
later ] very seriously and did not understand them in the first place.

You made a very good point in your last mail, but again I had the 
feeling
that I had inadevertly insulted you, it was *not* my intent.

So we have the tool, and as always there is danger with power, Tom's 
link to
the Object Adapter Pattern fits very well and when getting into that
paradigm one might as well adapt more towards method chaining than 
before,
even with some small magic.

Tom's attitude "I do not like that", "other people like that", "hmmm why 
do
they like it?",
"hmm maybe because they see it differently, let us do some research", 
"see
that is interesting" is truely admirable and very productive.
I try to mimmick that attitude for sure :)

OTOH one has to look out for code that is not too clear, we are starting 
a
very philiosophic thread here, sorry folks, I thaught BDDs paradigm 
change
was too radical too, but I think that is because I am very conservative 
(c.f.
my POV towards ducktyping).

Those of us who want always to understand - count me in for 100% - might
sometimes fall into the trap of not allowing certain abstractions to 
take
place because, we cannot - even the smartest - immediately understand 
them.
It is a truely difficult process to decide if a new paradigm is worth
exploring and I am more than glad to have nice, competent people here
talking about their paradigms and ideas.

Nuff said for today.

Cheers
Robert

David
>
> --
>                    David A. Black | dblack@wobblini.net
> Author of "Ruby for Rails"   [1] | Ruby/Rails training & consultancy [3]
> DABlog (DAB's Weblog)        [2] | Co-director, Ruby Central, Inc.   [4]
> [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
> [2] http://dablog.rubypal.com    | [4] http://www.rubycentral.org
>
>


--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein
Posted by unknown (Guest)
on 2006-09-29 15:48
(Received via mailing list)
Hi --

On Fri, 29 Sep 2006, Robert Dober wrote:

>
>
> As a matter of fact I took your concerns, and Tom's [ I'll come back to that
> later ] very seriously and did not understand them in the first place.
>
> You made a very good point in your last mail, but again I had the feeling
> that I had inadevertly insulted you, it was *not* my intent.

No, I didn't get that impression in the slightest.  I'm just doing my
usually thing of burrowing down into Ruby stuff and seeing what's
there -- nothing personal riding on it.


David
Posted by Dr Nic (nicwilliams)
on 2006-09-29 16:02
[David] wrote:
> No, I didn't get that impression in the slightest.  I'm just doing my
> usually thing of burrowing down into Ruby stuff and seeing what's
> there -- nothing personal riding on it.

Ruby is great for burrowing. Java is bad. I remember burrowing in Java 
and you always end up at something "final"; something you'd LIKE to 
override or extend but you're not allowed for reasons unknown.

Now we are officially OT. :)

Nic
Posted by Charles Nutter (headius)
on 2006-09-29 16:34
(Received via mailing list)
On 9/28/06, Dr Nic <drnicwilliams@gmail.com> wrote:
> I like this idea too - something that allows you to pick which iterator
> method to use (that is: select, each, map)
>
> Implementable syntax might be:
>
> %w{the meaning of 42}.map_length

FWIW I really prefer the magic underscore over anything else.

The pluralization thing has too much potential for collision and looks
jarring (to_as looks to me like "to" "as", which doesn't make any
sense; then again I'm not a fan of programmatic pluralization for any
reason, since it's very western-language-centric and far from
foolproof (moose? virus? fish?)).

The magic dot has a potential to create scads more objects to handle
the adapting. With a magic dot, list.map.to_i necessarily has to
create some adapter object for the call to map so there's a receiver
for to_i where no object was required before. Unless Ruby is adding a
pretty powerful GC in the future, perhaps we should avoid adding tons
of transient objects just for the magic dot.

The magic underscore has far less potential to cause a collision and
requires no intermediate objects to be created. And as others have
mentioned, it's been proven to look and feel really nice by
ActiveRecord.
Posted by Dr Nic (nicwilliams)
on 2006-09-29 16:57
I like your summary.

> The pluralization thing has too much potential for collision and looks
> jarring (to_as looks to me like "to" "as", which doesn't make any
> sense; then again I'm not a fan of programmatic pluralization for any
> reason, since it's very western-language-centric and far from
> foolproof (moose? virus? fish?)).

I agree that you shouldn't use it if the resulting code makes no sense 
or might cause conflicts. If I've got an array of ActiveRecords that 
have a name field, then calling @list.names to return an array of names 
still seems to be readable and conflictless imo.

> The magic dot has a potential to create scads more objects to handle
> the adapting. With a magic dot, list.map.to_i necessarily has to
> create some adapter object for the call to map so there's a receiver
> for to_i where no object was required before. Unless Ruby is adding a
> pretty powerful GC in the future, perhaps we should avoid adding tons
> of transient objects just for the magic dot.

Perhaps the proxy could be associated with the class and reused?

> The magic underscore has far less potential to cause a collision and
> requires no intermediate objects to be created. And as others have
> mentioned, it's been proven to look and feel really nice by
> ActiveRecord.

I like this a lot too.

#1 and #3 are currently available in the .rb file on my blog page for 
anyone finding this thread.

Nic
Posted by unknown (Guest)
on 2006-09-29 17:00
(Received via mailing list)
Hi --

On Fri, 29 Sep 2006, Charles O Nutter wrote:

> On 9/28/06, Dr Nic <drnicwilliams@gmail.com> wrote:
>> I like this idea too - something that allows you to pick which iterator
>> method to use (that is: select, each, map)
>> 
>> Implementable syntax might be:
>> 
>> %w{the meaning of 42}.map_length
>
> FWIW I really prefer the magic underscore over anything else.

I do too, generally, though map_length sounds like "the length of the
map of this object".  One starts to think there's a reason that map
takes a block....

> The pluralization thing has too much potential for collision and looks
> jarring (to_as looks to me like "to" "as", which doesn't make any
> sense; then again I'm not a fan of programmatic pluralization for any
> reason, since it's very western-language-centric and far from
> foolproof (moose? virus? fish?)).

Yeah, that was my point with sheep, even though I do rather like the
way the plural things read (when they work).  How about:

   array.meese.each do |moose| ... end

The mind boggles :-)


David
Posted by Charles Nutter (headius)
on 2006-09-29 17:33
(Received via mailing list)
On 9/29/06, Dr Nic <drnicwilliams@gmail.com> wrote:
> > The magic dot has a potential to create scads more objects to handle
> > the adapting. With a magic dot, list.map.to_i necessarily has to
> > create some adapter object for the call to map so there's a receiver
> > for to_i where no object was required before. Unless Ruby is adding a
> > pretty powerful GC in the future, perhaps we should avoid adding tons
> > of transient objects just for the magic dot.
>
> Perhaps the proxy could be associated with the class and reused?

Threading, threading, threading...remember JRuby is native-threaded
and Ruby 2.0 should be as well. Even if not native-threaded, a
green-thread context switch could try to use it twice.

And before someone suggests a "proxy pool", almost all benchmarks I've
seen show that with a good GC, just creating transient objects is way
faster than pooling. Of course, Ruby's GC is not on the same level as
the JVM's, so a pool may be faster in Ruby's case.
Posted by Trans (Guest)
on 2006-09-29 17:57
(Received via mailing list)
Charles O Nutter wrote:
> The pluralization thing has too much potential for collision and looks
> jarring (to_as looks to me like "to" "as", which doesn't make any
> sense; then again I'm not a fan of programmatic pluralization for any
> reason, since it's very western-language-centric and far from
> foolproof (moose? virus? fish?)).

You are right there. Pluralization is really going overboard, besides
the exceptions it creates a great deal of computational overhead. It
seems great on the surface, but in the end it is simply is not worth
the effort. Although it can seem odd for the English speaker at times,
Ruby's general favoring of the singular is a very good thing. And this
is one area in which I feel Rails has been unhelpful.

> The magic dot has a potential to create scads more objects to handle
> the adapting. With a magic dot, list.map.to_i necessarily has to
> create some adapter object for the call to map so there's a receiver
> for to_i where no object was required before. Unless Ruby is adding a
> pretty powerful GC in the future, perhaps we should avoid adding tons
> of transient objects just for the magic dot.

Actually this is largely mitigated. Best practice is to cache the
adapter object. So for example Enumerable#every:

  def every
    @_functor_every ||= Functor.new do |op,*args|
      self.collect{ |a| a.send(op,*args) }
    end
  end

This is something not often shown in examples and admittedly may not
make it into first editions of such functions in practice, but
utlimately it gets incorporated and makes a huge difference in the over
head you mention.

> The magic underscore has far less potential to cause a collision and
> requires no intermediate objects to be created. And as others have
> mentioned, it's been proven to look and feel really nice by
> ActiveRecord.

I disagree. "Magic underscore"[1] is either a function of
method_missing or dynamic method creation. There is acually more
potential for name collision in these cases. IN fact that is one of the
uses of the magic dot, to create namespaces. Also care must be taken to
propogte method_missing through the class heirarchy so as not to step
on other people's magic toes. And dynamic method creation adds a lot of
additional methods to a class that Ruby must sort through when
dispatching a call. It certainly looks nice, and I'm in no way agasint
it's use. But there are tradoffs to be considered, and one should apply
that techinique that works best to the need at hand.

[1]FYI, "magic underscore" isn't an a good name b/c we're really just
talking about dynamic method names. These can be anything and do not
neccessarly need an underscore.

T.
Posted by Trans (Guest)
on 2006-09-29 18:07
(Received via mailing list)
dblack@wobblini.net wrote:
> > I agree - it is very nice syntax.
>
> The ship has clearly sailed on the magic dot, but for the record let
> me explain what I don't like about it.
>
> My problem with something like this:
>
>    x.should.be.equal.to(y)

I agree. Unless #should, #be and #equal are all creating some truly
useful and generally applicable adaptation then this is just "fluff
code". Again overhead is being added for no appreciable gain. Of
course, I making an assumption here since I haven't looked at the code
, but I suspect that a magic dot notation like:

    x.should_be.equal_to(y)

is more appropriate. In this case it is easy to see that #should_be is
an assertion adapter. This is interesting, b/c when you break it down
like this one could actaully go a bit further and create more natural
ruby constructs:

    x.should == y

T.
Posted by Dr Nic (nicwilliams)
on 2006-09-29 18:25
With everyone's well founded concerns about name collisions, we should 
all know full well that we live with them in Ruby world on a daily 
basis: monkey patching, method overriding in subclasses, aliasing and 
chain aliasing (how many times do ActiveRecords need to alias some 
methods?!), etc. So hopefully our internal namespace collision detectors 
are already turned on :)

Nic
Posted by Rob Sanheim (rsanheim)
on 2006-09-29 19:39
(Received via mailing list)
On 9/29/06, Dr Nic <drnicwilliams@gmail.com> wrote:
> With everyone's well founded concerns about name collisions, we should
> all know full well that we live with them in Ruby world on a daily
> basis: monkey patching, method overriding in subclasses, aliasing and
> chain aliasing (how many times do ActiveRecords need to alias some
> methods?!), etc. So hopefully our
> internal namespace collision detectors are already turned on :)
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

You misspelt "extensive test suite running continuously" =)

- rob
Posted by Dr Nic (nicwilliams)
on 2006-09-29 20:11
Rob Sanheim wrote:
> On 9/29/06, Dr Nic <drnicwilliams@gmail.com> wrote:
>> With everyone's well founded concerns about name collisions, we should
>> all know full well that we live with them in Ruby world on a daily
>> basis: monkey patching, method overriding in subclasses, aliasing and
>> chain aliasing (how many times do ActiveRecords need to alias some
>> methods?!), etc. So hopefully our
>> internal namespace collision detectors are already turned on :)
>    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 
> You misspelt "extensive test suite running continuously" =)

No spellchecker on Ruby forums UI. Perhaps I can whip up a greasemonkey 
script to help me with such simple/common typos. :)
Posted by Robert Dober (Guest)
on 2006-09-29 21:31
(Received via mailing list)
On 9/29/06, Rob Sanheim <rsanheim@gmail.com> wrote:
>
> On 9/29/06, Dr Nic <drnicwilliams@gmail.com> wrote:
> <SNIP>
>
> internal namespace collision detectors are already turned on :)
>    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> You misspelt "extensive test suite running continuously" =)


Miss Van  Pelt, reread your Peanuts,
but you have a point of course!

- rob...



..ert

--
Posted by Seth Thomas Rasmussen (Guest)
on 2006-10-01 07:16
(Received via mailing list)
Charles O Nutter wrote:
> The pluralization thing has too much potential for collision and looks
> jarring (to_as looks to me like "to" "as", which doesn't make any
> sense; then again I'm not a fan of programmatic pluralization for any
> reason, since it's very western-language-centric and far from
> foolproof (moose? virus? fish?)).

And just about every programming language syntax isn't already? I like
programmatic pluralization because it allows us to write code in the
same way we talk about it. It's like optimization for our brains, and
expressive power that seems to get closer to more intelligent programs,
as well as making syntax more accessible to laypersons. As for the
potential inaccuracy of converting certain terms, you could provide an
interface to add definitions as Rails' Inflector does.

On the topic at hand, I don't like the plurals option. The
Symbol#to_proc style currently in ActiveSupport seems just about
perfect to me, although I don't see why it couldn't just be:

foos.map :bar

p.s. I got totally lost with all that crazy.dot.talk. That hypothetic
code made me want to cry.
Posted by Dr Nic (nicwilliams)
on 2006-10-01 07:31
Seth Thomas Rasmussen wrote:
> foos.map :bar

That'd be workable syntax.

class Array
  alias old_map map
  def map(*args)
    if args.length > 0
      return self.map {|item| item.send args.first}.map *args[1..-1]
    else
      return self.old_map
    end
  end
end

This would allow:
people.map :fullname, :split

as the equivalent of:
people.map {|p| p.fullname}.map {|n| n.split}

Oh so much fun :)

Nic
Posted by Dr Nic (nicwilliams)
on 2006-10-01 07:44
Trans wrote:
> Charles O Nutter wrote:
>> The pluralization thing has too much potential for collision and looks
>> jarring (to_as looks to me like "to" "as", which doesn't make any
>> sense; then again I'm not a fan of programmatic pluralization for any
>> reason, since it's very western-language-centric and far from
>> foolproof (moose? virus? fish?)).
> 
> You are right there. Pluralization is really going overboard, besides
> the exceptions it creates a great deal of computational overhead. It
> seems great on the surface, but in the end it is simply is not worth
> the effort. Although it can seem odd for the English speaker at times,
> Ruby's general favoring of the singular is a very good thing. And this
> is one area in which I feel Rails has been unhelpful.

The way I coded it, it singularizes the string and passes that as the 
method call for the items of the collection. So if you pass a singular 
method name, then it will still be singular when its passed to the 
children.

That is:

people.names

returns the same list of names as

people.name

So non-English speakers can be happy too. Of course, if the people Array 
class had a name method, the latter wouldn't work. But unless you have 
an Array of Arrays, you won't get many name conflicts btw the Array 
class and the container class.

Re: performance overhead - I'm not sure if the standard map+block is 
more or less efficient than a for-loop, but I use it anyway because my 
code is much more readable and writable. If I later discovered that I 
had a performance bottleneck near my map+blocks, then I could refactor 
them for speed.

I don't think that in a thread on "fun syntax ideas" disapproving on the 
ideas based on small performance hits like "apply a gsub on a string" is 
much fun. :(

Cheers
Nic
Posted by Jordan Callicoat (monkeesage)
on 2006-10-01 08:06
(Received via mailing list)
Seth Thomas Rasmussen wrote:
> On the topic at hand, I don't like the plurals option. The
> Symbol#to_proc style currently in ActiveSupport seems just about
> perfect to me, although I don't see why it couldn't just be:
>
> foos.map :bar

It can...

class Array
  def map(sym=nil, &block)
    self.inject([]) { |col, item|
      if block_given?
        col << block.call(item)
      elsif not sym.nil?
        col << item.send(sym)
      else
        col << item
      end
    }
  end
  def map!(sym=nil, &block)
    self.replace(map(sym, &block))
  end
end

Regards,
Jordan
Posted by Trans (Guest)
on 2006-10-01 13:56
(Received via mailing list)
Seth Thomas Rasmussen wrote:
> expressive power that seems to get closer to more intelligent programs,
> p.s. I got totally lost with all that crazy.dot.talk. That hypothetic
> code made me want to cry.

Rails :\
Posted by Charles Nutter (headius)
on 2006-10-02 22:19
(Received via mailing list)
On 10/1/06, Dr Nic <drnicwilliams@gmail.com> wrote:
> Re: performance overhead - I'm not sure if the standard map+block is
> more or less efficient than a for-loop, but I use it anyway because my
> code is much more readable and writable. If I later discovered that I
> had a performance bottleneck near my map+blocks, then I could refactor
> them for speed.

The JRuby code started out as a port of the C Ruby code, and for us a
'for' is just an 'each' over a range...so it's probably about the
same, performance-wise.
Posted by Martin DeMello (Guest)
on 2006-10-03 12:04
(Received via mailing list)
On 10/1/06, Dr Nic <drnicwilliams@gmail.com> wrote:
>
> This would allow:
> people.map :fullname, :split
>
> as the equivalent of:
> people.map {|p| p.fullname}.map {|n| n.split}
>
> Oh so much fun :)

I did this a while back by adding an f (for functional) to the method
name - so if you said people.mapf :fullname method_missing would see
that it ended with an f, strip the f out and construct a block to pass
to map. map_fullname reads even better, though.

martin
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.