Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Ruby is beautiful (but I'm moving to Python) (allthingsprogress.com)
121 points by djacobs on Nov 28, 2010 | hide | past | favorite | 172 comments


This is a perfectly cromulent article, but as someone relatively new to Ruby, I don't see the beauty. Perhaps I've spent too much time with the airless asceticism of, say, Scheme, but Ruby just reads a mess to me. Too many synonyms, too much implicit behavior. There's too much language for my taste. Of course, beauty is in the eye of the beholder &c., &c., &c., and I wouldn't deny that there is a certain pragmatic attraction (even I like to get shit working). But beauty?


> This is a perfectly cromulent article, but as someone relatively new to Ruby, I don't see the beauty. Perhaps I've spent too much time with the airless asceticism of, say, Scheme

Yes. Ruby is beautiful when you come from PHP or Java or C++. If you come from Python it's meh because it's a very similar language (though the community is different and a number of recipes/best practices are very different) at the syntactic and at the semantic levels, and if you come from Lisps, from Smalltalk, from ML or Haskell, etc… then it's not "meh" it's "ugh", because the language is far more complex less orthogonal and far more full of weird corner-cases than what you come from.

TFAA came to Ruby from Java, so Ruby was like seeing the Sistine Chapel for the first time.


Instead of a simply giving your subjective aesthetic evaluation, based on some measure of "elegance", you could objectively compare, in HCI terms, the usability of the languages as user-interfaces to the computer. A mouse may be more elegant than a keyboard, but for, say, word-processing, it would have comparatively-horrible usability.

Likewise (and this is just a throwaway argument, not the general point I'm trying to make), Lisp may be more elegant conceptually than Ruby, but when trying to find an individual incorrect line of code to make a change, Lisp's "elegant" uniformity actually hinders scanning, whereas Ruby's bumpy, "inelegant" syntax gives your eyes regularized shapes to abstract sections of code into, and thus visually skip them without having to read into their contents.

However, as the mouse's elegance matches well with a paint program, Lisp matches well with Turing-complete data-specifications ("code as data.") Usability is not a one-dimensional spectrum, like your partial ordering of "beauty" above, but rather a consideration made separately for each task an interface is used for.


Actually, despite all the fanfare about LISP, Haskell, Scheme et al, more useful programs have been written and deployed in, say, Python, than all those combined.

What's the last useful LISP program you have used? What proportion does it consist among the other useful programs you use?


> What's the last useful LISP program you have used? What proportion does it consist among the other useful programs you use?

Was that a subtle dig at those who spend too much time on HN?


Emacs (ok, so it has a kernel of C code but it's still by and large a lisp program)


I use Scheme/Haskell for most of my scripting purposes, the only exceptions being the cases where I want to make use of some extant library, in which case I switch to Python/Ruby. I used stumpwm for a while, which was written in Common Lisp, and a few months ago switched to XMonad, which is all Haskell. All my editing is done in Emacs, which uses a variety of Lisp (elisp.)

Given that close to 100% of my time is spent in XMonad, and >50% of my time is spent in Emacs, and every session involves at least some interaction with my collection of scripts... I'd say I use quite a lot of useful programs written in those fanfare-laden languages.


I'm a Python programmer, and I find code written in Ruby to be more beautiful.

It's just a personal preference, but I find anonymous code blocks to be a lot more elegant and intuitive than decorators + with statements + for comprehensions. I also like that classes are open, and that you can execute code inside the declaration of a class and that self is implicit ... making tasks suited for the __metaclass__ concept in Python trivial.

I also find Lisp / Haskell and ML to be really ugly ... as in, I could never look over a piece of code and understand what it is doing without learning the language first (with the learning curve being as steep as it gets).

     the language is far more complex less orthogonal and far 
     more full of weird corner-cases than what you come from
But that's the price you pay for convenience.

E.g. I don't appreciate that ML doesn't have a simple concept like operator overloading, or that in LISP every DSL still looks like LISP. I don't like that a Smalltalk application is not portable between implementations or that applications are big, monolithic images of the virtual machine with everything included, even the IDE.

It's easy to get into these mine-is-bigger-than-yours contests, especially with languages, but you know what works better than formulating half-baked opinions?

Results. It's a lot better to shut up and show me some code ;)


1. You can not really juge the source code of a language if you don't the language. Reading alot of functional code is almost always easier then OO code because of pure functions. Look at this video for example at the videos witch can be found here http://www.janestcapital.com/technology/ocaml.php

2. The learning curve of those languages is not bigger then the learning curve of other languages. Time time I spend with making pretty OO designs in school was way bigger then the time it took me to learn clojure and FP in general but this of course is a issue we can not solve. I just don't like it if people say something as if it is a fact.

3. Is it more convenient to do this array.select &:even? better then (filter even? array)

The later seams more intuitive to me and I didn't have to learn more syntax.

4. In Lisp not every DSL looks like Lisp.


"The learning curve of those languages is not bigger then the learning curve of other languages."

If only it wasn't for the fact that reality and history has proven otherwise...


The Homecomputer on witch most programmer learned where to slow for functional languages of that time. So FP could only be used in specialized domains.

Most programmers went form basic (lack of alternative) to C then C++ and now Java thats a path of simularity. Most where never exposed to functional programming and now the all have a hard time to switching there OO brain off.


Any source for that utterly outlandish claim?


Utterly outlandish? Please.

The only proof we have of something being easier to learn, beside anecdotal evidence ("oh, I tried it and it was easy") is statistical empirical evidence, i.e people actually learning it. Well, people are not actually learning those languages. They are learning the "other ones".

(Where by people, I mean: a significant percentage of people, > 1%. I'm sure me, you and that "professional programmer who gives a shit about Haskell" do not a significant percentage make).

Even in universities, students find functional languages difficult, and opt-out of those classes.


> I also find Lisp / Haskell and ML to be really ugly

Wow.

> I don't appreciate that ML doesn't have a simple concept like operator overloading

ML operators are nothing more than functions. The issue of "operator overloading" comes from the type system and the simplicity of the language.

> or that in LISP every DSL still looks like LISP

You might want to read on Scheme reader macros.

> I don't like that a Smalltalk application is not portable between implementations

It's true that you don't have this issue in Ruby as the "standard" is simply the original implementation (aka there is no standard at all, and not really any competing implementation).

> or that applications are big, monolithic images of the virtual machine with everything included, even the IDE.

That definitely isn't the case. That's not the case in GNU Smalltalk, and most commercial smalltalk let you create a stripped production image which contains only the necessary code.


> It's true that you don't have this issue in Ruby as the "standard" is simply the original implementation (aka there is no standard at all, and not really any competing implementation).

Check out https://github.com/rubyspec/rubyspec.

And there are plenty of competing implementations: JRuby, Rubinius, MagLev, etc.


Checking out an effort to extract a viable specification from an implementation which manages to be incompatible with itself every other release? Why?


The C# compiler in .NET also has incompatibilities with the ECMA standard. Need I mention C++, the most widely used and at the same time poorly implemented language ISO standard ever?

In fact, can you mention a single language with a standard that doesn't brake compatibility with its standard?

And yet the point is moot, because compatibility between implementations is manageable for popular languages like Javascript, C++ and yes, Ruby (JRuby, Rubinius). That's not the case for Smaltalk.


Not to mention the impending ISO standard.


or that in LISP every DSL still looks like LISP

<bait>When your language is already at the top of the beauty chart, why would you write a DSL that is not also beautiful?</bait>

It is really a programmer choice. Lisp programmers generally love the way Lisp looks because of the advantages awarded by those looks (check Myth #7 here: http://www.algo.be/cl/myths.htm). But you can certainly create a DSL that requires more extensive string parsing, and CL provides a lot of help towards that end, including native translations of strings to Lisp objects where your parser needs them.


while we're complaining - my big problem with, really, programming languages in general, these days, is that they're getting good at making it easy to do complicated things within a process but unfortunately typical development projects are getting to be more distributed, which means that the nice abstractions your languages provide usually can't extend across your entire application, so you end up dumbing things down, relying on stuff like web frameworks which imo tend to be a bunch of hacks, etc. (This is probably the reason for the current popularity of dynamic/untyped languages - why bother specifying types when the invariants they create will only hold across part of your application anyway?)

I'd like to see more effort put toward creating programming environments that provide clean abstractions that span entire multi-process distributed applications.


Ruby is nicer to read than Python. Here's how each language reverses a string:

# Ruby

string.reverse()

# Python

string[::-1]

Which looks better?

Edit: I'm not sure why this is being down voted. It's a true statement.

Edit2: With all the down voting on Hacker News recently, I'm about to quit sharing my knowledge here. Maybe pg will do something about this. It needs to change otherwise good people will stop posting here.

Edit3:

irb(main):002:0> x = "hacker"

irb(main):003:0> puts x.reverse()

rekcah

>>> x = "hacker"

>>> print x[::-1]

rekcah


I think possibly because it's 'fiddling around the edges'. Sure, it's nice to have a way to reverse a string, but you don't do that very often in practice - assigning to lists, calling functions, etc. are all far more common.

But yeah, I hear you on the downvoting.


FWIW, I come from Java and find Ruby to be fairly ugly.

It's all subjective, but I prefer concise, exact non ambiguous readable code.

From a google for 'ruby sample code'...

http://www.fincher.org/tips/Languages/Ruby/

  print " with no line breaks."

  printf("\n\nprintf ... %7.2f,... %s.",3.14156,"me")
Eugh brackets are optional for invoking functions? So I can no longer just look for () after a name to determine what is a function invocation?

  def welcome(name)
   puts "howdy #{name}"
  end
"end"? Seriously? Verboseness... (This is one of the things that for me, makes ruby very ugly. It's needless verbosity and doesn't have any advantage over using {} ).

  "hello".upcase() => "HELLO"
  "hello".upcase => "HELLO"
Yuck. So how do you know what's a function and what's a variable?

  balance = -10.0
  puts "Bankrupt" unless balance > 0.0
Starting to look like cobol here... 'unless'? seriously? Why is that nicer than an if statement?

Java code has a very exact, easy to parse syntax. We all know it, and it's easy to learn - {} for code blocks, () for method invocations, etc

That's just for starters.


It cannot please everyone so if you are happy with a less "conversational" language, stick with it. "Unless", for example, is what I think to myself so "if not" is a suboptimal translation thereof.

I would point out, however, that printf is fairly rarely used and that I am not familiar with fincher.org in the context of sites to recommend newbs to learn Ruby from.

Removing the difference between accessing an attribute (variable) and invoking a method is a solid OO principle. You, as a client of the API, should not care how obj.foo is implemented.


> Removing the difference between accessing an attribute (variable) and invoking a method is a solid OO principle.

It's called the Uniform Access Principle[1] and the languages that don't take advantage of it often suffer from a getter/setter hell.

[1] http://en.wikipedia.org/wiki/Uniform_access_principle


Er, that's one of those false dichotomy thingos. It's quite possible to have something like properties in Python: http://www.python.org/download/releases/2.2.3/descrintro/#pr...

Hey presto! Now you have the best of both worlds.


> "Removing the difference between accessing an attribute (variable) and invoking a method is a solid OO principle. You, as a client of the API, should not care how obj.foo is implemented."

I disagree. Code execution is not data access. They are very separate concepts.


Inasmuch this conversation is subjective, I just do not think that statement is objectively true. It is a basic OO principle that the outside world is not privy to the inner workings of an object (or class if you prefer).

Whether you like that or not is immaterial. You are free to avoid that aspect of OOP or the paradigm altogether.


I haven't studied OOP extensively in a strict setting, but I would have said that in the OO world, a property is completely separate to a method.

For example,

  class flower
  property color
  property numberOfPetals
  method pluckPetal()
  method water()
A property defines data about an object, and a method defines something you can 'do' with the object.

Could you give some pointers to the OOP principle that blurs the line between these two?


It's called the Uniform Access Principle, as I've already mentioned in a separate comment. Getting back to your example, it is not very useful without mentioning a language under examination. There is no single definition of OOP, and every language implements in a slightly different way.

There are languages where UAP is enforced by the syntax (eg. Eiffel, Smalltalk, Ruby) and languages where it's a matter of convention. But even in the latter it's considered a good practice to keep properties private and encapsulate them with accessors. Some even have dedicated features that help with that (auto-properties in C#, properties in Python).


> I haven't studied OOP extensively in a strict setting, but I would have said that in the OO world, a property is completely separate to a method.

There is absolutely no reason for that, and the grandparent of all things object-oriented (Smalltalk) very strongly disagrees with you: everything is a message, and there are no properties.

> A property defines data about an object, and a method defines something you can 'do' with the object.

A getter method is a property and a method. Properties are irrelevant, access should be uniform, the implementation details of an object (whether a "property" provides direct access to internal data or not) is of no concern to the user of the object.

A property is nothing more than a method whose contract is "give me some data"


That's a fine answer, and some people may find that a helpful way to organize programs.

However, for me, and the CPU, we treat code execution differently to data access.


There's OOP qua Smalltalk/Kay, and then there's OOP qua Java. You're describing OOP qua Java, which is an ugly type of OOP designed for certain performance advantages.


Don't be ridiculous.

1. It's not ugly

2. It's how CPUs work

3. It's how most people think


1. By ugly, I mean less mathematically elegant. In Ruby, you say "paul.foo" and get foo from Paul. How Paul gets foo for you is up to Paul. Simple.

2. If you want a programming language that maps closely to how CPU's work, Ruby's definitely not for you. Assembly and C are for you.

3. I can't speak for most people. What I can say is that I can think in C and I can think in Ruby, and it doesn't seem difficult for me.


A Java developer complaining about Ruby's supposed verbosity? What's the world coming to?! When one looks at Java code, 90% of it is just syntactic sugar, which doesn't add much to the actual working code. One has to filter through large amounts of white noise to get to the crux of the code. Not so with Ruby (and many other languages).


This is exactly what the original article was saying. ;) The languages take very different mindsets though, so if someone is actually happy with Java, then it's very possible that they don't have (or want) the right mindset for using Ruby.


Not really.

"public static final" is not particularly verbose. It's a one time upfront cost which defines a few flags. It's error free, since a typo in any of those keywords will be picked up.

It can also be automated easily etc.

But Ruby using 'end' etc instead of curly braces, that's going to add up to a lot of verbosity.


With regards to differentiating methods, that's simple. "obj.name" calls a method. An object's variables are hidden inside the object, so the only way to access them is via methods anyways.

Furthermore, variables can't be called. If you have a proc object in a variable, you use "myproc.call" to invoke it. The only ambiguity is between methods call within the same 'self' and local variables:

    def foo
      42
    end
    
    def bar
      puts foo #=> 42
      foo = 30
      puts foo #=> 30
      puts self.foo #=> 42
    end
In practice this isn't a big problem.


Ah I didn't realize Ruby does not have the ability to access properties of an object. That seems like a pretty big disadvantage.


That's because methods effectively -are- properties. See:

  class Foo
    attr_reader :bar
    
    def initialize (num)
      @bar = num
    end
  end
  
  puts Foo.new(42).bar
attr_reader is a class-level method that defines a getter method for the named variable. There's also attr_writer, for setting, and attr_accessor, for both at once.


... and people complain that Java is verbose???


Here it is, converted to java. You tell me which is more verbose.

    public class Foo
      int bar;
      
      public Foo(int bar) {
        this.bar = bar;
      }

      public int getBar() {
          return bar;
      }

      public static void main(String[] args) {
        System.out.println(new Foo(42).getBar());
      }
    }


Actually, in idiomatic java, it'd be even longer:

You should make bar private, and add a setter. After all, we might want to change the rules on setting bar sometime, and you wouldn't want to have to go back and change everywhere that accesses it...


> You should make bar private

It's package-access by default, that's enough to hide it from the third-party users of the class.

> and add a setter

The original code uses `attr_reader` which defines a readonly "property". The Java translation is a single getter, with no way to set the value from outside the class.


That's not really true. Why would you need a getBar() method in Java?

    public class Foo
      int bar;
      
      public Foo(int initBar) {
        bar = initBar;
      }

      public static void main(String[] args) {
        System.out.println(new Foo(42).bar);
      }
    }


1. bar's visibility is package local, so your code is already broken, bar is invisible outside its package

2. let's say you solve this conundrum by making the field public

2.1. This piece of code is now frozen solid, you will not be able to ever refactor it (where refactoring is defined as changing implementation without changing behavior) since you can not transparently swap fields and methods in Java

2.2. This piece of code is dead to abstract types, as fields can not be part of interfaces in Java.

2.3. This piece of code is incompatible with Java Beans and will therefore be unusable in e.g. JSP taglibs


JSP taglibs? wtf are you talking about. I'm in no way defending the idiocy of 'enterprise java'.

and your other points don't really make any sense at all. There is no such thing as 'fozen solid code'. Unless you're interfacing to external libraries etc and have agreed on a specific API, which is unlikely to include "yeah just reference 'bar' directly" unless you're insane.


until java has a var keyword and closures, there is no way you can claim that it's less verbose than languages like ruby or python.

I can't count the amount of time I wasted typing things like

  LongVariableName longVariableName = new LongVariableNameImpl();
as a java programmer. Also the amount of extra typing for creating anonymous inner classes made GUI coding a real chore. Sure your IDE can automate lots of it, but emacs automatically types end for me when I type def so it's not even a consideration.

Your comment comes across as someone who is either trolling or has no real experience in a language outside of java.


1) If you're reading bad code, that could be a problem. But 99% of Ruby code I read has been written by people who know when they need parentheses/brackets to make the code readable (e.g. when it's not the only code on the line.) But there are tons of times when it's wonderful to be able to leave out the parentheses.

    -
2) It might be because I spend a lot of time with Ruby, but I much prefer `end`s to curly brackets, they're just easier on the eyes, especially when they're going to take up the entire line anyway:

    a
      b
        c
          d
          end
        end
      end
    end


    a {
      b {
        c {
          d {
          }
        }
      }
    }
Of course, at times I wish Ruby used indentation to declare structure, like Python.

    -
3) I don't think I've ever had that problem. If I'm calling `person.full_name`, I don't care if that's a variable, or a method joining first_name and last_name. And if I it was a method, ideally I'd have a corresponding `full_name=(str)` method defined too, so `person.full_name = "Joe Bloggs"` would work, and split the string into the first, last, and optional middle names.

    -
4) Why? Why not? What makes this easier to read?

    puts "Bankrupt" if balance <= 0.0



Ruby is a lot like the English language; when you're learning it as a second language, you're constantly confused and frustrated by it's weird syntax, but once you get past those initial hurdles, it just clicks. I love Ruby because I never feel like I'm programming in it, it almost feels like pseudo code that's not going to actually execute.

Essentially you could get any non-programmer to solve a problem on paper, and turn it into Ruby code which, without too much fuss, describes their process.

    # get the customers text file
    # each customer is on their own line, w/ their name and age separated by a comma
    # group the customers by age
    # show me the top 3 most common ages

    file = File.open('customers.txt')

    customers = []
    file.each_line do |line|
      name, age = line.split(",")
      customers << {:name => name, :age => age.to_i}
    end

    grouped_ages = customers \
                    .group_by{ |c| c[:age] } \
                    .map{ |c| [c[0], c[1].size] } \
                    .sort_by(&:last) \
                    .reverse

    grouped_ages.first(3).each do |age, size|
      puts "#{age} years old: #{size} customers"
    end
    
Four blocks of reasonably clean code (except the 3rd, that could be cleaned up a bit), which implement the four lines of plain english instructions.


>I love Ruby because I never feel like I'm programming in it, it almost feels like pseudo code that's not going to actually execute.

Uh, you realise that describes any high level language, right? Ruby scores pretty low on the readability scale, about halfway between Perl and Python, but I find it's more familiarity with a particular language that determines how readable people find things.

Here's a quick Python version. The main thing to notice is that while the overall flow/structure is similar, I don't have a lot of { } << \ characters hanging around, and I don't have to chain blocks together since I have list comprehensions.

    from collections import defaultdict

    customer_file = (line.strip().split(',') for line in file('customers.txt'))

    grouped_ages = defaultdict(list)
    for name, age in customer_file:
        grouped_ages[age].append(name)

    age_lengths = sorted( [(len(names), age) for age, names in grouped_ages.items()], reverse=True )
    for length, age in age_lengths[:3]:
        print "%s years old: %s customers" % (age, length)


>Uh, you realise that describes any high level language, right?

I'm inclined to agree. I think the following also pretty closely matches the english requirements.

    (with-open [rdr (reader "customers.txt")]
      (->> (line-seq rdr)
        (map #(second (.split % ",")))
        (group-by identity)
        (map (fn [[age coll]] [age (count coll)]))
        (sort-by second (comparator >))
        (map first)
        (take 3)))


Looks kinda nasty to me, but then I'm not too familiar with Clojure/Lisp/whatever-the-hell-that-is ;)

I think one of the side effects of learning a Lisp is that you get a bit blasé about using map. Do you find list comprehensions easier than map/filter? Is there a list comprehension equivalent in Lisp, or would you have to write your own?


It's clojure.

As for preference, given that map, filter, etc., are lazy, I like the clear visibility of each step working on each element of the sequence.

Clojure has a list comprehension, for, though using it here is more trouble than it's worth since you have to group and sort, both of which require you to step outside the comprehension and work on the whole list; that's why your code has multiple sections.

Instead, I see the example as just a selection/transformation process on sequences of data. Each step in the clojure code takes and returns a sequence of values (the ->> macro weaves them together):

  0. a sequence of lines from a file
  1. a sequence of age strings
  2. a sequence of [age, [ages...]] tuples
  3. a sequence of [age, count] tuples
  4. a sequence of [age, count] tuples sorted by count desc
  5. a sequence of age strings
  6. a sequence of up to 3 age strings
Fun detail: The with-open macro is akin to python's with statement, supports arbitrary number of items, is closed in reverse order of their appearance, and didn't require a change to the language to implement ;)


I wanted to reply to anthonyb's comment about macro use changing the language in the clojure example but couldn't, I guess because it's too deeply nested.

Anyway, ataggart didn't write a macro he just used one that's already part of the language. Using a macro does not count as changing the language.


He was talking about with-open not needing a change to the language to implement. In other words, Python's with statement did need a change to the language, but then Python is a (semi-)interpreted language written in C, so it's a cheap shot - just what I'd expect from a dirty Lisp hacker ;)


Well, you need to sort by occurrences, so you have to work with the whole list in this particular case. I also don't think that having two sections is a particularly big deal, since semantically you're working with two separate things too (the list of people+ages, and the aggregated list of names+a count). If you wanted to do something else too (say, list the names as well) then having an intermediate form can come in handy.

Also, I'm pretty sure that writing a macro counts as 'changing the language', although that line's a bit blurred when you're talking about lisps ;) ;)


Note, I wasn't criticizing the python implementation. It's a perfectly reasonable way to model the problem.

You brought up list comprehensions, and something about being "blasé about using map". I wanted to show how a different way of modeling the problem yields a different structure to the code (namely, as a chain of transformations on sequences).

One is not better or worse than another. One of the things I enjoyed most about learning clojure was forcing myself to think in these different ways.


Well, I was comparing it to something like Java. Though Python still scores far lower on my readability scale. It's seems like it's halfway to being minified, the lines are chock-a-block.

Also, this is a better version in Ruby:

    file = File.open('customers.txt')

    customers = {}
    file.each_line do |line|
      name, age = line.split(",")
      customers[age.to_i] ||= []
      customers[age.to_i] << name
    end

    grouped = customers.sort_by{|age, names| names.count}.reverse

    grouped.first(3).each do |age, customers|
      puts "#{age} years old: #{customers.count} customers"
    end

…not sure what I was thinking before, it was late.


> Python still scores far lower on my readability scale. It's seems like it's halfway to being minified, the lines are chock-a-block.

That's likely because you're not used to reading Python. For me, Ruby seems unreadable - you have all these weird << and ||= assignments, {||} blocks, etc. I don't parse those as well, because I don't program much Ruby. I'm sure if I did, it'd make a lot more 'intuitive' sense - ditto for you and Python's list comprehensions.


<< and >> are rudimentary it's almost always exactly the same as unix dated from 1970's redirection. e.g: $ echo 'crap' >> somefile.txt. ||= reads as 'or equal', simple.


Yeah, I know what they do - eg. ||= being a Ruby idiom for 'set if this currently evaluates as false'. The point is that because I don't often program in Ruby, it's less readable (for me). Similarly, if you're not used to list comprehensions they'll seem opaque - but I use them all the time, and find them far more readable than equivalent expressions using map/filter.

That said, I do find the more "squiggly" languages (Perl, Ruby, C) to be less readable than the equivalent Scheme or Python, and I suspect that it's because there are fewer weird characters, so it's closer to English.


Where is this readability scale? Would you mind giving a link for it, I wouldn't mind seeing how the 'readability' statistics came to be.


The groupby, if done using itertools, will cut some code.

  from itertools import groupby

  customer_data = (line.strip().split(',') for line in     file('customer.txt'))
  grouped_ages = groupby(customer_data, key=itemgetter(1))
  print sorted((len(list(g)), k) for k, g in grouped_ages)[-3:]


Ah yes, I'd forgotten about groupby. You'll also need to do a

   from operator import itemgetter
as well.


A meta-question: why do people keep downvoting this comment? It's been up and down ever since I posted it. Is it that I'm critical of Ruby? I would've thought that if I take the time to write some code and respond in a rational way, then it should be worth at least a couple of karma. What gives?


Trying to make a programming language modeled on plain english instructions is a recipe for disaster. Perhaps that's why I find your example at the end pretty ugly code.


Ruby can use both "{...}" and "do ... end", with a slight difference between the two (precedence):

    def some_method { ... }
    def some_method; ... end

    obj.something # "something" is allways a method
    # never a var, say accessor (getter, setter &c ...)


Having optional beauty isn't really any beauty at all though.

I'm just more at home with exact, specific concise well structured syntax.

I know it's an extremely unpopular opinion to hold, especially round these parts, but I don't see any beauty in Ruby syntax. Same with Python...


def cannot have {}, it needs ;/end.

{} or do/end work for blocks, however.


indeed, you are right


There's ways to make anything look hideous, as for your points. * end vs {} is one more character, I can't believe I even typed this as it's so stupidly pedantic. * Keywords.


I have a strong dislike for the now-nearly-meaningless terms "beautiful", "eloquent", "elegant" &c. but for me the deciding factor between Ruby and Python for a project (assuming no constraints from libraries required and such) is Ruby's internal consistency. Python is a bit more haphazard; the infamous `len(str)`, to wit.


> Python is a bit more haphazard; the infamous `len(str)`, to wit.

There is nothing infamous about it. It's a multimethod, the designers of Python decided that mandating the same function for everything (via a common protocol under the covers) was better than risking people implementing a thousand different method names. They did the same with the iterator protocol.


I think that is a poor argument since the same is not true of every function. Therefore, it feels inconsistent to me, which is the only basis I can make judgments on.


> I think that is a poor argument since the same is not true of every function

What is not true of every function?


I think the GP was referring to "mandating the same function for everything (via a common protocol under the covers) was better than risking people implementing a thousand different method names".


I wouldn't call Python haphazard, it's just a different approach. Ruby was designed from the ground up as an object-oriented language, and the fact that everything is a method call (message) gives it a touch of consistency. This is different from Python which is a multi-paradigm language. In fact the early releases didn't support objects-oriented programming at all. On the other hand Python may feel more consistent because of the fact that, in contrast to Ruby, there is one obvious way to do something[1].

[1] http://www.python.org/dev/peps/pep-0020/


I think you've answered your own question: beauty is in the eye of the beholder.

That said, I think Ruby is beautiful for a few reasons, but they mostly stem from the fact that Ruby strikes the perfect balance between Lisp and Other Languages: it's taken just enough of the good parts of Lisp and grafted them onto a more 'usual' language. Maybe 'grafted' is too harsh, it's Lisp _from the perspective of the rest of the world_. It's taking Lisp's ideas through a slightly different lens.

Whatever, I'm almost rambling. You get the idea. Some people think Java is beautiful, too...


It's mostly taking Smalltalk's ideas, not Lisp's, and it's crashing those ideas from orbit into Perl, of all things.

Ruby doesn't have Lisp-style lambdas, or macros, or conses, it has blocks and messages (it tries to anyway) and classes. That's the Smalltalk recipe book. Ruby uses `select` and `reject`, `collect` and `inject`. Those come from Smalltalk's collections.


Broad generalizations are always false. Smalltalk's influence on Ruby is undeniable, but matz has specifically said Lisp influenced him, as well.

You're speaking of Lisp's _features_, I'm talking about Lisp's _ideas_. It may not have 'Lisp macros,' but it does embrace metaprogramming, for example.


> Broad generalizations are always false

Are you reminding yourself of that issue?

> but matz has specifically said Lisp influenced him, as well.

He might have said that, but I don't see it. Then again, considering what he did to Smalltalk it might be very, very well hidden. And in a pretty sad shape.

> You're speaking of Lisp's _features_, I'm talking about Lisp's _ideas_

They're in the same state.

> It may not have 'Lisp macros,' but it does embrace metaprogramming, for example.

Lisp metaprogramming is macro-based, unless you're getting into CLOS.

Smalltalk's metaprogramming is based on metaclasses and "unhandled message" forwarding.

Guess which one Ruby has?


> Are you reminding yourself of that issue?

Both of us, yes. My original comment was painting with a broad brush, and your follow-up is too.

> Guess which one Ruby has?

You're still speaking around me. The implementation of Ruby's metaprogramming is irrelevant, it's the place of prominence it's been given in the design and culture.


I find the beauty of Ruby to be in its object orientation model. The underlying simplicity of Ruby's Modules, Classes and Eigenclasses, and the richness of the architectures they enable is quite elegant and inspired.

The rest of the language is definitely more about pragmatism. How could it not be with the Perl legacy?


I really didn't like some of his examples (especially the part containing 'longer_than_5', that was hideous IMO!) He tried explaining Ruby's simplicity…by using some of the most confusing idioms.

For example:

    array.select &:even?
Is really just:

    array.select{|n| n.even?}
I generally always use the latter. It's just cleaner. I hate overly clever code.


Which of these Haskell examples do you prefer, then?

    filter even xs

    filter (\x -> even x) xs


Overly clever or confusing to you, idiomatic to others (and vice versa).


The former isn't guessable unless you know special modifier characters. It's also error prone if you typo a single character.

The latter is readable.


That's true, but the modifier character* (not more than one) is consistent: & says "take the named method, call to_proc on it, and pass it in as a block". Since many methods allow blocks to be passed to them, this kind of code is useful and well-understood, I think.

I want to note that the &:even? idiom is only used in the simplest cases.


You're contrasting "not guessable" with "readable." The behavior of Ruby's `||` is not guessable for a lot of people but it's still quite readable if you know the language.


From Scheme (or even Common Lisp), I would agree with you, Ruby isn't exactly beautiful. But from Java (which the article compares it to), it's glorious.


Nobody could possibly gainsay that. Java is hideous.


I could. Java is beautiful compared to Ruby in a lot of ways.

http://news.ycombinator.com/item?id=1948234


I'm not saying you're wrong: I have been using python for so long, there are undoubtedly problems with it which I am so used to I just don't see them. But I'm curious about why python has a reputation in the ruby world as ugly.

And yes, installing scipy from scratch is a bear. If you're using a modern linux distribution, you probably want to install a python scipy package.


I can't speak for the 'Ruby world', but the loss of blocks is significant. Significant whitespace makes code ugly sometimes. "There should only be one way to do it." is wrong. Basically, Ruby values _flexibility_ above all else, and Python introduces unnecessary rigidity, which feels 'wrong' to a Rubyist.

And that's another difference between the two communities: Gems are always installed through Rubygems, no exceptions. Distribution's packaging systems (I'm looking at you, Debian) have always just screwed things up, and so Rubyists tend to just remove any system Ruby, install rvm from source (which entails running one bash script), and doing it all through there. Then, everything works great.


That quote isn't quite correct. The PEP quote is:

"There should be one-- and preferably only one --obvious way to do it."

The "obvious" portion of that makes it a little less strict than your quotation. I think it is a "good" axiom to try and aim for. The problem is people think differently and you can't force that really.

I like Perl, where almost anything goes, though. :)


    The "obvious" portion of that makes it a little less
    strict than your quotation.
The "obvious" portion is what makes it such a problem. If you have one library for a task, then the choice really is obvious. If you have two libraries, each very good but offering different takes on servicing a task, then "obvious" becomes a problem, and if "obvious" is a goal then one of those libraries becomes a problem.

"Obvious" is a problematic goal much like "fair" and "equal" are problematic goals in society. You end up sacrificing much that is good and valuable in pursuit of what is often a vague and situational ideal.


Yes, obviousness is subjective. However, we're discussing what makes a programming language good. Goodness is subjective too, is it not?


The problem is not that it's subjective, it's that it leads to unintended conflicts when you try to enforce it.


> Yes, obviousness is subjective.

The subjectivity of the obviousness being nicely handled by the next stanza:

> Although that way may not be obvious at first unless you're Dutch.


I only know a little bit of Python so far, but I think it's things like the "underscore methods" (__len__, __cmp__, __init__) and the lack of blocks (which give Ruby a kind of elegant unity).

I do think, though, that Python's list comprehensions are quite beautiful, and I'm looking forward to using them.


To some extent: the underscore methods represent 'magic behaviour' i.e. this gets called implicitly by something else, you never call this directly.

i.e you write 4+2 to add things not 4.add(2)


Is this kind of magic irreversibly baked into Python, or can you make your own magic? One of the things I love about Ruby is that you can make your own magic, because a lot of the "magical" methods that you define (initialize and <=>, for instance) are just, by convention, the methods called by some module or class or whatnot, and you can write your own mixins or do metaprogramming to change up that behavior.


Sure, you can do most of Ruby's wacky tricks in Python, it's just not usually recommended:

    >>> class Foo:
    ...   def __init__(self, name):
    ...     self.name=name
    
    >>> a1 = Foo('Alice')
    >>> a2 = Foo('Alice')
    >>> a1==a2
    False

    >>> Foo.__eq__ = lambda self,other: self.name==other.name
    >>> a1==a2
    True


Blocks are indisputably useful, but beautiful? There's no shortage of rants on the bizzare inconsistencies between blocks and proc and lambda (do I use call or yield? can I use return? why does arity checking rarely work?)


Maybe it's me but I find those underscore methods very helpful while skimming code.. They clearly point out the "magic functionality - probably adding syntactic sugar" declarations, helping me focus to the actual interface of the class.


I think len() being a function instead of a method, explicitly specifying self for each method and other inconsistencies(albeit small) lead rubyists to think of python as ugly. I'm no rubyist(I prefer expediency to elegance, hence python over ruby), so take this with a grain of salt.


I think the relationship between lists, iterators, and generators is one of the greatest features of Python. I think len makes sense as a function in the same way the sum function makes sense as a function. Both do an operation on any eager iterable, including ones that don't store or "know" their own length.

The explicit self for methods comes straight out of the Python "rule" that explicit is better than implicit. Python is purposefully putting explicitness ahead of beauty, and I agree it's not particularly beautiful. Something that I find even less beautiful in Python is its super syntax:

super(theClass, self).method()

I'm still relatively new to Python, but I would argue that the super syntax goes a bit too far in explicitness (and I think it's fair to argue the same thing for the "self" in methods). Incidentally, there is a PEP (Python Enhancement Proposal) from 2007 to make super just work as super().method().

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


Ironically for people still criticizing "len" as a function, it is now the more acceptable way of accomplishing the task than what Ruby is doing in many circles. In Python, len is a generic function that can call anything that implements a certain interface. This is more correct that baking the "len" function in somewhere in the object hierarchy, or implementing it relatively randomly throughout the hierarchy with a series of "len" methods that may or may not actually be connected. (len isn't the best example since it's in the "standard set", but in general just because two methods have the same name doesn't mean, well, anything in particular, really.) Favoring interfaces over inheritance leads you to the Python solution, not the Ruby solution. Python's arguably not merely "OK" but more right than Ruby here, if you are really going to be an OO purist (of certain flavors).

Python then actually ends up taking advantage of this by having len able to use any of several interfaces. It may call double-underscore-len, but it may also traverse an iterator. It could potentially do other things as well. It's actually a straightforward application of the "prefer interfaces over inheritance" to the dynamic language case. You can criticize the spelling of the double-underscore methods (which if you are really grumpy, can actually be fixed by a metaclass, though I think the cost/benefit tradeoff is bad unless you are the only person who will ever use that code), but if you haven't used them you may not realize just how finely tuned they are, and how well they work with the functions that actually search over the interfaces to find the best one to use in a way somewhat difficult to replicate directly with a "method".


    Python's arguably not merely "OK" but more right than
    Ruby here, if you are really going to be an OO purist 
    (of certain flavors).
Ruby's flavor is primarily that of sending messages to receivers (hence parens being optional). Python seems more about invoking methods on objects.


I don't think I'd call len pure for OOP. Rather, having a top-level definition--len(array) instead of array.length--gives us functional purity. That is, it discards (or hides) the concept of message passing and treats top-level methods like mathematical functions.

Lately I've heard a lot of chatter about Ruby Interfaces. They could be useful to achieve better unity. Though the Ruby collection API is already pretty consistent.


There are two nice things that you get with an explicit "self":

* You can nest classes and methods. This is ugly, so I never use it except in testsuites where declaring a mock class right in the test method is the best way to do it, but it's great to have "self" be the testcase and "xself" be the mocked method.

* There's no such thing as a magic variable. Every name you can reach is declared somewhere, either locally, globally, or from `__builtins__`. If self were automatic, then it would be invisible like the builtins, but it would change depending on where you used it from. The consistency is worth the minor inconvenience, IMHO.


the thing is, self being explicit makes it more consistent

unlike 'self' in other languages as a keyword, 'self' is just a variable with the same scoping.

i.e self always refers to the most inner scope in other languages (a special variable), meanwhile self in python is wherever self was bound in the current scope.

and fwiw: len is a holdover from earlier python (you can define a method __len__ if you want...)


> len is a holdover from earlier python

No. len is basically a multimethod.

> (you can define a method __len__ if you want…)

You have to, it's part of the length protocol, `len()` will not work if you don't. Because `len(o)` calls `o.__len__()`). If you start calling underscore-methods directly (outside of a super() access), you're heading for trouble with your coworkers.


Once you make a parameter special, subsequent effort to hide that it is special seems odd. The self parameter looked different in the call to the function.


I shunned py because:

    each(list) vs list.each
    def(self, args)
    __ugh__
    can't do templates (erb?)
    dislike object model (objects != functions etc)


In Python, though, there seem to be competing managers (easy_install and pip) and separate ways to package libraries for uploading. I’m also hearing names like setuptools, distutils, distribute and virtualenv, and I have to say that the whole ecosystem isn’t too clear to me yet. And the documentation tends to assume I know what all the above mean already!

This also bugged me the last time I wrote any Python code. I decided the sensible response was to go write Scala code until the situation resolved itself. Has it?

(I hope Python never acquires the problem C has, where its users are scattered so far and wide that every halfway valid tool attracts enough satisfied users to sustain itself, preventing the community from being coherent enough to advance in any direction at all. Guido needs to be a Ghengis who keeps all the tribes pulled together and galloping in the same direction, not scattering into disconnected groups.)


Those names are not all disjoint. pip has superseded easy_install, so you should use the former, distribute is a way to write setup packages (pip only installs them), and virtualenv is a way to avoid messing up your system with packages by installing them to a single, self-contained directory.

There's really no fragmentation whatsoever that I've seen. Install a package using your preferred way, in the end everything installs fine whether it's built with setuptools, distutils or distribute (or just copy the files to your site-packages directory). I haven't read the entire blog post yet, so I haven't gotten to the part you quote, but that's my two cents.


Actually, there is fragmentation: pip does not supersedes easy_install, since easy_install does things that pip cannot do (like installing from something that is not a source tarball). Also, distribute being a fork of setuptools, with neither distribute/setuptools being a superset of each other, means more fragmentation as well.

Also, the affirmation that everything install fine whether you use setuptools/distribute/distutils is simply not true. We get almost daily bug reports/user complaints in numpy/scipy because of installation issues mostly caused by distutils, or people using pip/easy_install (which does not work with numpy distutils extensions). The situation is confusing for a lot of users, especially the ones who are not super familiar with python.


Python packaging is indeed a mess. The scipy community in particular is acutely aware of the issue - distutils and all the cruft on the top (setuptools, pip, etc...) are not robust and extremely adverse to extensibility.

This is a complex issue, though, especially if you want to play well with native tools on each platform. It does not help that python packaging tools have been created by accretion instead of begin designed around simple, robust principles.


For anyone who wants to help Python wrt packaging, get behind [Tarek] and his work on distutils2. That's the future of Python packaging (with Guido's blessing) [^1]. More info on python packaging temporarily at http://guide.python-distribute.org/ .

There's also a [packaging discussion group] which seems to be primarily focused on distutils2 development.

[Tarek]: http://ziade.org/

[^1]: http://tarekziade.wordpress.com/2010/03/03/the-fate-of-distu...

[packaging discussion group]: http://groups.google.com/group/the-fellowship-of-the-packagi...


I am aware of distutils2 - the consensus in the scipy community is that it won't improve the situation at best, and will most likely make it even worse.


Sorry, didn't mean to address you personally. Edited my post.

Also, will study your Oct. 13 blog post on the matter to learn more about the issues.


ah, sorry for the misunderstanding. Note that I don't pretend to be authoritative on the subject (although I think it is fair to say I am within the scipy community).


Instead of:

  public int[] filterEven(int[] array) {
    aggregator = int[array.size()]
    for(int i: array) {
      int aggregatorSize = 0;
  
      // The next line is the only unique part of
      // this function!
      if(array[i] % 2 == 0) {
        // Someone please tell me there's an easier way
        // to append to an array than this
        aggregator[aggregatorSize] = array[i];
        aggregatorSize += 1;
      }
    }
  }
  
  int[] array = { 1, 2, 3, 4, 5, 6 };
  filterEven(array);
  // => { 2, 4, 6 }

in Java, you'd normally use collections and not arrays.

So it'd be:

  List<Integer> result = new ArrayList<Integer>();
  for(int i : argument) if(i%2==0) result.add(i);
So it's really 2 lines, not 7.

And if you really needed to work on an argument passed in the form of a primitive array, you'd use Arrays.asList(arrayArgument) to easily turn the array into a list.

Java really shines when you are doing multithreaded code because you have a rich set of thread safe collections. (e.g. multiple simultaneous requests in a web app all modifying shared data structures).

With reading something into a file, anyone that does this often will just use a library (either their own or a 3rd party one).

Thus, they'd just do:

  String data = FileUtil.readFile("abc.txt");


Agreed. A lot of complaints about Java are because of shit APIs (standard library) rather than the language itself.

It's certainly possible to write beautiful code in Java, it's just not very common :)

One thing that Java could benefit from greatly would be type inference. That alone would remove so much syntactical noise.

Honestly, who cares that you need to write a Main class? This is quite commonplace, and only really inhibits scripting tasks. In any real application, this is a non-issue.


Duly noted. I asked for alternatives because idiomatic Java eludes me. Thanks.


I think the author has done a great job pointing out a need: science tools for Ruby.


There was a similar discussion elsewhere about this. Short version: what's the point in developing them? Despite what ardent proponents of either will tell you, they're essentially the same language. Porting code from one to the other is straightforward or trivial. Learning one with a background in the other is a matter of days.

I get it for the FORTRAN -> Java transition; I understand that you'd want to port your stuff to Python from Java. But why would anyone port massive and complex libraries (SciPy is not your regular "Yep, coded that in 4 days!"-gem) to a virtually identical language? [1]

No point. Learn Python, and get some stuff done.

[1] Now, if you're about to build a good scientific/numerical/statistical/(...) library for Clojure -- I'm all ears.


I am, in fact, trying my hand at stats in Clojure, to see if it's a viable alternative. I finished the Wilcoxon Rank Sum Test yesterday, and it's ridiculously elegant compared to the current SciPy implementation. Clojure is pretty fantastic.

But where's the package management? Clojure might be a bit too young.


clojure package management is built on top of maven typically. There are two main approaches here:

1. Use Maven as Maven with https://github.com/talios/clojure-maven-plugin - My impression is that this option is often more popular with people coming to clojure from java, as you get the full XML and maven experience.

2. Use Leiningen https://github.com/technomancy/leiningen – this is a project and dependancy management / built system built in clojure on top of Maven's libs. You have a single (and simple - no XML) project.clj file that describes your project. My impression here is that lein is popular with people coming to clojure from non-JVM land. Being a former pythonista, this is my preference.

There is also a default maven repo that i believe both work with hosted at http://clojars.org.

In both cases maven handles dependency resolution and package management. My experience is that a global install of jars is not common like it is in python or ruby land.

The other tool that you will want to look at is https://github.com/liebke/cljr which is a repl built ontop of lein's package management commands. This is useful because it lets you run a repl without a project (lein requires a project) but still gives you control over what libraries are available. If you are using incanter (the stats package mentioned by Estragon) you will want cljr


I'm using Leiningen at the moment, but I don't like importing my dependencies into my project folder. That's why I said "centralized package management". Is there a way to store all your dependencies in a central non-project-specific folder?

I'll have to check out cljr.


  ...if you're about to build a good scientific/numerical/statistical/(...) 
  library for Clojure -- I'm all ears.
Presumably you're aware of Incanter (http://incanter.org/), which wraps scientific libraries for Java.


I still think Ruby is a little too "expressive" to be taken seriously is scientific circles. In my view, DSLs are not a positive feature in academic work, because everybody's D is different from the next guy's. This is why the linga franca of almost all algorithms papers is, in fact, pseudocode. Python is sufficiently structured that it practically reads like pseudocode.


Yes, but Perl has a huge scientific following as well, so Ruby should be able to used there as well. However, I think with Python and Perl in that niche, it would be hard for Ruby to break significant ground there unless a RoR moments hits for that area with Ruby.


Right, so i agree with the author on this front, but it's not to say that there are no tools with which to do analysis, but many of them are pretty rudimentary.

I'd love to see more people pitch in and help develop tools that would make scientific analysis easier.

I did a presentation at RubyKaigi on this general subject actually: http://www.slideshare.net/knowtheory/mapping-the-world-with-...

(and a video: http://rubykaigi.tdiary.net/20100829.html#p09 )


'I love that I can define + for any object in Ruby and that doing so gives me += for free.'

fwiw: this works in python too

>>> class Foo(object): ... def __add__(self, x): ... print "%s+%s"%(self,x) ... >>> a = Foo() >>> a+=8 <__main__.Foo object at 0x657d0>+8 >>>

You can override __iadd__ separately too.


I think there's always been a bit of 'grass is greener' sentiment between the Python and Ruby communities. As a Python guy I do appreciate the look of Ruby code.

However for sheer pragmatism Python wins; almost every API and library you can think of has its own Python bindings.


Hmm, not for me. I think things like paren-free function calls are awful for readability and

    array.select &:even?
is far, far less clear to me than

    filter(even, array)
Ruby just seems to have tons of unnecessary syntax, I guess.


A lot of 'unnecessary' syntax is comming from the fact that block forms 'do..end, {}' are not objects in Ruby.

I wish Ruby implemented them the same way as in Smalltalk, to be used as objects passed to a method's arguments.

All the 'do..end, {}', '&', 'yield', block_given?, etc. would have been gone. And there would be just one unified way to construct and call a block.

This is the only part of the language I find wrong in Ruby. Any Rubyists share the same feeling?


Yes. I have a feeling it's not even an uncommon sentiment among Rubyists. Ruby's implementation of blocks was a huge chunk of technical debt that it incurred early on when it kind of wanted to be Perl, and all the attempts to patch it up while maintaining backwards compatibility have made it a hugely complex corner of the language. Ruby would be vastly less confusing if they threw out all the current syntax and semantics of blocks, straight-up aped Smalltalk's, and unified them with methods.


> However for sheer pragmatism Python wins; almost every API and library you can think of has its own Python bindings.

This is largely true for Ruby too. Both have great C FFIs, so it's not hard to write these kinds of wrappers. I've never been wanting.

I don't think you can really call this a general win for either language, though Ruby does tend to lose out to NumPy and SciPy (from what I hear).


This is the reason I stuck with Python for my development and production code. Python scientific programs running on the backend, using all sorts of fancy libraries (NLTK and numpy mostly) and then a Django frontend that plugs right in.

I'm dabbling with RoR and it's certainly pleasing at times, but there are the odd bits of Python I keep running into that make me smile too. Especially map. :]

To me it seems that half the anti-Python sentiment is because you can write some truly terrible Python code, just as you can write some truly terrible Java code. You can also write some elegant Python code (although there are some situations where you just will run into those damned underscores), but it's in the minority.

Coming from Perl (no, really) and Python, my main issue with trying to learn Ruby is all the extra syntax and punctuation. It just looks and feels wrong until you force your way through it and see it from the other side. There are some really nice advanced features of the language (I sat in on an advanced Ruby class and found it surprisingly easy to follow given a background in ML, Perl and others) so I'm still going to persevere and learn it, but I'm still at the "Ruby feels arse-backward" stage. I think to me Ruby feels like Python does to Rubyists. Sort of.


Map isn't really an "odd bit of Python" that you ran into, it's a bit of Lisp.


Actually, I know it from ML. I was more smiling at it existing in Python, than Python having 'invented' it.


Or you could use Ruby where it continues to make the most sense and use Python where that makes the most sense. After all, the languages are so similar that keeping them both in the tool belt has less mental overhead than say Ruby and Scala.


As a Ruby programmer, I think it's great to learn Python. While they are similar, there are many differences, and even some advantages to Python. Plus, it never hurts to add to your resume! Finally, Python is usually installed on more systems than Ruby, so if you do lot's of systems administration, you don't have to worry about adding another package.


I'm not sure why this is bugging me, but p and puts are not the same thing in Ruby. In most non-debugging contexts, p 'hello world' would be odd since it would print the string for inspection (i.e. with the string literal quotes around it), no?


Yes, that's true. And since I used println in the Java example, I guess I should switch the Ruby example to puts. Will do that now.


Why is the website telling me I'm an administrator?

http://d.pr/wfTk


I'm having cache problems, sorry! (This is my first production app.) The problem should be solved for now, though I had to turn off caching to fix it.

Urgh, Rails...


No apologies necessary. I just wanted to make sure you saw it in case there was a hole you needed to close.


You can't use static page caching, but rails caching should work fine if you use administrator status as a cache key.


"Urgh, Rails..."

You can hardly blame Rails for your programming error.


That was just a comment on how easy it is to screw up caching in Rails. I acknowledge it was my fault.


Title is a little flamebaity, considering it seems like he is adding python, rather than "moving to".

I like both, but Ruby does it for me bigtime. I actually wish it also had Python's whitespace rules, but since I use Haml a lot I still benefit from it sometimes.

One important facet of Ruby is that it was written to optimize programmer happiness. As a result, it is a lot of fun to code in. The article's author says something similar himself:

"Now, I want to be clear: I like Ruby better than Python. Its semantics make more sense to me than Python’s, and the language itself is more beautiful."

As someone who codes between 2 and 20 hours a day, a language like that is where I want to be. Ruby does have its gaps so other languages are needed too - I use actionscript for front-end stuff (instead of MacRuby) and functional languages for concurrent programming (instead of EventMachine).


Using Ruby extensively with CoffeeScript is also making me long for significant whitespace. I think CoffeeScript gets it perfect. Unfortunately, it's just a wrapper around JS so it has limited uses (until Node.js gets mature).


Haven't checked out CoffeeScript before, but it's very terse. Me like.


Yes, I am not sure why one would "move". Learn Python, presto, you now know two handy languages and can use them at your discretion.


That's valid. I'm adding it, not moving. That sounded weird for a title, though.


I'm not a scientist but this article got a really valid and good point. I only know about this Ruby-lib within the scientific context:

http://www.wedesoft.demon.co.uk/hornetseye-api/files/Hornets...

One thing that hit me though. The author of the article maybe should consider a little effort. I mean...libraries for scientists should probably be developed by scientists (the target group), which means it's an excellent opportunity for the ones that identify the problem to get something started. No code falls down from heaven. Supply and demand.


How does Python's science libraries compare to Java's?

If they're comparable, why not use JRuby and use all the Java libs you want?


An unsatisfying article. Judging from the code, I am not convinced that the author gets Ruby. At the very least, Proc#curry doesn't make a very compelling example.


I'm sorry you feel that way. What about that example makes you think I don't understand Ruby? Composing functions (and currying in arguments one at a time) is probably one of the more powerful things you can do with the language.

I wasn't saying that is how I would implement filters. Just that that is the DRYest way to do so--and it's easy in Ruby.


You have nothing to be sorry about. If I had noticed that this was a self-post I would have phrased my response more personally and (hopefully) with more tact.

I'm not looking to second guess each of your examples, many of which were fine. I felt that your currying example was trying to bring in a purely functional toolkit ala Lisp when it wasn't appropriate. Function composition (which you allude to in your reply, yet I don't see) and blocks (especially!) show off Ruby's functional capabilities quite well and would be just as effective and more practical.

Btw, if you're quite new to Python, do yourself a favor and learn about list comprehensions. They can be quite wonderful.

Good luck!


Ah okay, I think I see your point. The currying example was intentionally Lisp-inspired. I didn't mention this, but I've also just started to program in Clojure--though not for work.

As I say, I wouldn't use that last technique in my actual code. It just shows how powerful the language actually is. I think my normal code falls in line with the standard Ruby paradigms, but with a functional twist.

And yes, list comprehensions are fantastic. :)


Comparisons between Java with exception handling and a scripting language with a one liner that does no error checking are pretty worthless.


The point is: when I'm writing a script (or better yet, doing this interactively), I don't want error checking. I see an error, and I fix it. This article centers around agile scripting for science, not building enterprise applications or libraries.

The point is not that the two samples are exactly equivalent. The points is that you can go no simpler with Java's standard libraries.


Au contraire, I am of the opinion that checked exceptions are the scourge of Java.


What are good alternatives for data crunching? Incanter suitable yet?


guys, sorry beautiful and sexy are not for Programming Languages. Really.





Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: