The Artima Developer Community
Sponsored Link

Weblogs Forum
The Adventures of a Pythonista in Rubyland/2 - No Comprehension

30 replies on 3 pages. Most recent reply: Jan 4, 2009 7:26 PM by Carl Graff

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 30 replies on 3 pages [ « | 1 2 3 | » ]
Carson Gross

Posts: 153
Nickname: cgross
Registered: Oct, 2006

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Oct 30, 2008 4:47 PM
Reply to this message Reply
Advertisement
>
> I think the question is how you do something like this:
>

> [x.lower() for x in aList if len(x.strip()) > 0]
>

> using built in methods. It's not clear to me how you
> would do that in Ruby.

Well, I'm no ruby expert, but I'd do this:


x.select{|s| s.strip.length > 0 }.map{|s| s.downcase }


You just compose the methods you want together in whatever manner you like, just like in regular old code. No syntax to learn beyond the block/closure syntax, which is generally applicable (i.e. it doesn't apply only to Lists.)

Doesn't seem crazy to me.

For completeness, the same thing in GScript, our internal statically typed scripting language, is:


x.findAll( \ s -> s.strip().length > 0 ).map( \ s -> s.toLowerCase() )


In GScript, we don't make a distinction between block and regular method parameters like ruby allows you to do. Blocks/closures are just another possible argument type. Personally, I prefer that simplicity.

Cheers,
Carson

Mark Thomas

Posts: 1
Nickname: markthomas
Registered: Oct, 2008

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Oct 30, 2008 6:34 PM
Reply to this message Reply
> I think the question is how you do something like this:
> [x.lower() for x in aList if len(x.strip()) > 0]
> using built in methods. It's not clear to me how you
> would do that in Ruby.

Simple.

alist.collect{ |x| x.downcase unless x.empty? }.compact


The "compact" gets rid of any nil items. This would have worked in the original topic, too:

aList.collect { |x| x.length unless x.rstrip.empty? }.compact

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Oct 30, 2008 7:13 PM
Reply to this message Reply
> Well, I'm no ruby expert, but I'd do this:
>
> x.select{|s| s.strip.length > 0 }.map{|s| s.downcase }
>
> You just compose the methods you want together in whatever
> manner you like, just like in regular old code. No syntax
> to learn beyond the block/closure syntax, which is
> generally applicable (i.e. it doesn't apply only to
> Lists.)
>
> Doesn't seem crazy to me.

Not to me either. But I find the frequent claims that Ruby might as well be plain English a bit of an exaggeration.

To be fair, select and map are specific to lists (or arrays or whatever). And technically for comprehensions are not specific to lists. They can be used with any iterable object or with methods that yield values.

And, of course, you can do the same kind thing as you shown above in Python. I don't really care that much, I'm just a casual Python user. I haven't found any really strong argument for learning Ruby though.

James Iry

Posts: 85
Nickname: jiry
Registered: Nov, 2007

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Oct 31, 2008 9:36 PM
Reply to this message Reply
Monkey patch in a monadic bind and you can combine select/reject and map into one go. Bind is one powerful HOF.

Scala using a monadic bind (which Scala calls flatMap because bind is like doing a map and then flattening the result):
x flatMap {s => if(s.trim.length > 0) List(s.toLowerCase) else Nil}

I have to admit, the Scala monadic comprehension looks a bit nicer: for (s <- x; if (s.trim.length > 0) yield s.toLowerCase

But it translates into the slightly more complex: x filter {s => s.trim.length > 0} map {s => s.toLowerCase}

Which is equivalent to the Ruby: x.select{|s| s.strip.length > 0 }.map{|s| s.downcase }

and GScript: x.findAll( \ s -> s.strip().length > 0 ).map( \ s -> s.toLowerCase() )

Andy Dent

Posts: 165
Nickname: andydent
Registered: Nov, 2005

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Nov 1, 2008 11:01 PM
Reply to this message Reply
James Watson opined
> To be fair, select and map are specific to lists (or
> arrays or whatever). And technically for comprehensions
> are not specific to lists.

As I understand it, they are specific to any class which has mixed in the Enumerable module: http://www.ruby-doc.org/core/classes/Enumerable.html but there are differences between mixins in Ruby and Python duck typing about which I've got to read more. I found an interesting posting http://meme-rocket.com/2006/09/28/ruby-moduleinclude-at-odds-with-duck-typing/ which will be a starting point for my own investigations.

Posted from Te Anau in New Zealand's South Island on an utterly fabulous spring afternoon.

Michele Simionato

Posts: 222
Nickname: micheles
Registered: Jun, 2008

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Nov 1, 2008 11:37 PM
Reply to this message Reply
> I found an interesting posting
> http://meme-rocket.com/2006/09/28/ruby-moduleinclude-at-odd
> s-with-duck-typing/ which will be a starting point for my
> own investigations.

It is another example of generic functions being better than mixins. See my own post here:
http://www.artima.com/weblogs/viewpost.jsp?thread=237764

Carson Gross

Posts: 153
Nickname: cgross
Registered: Oct, 2006

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Nov 2, 2008 8:22 AM
Reply to this message Reply
> Not to me either. But I find the frequent claims that
> Ruby might as well be plain English a bit of an
> exaggeration.

Yeah, I agree with that. I personally prefer ruby because I find blocks an intuitive and flexible language feature, but honestly I don't use it very often.

> To be fair, select and map are specific to lists (or
> arrays or whatever). And technically for comprehensions
> are not specific to lists. They can be used with any
> iterable object or with methods that yield values.

Well, select() and map() don't have to be specific to Lists (although they may be in ruby, I'm not sure.) They both simply rely on iteration. I really think that the features are semantically equivalent. It's the classic trade off: language or libraries?

List comprehensions (and their more advanced friends) put feature design in the hands of the language designers by requiring new syntax in the language to support new features.

Blocks/closures delegate that responsibility to library designers by providing a general syntax for succinctly representing small functional units that library designers can use to provide features with.

The former, if done well, can have a more intuitive reading syntax since the language designer has free reign with the parser. Additionally, the language designer can implement the feature as they see fit rather than accepting the standard evaluation semantics of the language, since they control the whole environment.

The latter has the advantage that the language stays smaller and that library developers can add features as they see fit, rather than convincing some language weenie to add syntax for it.

In general, I come down in favor of the latter. However, seeing Microsoft's work on LINQ has shown me that you have to be pragmatic about the decision and that certain things are fundamental enough to warrant additional syntax in a language.

> And, of course, you can do the same kind thing as you
> shown above in Python. I don't really care that much, I'm
> just a casual Python user. I haven't found any really
> strong argument for learning Ruby though.

I think ruby is worth learning just because it's such a strange little language, with it's special block parameters, flexible parsing rules (which I've grown to despise) and interesting culture. But then there are lots of things worth learning and only so much time in the day.

Cheers,
Carson

Carson Gross

Posts: 153
Nickname: cgross
Registered: Oct, 2006

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Nov 2, 2008 10:45 AM
Reply to this message Reply
> It is another example of generic functions being better
> than mixins. See my own post here:
> http://www.artima.com/weblogs/viewpost.jsp?thread=237764

Note that he means "generic functions" in the lisp sense (http://en.wikipedia.org/wiki/Generic_function) not the java sense. I've always called that concept "multimethods," perhaps incorrectly. I was very confused on my first reading of his article because I kept thinking he meant using parametric polymorphism.

Cheers,
Carson

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Nov 2, 2008 12:19 PM
Reply to this message Reply
> Well, select() and map() don't have to be specific to
> Lists (although they may be in ruby, I'm not sure.) They
> both simply rely on iteration. I really think that the
> features are semantically equivalent. It's the classic
> trade off: language or libraries?

I meant that these operations must be defined on each type that you want to use them with but maybe that's not correct. The for comprehension just depends on a method or two (can't remember what) being there.

> ...
>
> In general, I come down in favor of the latter. However,
> seeing Microsoft's work on LINQ has shown me that you have
> to be pragmatic about the decision and that certain things
> are fundamental enough to warrant additional syntax in a
> language.

I tend to agree but Python's for comprehension is one of those features that python developers end up using all the time which, in my opinion, is really what determines whether a language feature should exist.

Jules Jacobs

Posts: 119
Nickname: jules2
Registered: Mar, 2006

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Nov 8, 2008 4:03 AM
Reply to this message Reply
> The for comprehension just depends on a method
> or two (can't remember what) being there.

Ruby's select, map, and other Enumerable methods depend only on a method `each`:

class MyCollection
  include Enumerable
  def each
    ...
  end
end


This class supports select, map, etc.

Elizabeth Wiethoff

Posts: 89
Nickname: ewiethoff
Registered: Mar, 2005

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Nov 17, 2008 10:42 AM
Reply to this message Reply
Turning my Python brain into a Ruby brain a couple years ago was darn frustrating. So, yeah Andy, I can relate. The fact that Ruby has a huge API on account of synonyms adds to the learning difficulty.

Trying to fake list comprehensions in Ruby can drive you bonkers until you get the hang of it. I suggest you revert your thoughts to the two good, old-fashioned Python map() & filter() functions.

Keep these equivalences in mind:

* Python map() == Ruby Enumerable#collect and its synonym Enumerable#map
* Python filter() == Ruby Enumerable#select and its synonym Enumerable#find_all
* Python reduce() == Ruby Enumerable#inject

* Python map() and Ruby Enumerable#collect/map always return a collection with the same number of elements you started with.
* Python filter() and Enumerable#select/find_all always return a collection with as many or fewer elements as you started with.
* Python reduce() and Ruby Enumerable#inject always return a single object.

You might find my "Ruby API Guide" helpful (http://mysite.verizon.net/hpassel/rubyguide/), although I haven't worked on it in months, and the external links have wandered off. Grrr.

BTW, I like the Ruby Cookbook. It's the only Ruby book I've bothered to buy, not being impressed by the Pickaxe and others I've perused.

Andy Dent

Posts: 165
Nickname: andydent
Registered: Nov, 2005

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Nov 17, 2008 7:07 PM
Reply to this message Reply
Carson translated:

Python
[x.lower() for x in aList if len(x.strip()) > 0]

to Ruby
aList.select{|s| s.strip.length > 0 }.map{|s| s.downcase }


and commented:
> You just compose the methods you want together in whatever
> manner you like, just like in regular old code.

One important point is that the Ruby solution is creating two lists. This may not seem like a big deal but I used to work with geological scientists who processed multiple million-item lists and dictionaries in Python. I'm also aware of Python being heavily used for data crunching in the bioscience community.

At those kind of data volumes, avoiding intermediate results starts becoming significant, which is one reason why Python introduced generator expressions in v2.4

http://www.python.org/dev/peps/pep-0289/

So, whilst the compositional approach in Ruby has some appeal, at data sizes where efficiency matters, it would be worth going back to a solution like my original:

destList = []
aList.each { |x| destList << x.downcase unless x.rstrip.empty? }

Andy Dent

Posts: 165
Nickname: andydent
Registered: Nov, 2005

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Nov 17, 2008 8:01 PM
Reply to this message Reply
Elizabeth wrote:

> You might find my "Ruby API Guide" helpful
indeed!

> BTW, I like the Ruby Cookbook
agreed. Noting your comments about the index on your website, Ruby Cookbook and many other Ruby books are in Safari so are searchable, including the ability to limit searches to just code snippets.

You can search in Safari without being a member or having a particular book in your bookshelf and the results are usually sufficient to at least refer you to the section in the paper book. I frequently use it in that manner, eg:
http://safari.oreilly.com/0596523696/rubyckbk-CHP-1-SECT-10#snippet

Elizabeth Wiethoff

Posts: 89
Nickname: ewiethoff
Registered: Mar, 2005

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Nov 18, 2008 5:00 PM
Reply to this message Reply
Thanks for the tip about searching O'Reilly Safari, but I can't use it effectively. I have to switch to my Safari browser (no relation) to search the book at all, and then I can't load the individual snippets. The snippets try to load Flash, which I can't use on account of my seizures. (Bah! I hate "modern" web sites.) I'm a text, CSS, non-animated pics, and non-Javascript person who often uses Lynx. :-)

[Elizabeth:] You might find my "Ruby API Guide" helpful. [Andy:] indeed!

Thanks! Maybe now I'm inspired to fix the external links!

[Andy:] One important point is that the Ruby solution is creating two lists. This may not seem like a big deal but I used to work with geological scientists who processed multiple million-item lists and dictionaries in Python.

Yep. I come from a scientific programming background, too. These days the hobby extreme programming group I'm in is using Ruby for comparing all the text in all the user files in a system. The number of objects created, hogging memory, and awaiting garbage collection is staggering.

One of the silly things about our group being so Ruby method-minded--we're doing OO!--is that we create throwaway Arrays just to perform min/max, e.g., [7, 2].min Sometimes I just cringe. Oh, if only they would let me define min() and max() functions...

[Andy:] At those kind of data volumes, avoiding intermediate results starts becoming significant, which is one reason why Python introduced generator expressions in v2.4

Enumerable::Enumerator might be suitable. But keep in mind, you're then limited to using just Enumerable and Object methods.

Carl Graff

Posts: 2
Nickname: cgramona
Registered: Jan, 2009

Re: The Adventures of a Pythonista in Rubyland/2 - No Comprehension Posted: Jan 4, 2009 3:27 PM
Reply to this message Reply
OK so I'm going in the opposite direction, from Ruby to Python, and trust me the frustration is the same going the other way. I have used Ruby for three years doing enterprise integrations and found it to be the most intuitive, productive, and consistent language I have used to date. You can always effortlessly modify the standard libraries if they aren't named exactly to your liking or have some functionality missing.

I have been using Python for about 2 months now mainly to use IronPythonStudio for .net interoperability and later for Google Apps. There is a lot to like about both languages but this series "seems" to be taking the tone of why can't I do things as easily in Ruby.

As such, perhaps it's worth mentioning a few things that I found more difficult in Python:
1. Ruby was easier to learn and more intuitive and consistent - surprising since Ruby was more different from my previous languages than Python is from Ruby.
2. Global, instance, and local variable scoping and usage is (to be kind) confusing and awkward.
3. Ditto for the importing of modules, classes, and name spaces.
4. Inconsistencies in collection method naming - for example .add for sets and .append for lists or is it the other way around.
5. I like the organization of RubyDocs which is similar to JavaDocs. I can get to a comprehensive listing of library objects and their functionality quicker. Is there a PythonDocs formatted similar to RubyDocs or JavaDocs? Once you get past the basics the long verbose textual type documents are tedious.

I sincerely hope to find Python as easy and powerful to use as Ruby after a couple more months as Python may be the only option available to me on certain projects. I would be perfectly happy using either language but given the choice, at this point, I would choose Ruby. Also the upcoming Rails and Merb merge makes learning and using Ruby desirable IMO (yes I know about Django).

Please do continue with this series because it will no doubt provide me insight into doing things the Python way instead of the Ruby way which will hopefully be as good or better.

Will a dominant dynamic language emerge over the next year or so such as Java did for static languages and if so which one and would that be a good thing?

Flat View: This topic has 30 replies on 3 pages [ « | 1  2  3 | » ]
Topic: The decorator module version 3 is out! Previous Topic   Next Topic Topic: Ubuntu on the EeePC

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use