Hacker News new | comments | show | ask | jobs | submit login
Ask HN: What does Ruby have that Python doesn't?
66 points by globalrev on Aug 22, 2008 | hide | past | web | favorite | 221 comments
About 6 months ago I decided to learn either Python or Ruby because I wanted a language to write webapps and simple computergames fast.

I kind of tried both for a while and Python gave the better impression in every way, readability, ease of use, libraries, documentation, expressiveness etc.

But there are so many really enthusiastic posts about Ruby and while Python has a lot of users and is very popular and successful I rarely see anyone rave about it. But maybe that just means it has gotten mainstream.

But anyway I like the Python philosophy that there should preferrably be one obvious way to do things. While similar in most ways, there the languages differ.

So, what do you Rubyists like so much about Ruby? Especially what do you think Pythion lacks?




What the hell, they're only karma points:

I lived with Python for 4 years before I lost an argument at my own company and had my project moved to Ruby. I've since moved in with Ruby and haven't looked back.

* Everything in Python feels like a symbol table hack. Private methods? We have those! Just exploit this bug in the class symbol table lookup code!

* First-class symbols. There may be little difference under the hood between a Ruby interned string and a Python string atom, but there's definitely a difference syntactically. This is a difference that is hard to articulate, but if you've written much C, it's like having every "enum" you could ever want predefined for you, and completely eliminates "magic numbers".

* Blocks and lambdas. I've read GvR's take on this. I know he thinks a named function is just as good --- maybe even better! --- than an anonymous function. I had nested named functions/functors in C++ and Java. Even Tcl "uplevel" is better than Python's castrated lambda.

* Method definitions in Ruby don't need to accept a "self" argument. Again: all of Python feels like a symbol table hack to me.

* Ruby has first-class Regexps. Python has an "re" library. You know what else has an "re" library? C.

* I haven't found an expression that is better written as a list comprehension than as a map/reduce/select expression.

There are painful things about Ruby:

* The FFI is immature. Outside of Common Lisp, Python ctypes may be the best FFI out there.

* I never got Python to crash on me (at least, not where it was Python's fault). I crash Ruby once a week.

* Ruby is palpably slower than everything. If performance matters to you and you don't know C, you may be better off in Python.

* The community is led by the nose by Rails developers, which can at times feel like a worst-of-all-worlds grab bag of methodology programmers, web designers, and dabblers.


Blocks and lambdas

Yeah, but this is an area where both languages are just a mess. If python's lambda is castrated, ruby's notion of an anonymous function is tumorous. We've got blocks, procs, lambdas and methods? What's the difference?

Ruby mixes up the syntactic requirements of "passing" some code to a loop to iterate with with the data requirements of binding a function to a scope. It's just a huge mess.

LISP and Scheme figured all this out decades ago, and yet only Javascript (and, almost, perl) among common scripting languages has managed to absorb the lesson.


You say "both languages are just a mess" as if to equate the two. But there's no comparison.

Your Ruby problem with blocks and Proc objects is a nit about elegance and semantics. How often does the difference between an actual Proc object and a block actually affect you? More importantly, if the cost of fixing that nit is that we wind up with Lisp's or Javascript's lambda notation, who would accept that? Javascript has relatively consistent semantics for anonymous functions, but extremely clumsy syntax.

Python simply doesn't have real lambdas. It has the ability to pass something called a lambda in place of a function, and that something forces you to think about things like the difference between a statement and an expression. It then tells you that you don't in fact want anonymous functions, but instead you want to define tens of itty bitty named functions and use them instead. You also "want" that "self" argument to all your methods, and you "want" to tack two underscores to the front of your method names to make them private.

So, I half agree with you. Yes, it would be nice if there was a (zero-cost) way of fixing Ruby's block semantics. Yes, I can rely on Lisp's lambda semantics slightly more than I can on Ruby's, which does start to matter when you start writing domain-specific language code. But I don't agree that this has any bearing on the Python vs. Ruby argument. Python lambdas suck.


True python's lambda's suck. And Ruby's lambda's for the most part don't suck.

But ruby's methods really do suck, and so do the complex construction of Blocks. While I recognize that blocks allow you to do weird things (like use return on the calling scope), the fact that they necessitate a special form (yield) and cannot be bound to a variable, and are not passed as standard function parameters just makes them inconsistent and gross.

Methods which aren't first class functions (but can be transformed into one with the helpful helper function!) also suck, and passing those around in a functional way is just a lesson in futility.

All that being said, I have much more faith in these warts being fixed as time goes on, than python's nasty lambda, and the gross over use of dunders.


"the fact that they necessitate a special form (yield) and cannot be bound to a variable, and are not passed as standard function parameters just makes them inconsistent and gross."

Which brings us to another point - when exactly do you actually need them? I have for every 1000 lines of ruby code maybe one line of "yield" code, and this is only to further extend classes for flexibility. Other languages dont allow you to choose what you want to have, ruby does.

You simply have to make decisions when to use what.

For me it is simplicity, elegance and beauty. These are my biggest design criterias.


I'm 100% with you on simplicity, elegance and beauty. I just demand that as much from the design of the languages I use as from my own code.

I've tried to explain it like this. To me ruby feels Turtles all the way down with respect to Objects, but some kind of nightmare tunnel of interleaved beasts down with Functions.

I don't think I should have to make that compromise, so I'll happily go about writing my ruby when I have to, but I'm waiting for the language that is consistent all the way down.

If I could replace every yield I've ever written in ruby with a .call() I would be so much happier :)


> I'm waiting for the language that is consistent all the way down.

Lua is close.


but I'm waiting for the language that is consistent all the way down.

Newspeak is coming... http://gbracha.blogspot.com/


Ok, now I'm not sure I follow. Apart from the performance issues, why can't you replace every method that "yields" with a method that takes the explicit block parameter, and .call() it?


sigh yeah... you could do that, but you often times you have to deal with methods that aren't invoked that way.

http://blog.sidu.in/2007/11/ruby-blocks-gotchas.html

is a good run down of some of the problems here


No it is not. You dodged the question again, by throwing a hardly related blog of someone else at it.

How many people will use yield _AND_ self.send in the same method please?! That seems like an awfully complicated and contrived example. Who the heck does this?


I think the "can't be bound to a variable" thing is a bit of a red herring too, especially if you're OK with Lisp and Javascript's syntax --- you can create a full-fledged Proc object with "lambda" any time you want.

The inconsistency is annoying, but 99.999% of the time, Ruby is actually giving you what you want.


Right, it just doesn't seem to be Ruby style, and it would be nice to be able to use the "pretty" block syntax to accomplish that.


   and cannot be bound to a variable
&block ?


The block itself isn't being bound; it's being converted to an explicit Proc object named "block".


Lua gets it right too.


As does nasal: http://plausible.org/nasal

That's my own language, and quite obscure (FlightGear uses it, and I've done quite a bit with it personally). But if you want to include Lua too, we might as well be consistent. I was trying to stay within languages with which most readers here would be familiar.


As does Eve (http://eve-language.blogspot.com/), as long as we're throwing out pet languages. ;-) Though I just redid virtually everything about Eve (changed it from a multiple-dispatch functional language to a single-dispatch prototype-based functional language) and haven't yet pushed the changes to GitHub.

For that matter, Ocaml/Haskell/Erlang all get it right, and those are not pet languages. And Cecil and Dylan almost get it right, but have some complications introduced by multimethods. So it's really just the popular languages tha screw up.


Interestingly enough the language everyone loves to hate, PHP, as of 5.3 has figured this out as well.


The "self" argument is great. It is the reason why methods in Python are normal functions and not special "methods".

It also makes this pointless but interesting piece of code possible:

  class foo(object):
     def subclassme(self):
          class subclass(type(self)):
              def __init__(self2):
                  self2.parentobj=self
          return subclass()


> Even Tcl "uplevel" is better than Python's castrated lambda.

Tcl, in its own way, is more powerful than both Ruby and Python in that only the syntax is a given. There is nothing special about 'if', 'while', and other control structures, which are not syntax, but commands. Indeed, you can write your own control structure commands in Tcl itself, with 'do ... while' being a classic example.


You can do the same thing in Japanese Tcl using blocks.


Ruby's lambda is worse than Python's.

Can you elaborate on why you think Python's lambda is castrated?


A python "lambda expression" can effectively only be a one-liner - basically the return line of a function minus "return".

That is why people consider them castrated - in most languages I'm aware of that have a "lambda" statement, it can be read as "create an anonymous function that executes this body of statements". In python it reads as "perform a simple transformation or calculation on or with these arguments", as that's all it's generally good for.


I think it is due to the statement/expression dichotomy that Python exhibits.

Python's lambda doesn't allow the use of statements (correct me if I'm wrong I haven't written Python in a few years and they may have "fixed" this).

Meanwhile Ruby only allows expressions too - the catch here is that everything in Ruby is an expression.


A lambda is traditionally a functional programming product--think Lambda Calculus. Functional programming doesn't have statements, and neither should lambdas. Or do you mean anonymous function, in which case you're right.


They don't plan to fix this, it's part of the core philosophy


* Everything in Python feels like a symbol table hack.

>It isn't bad at all. (And does not really matter)

* First-class symbols.

>Ok, but python has first class functions.

* Blocks and lambdas. I've read GvR's take on this.

>GvR is right.

* Method definitions in Ruby don't need to accept a "self" argument.

>It isn't bad at all. (And does not really matter)

* Ruby has first-class Regexps. Python has an "re" library. You know what else has an "re" library? C.

> Ruby has private methods. JAva has private methods too. Therefore ruby is bad.

And so on...

p.s. And if you need oop features why use ruby instead of java?


"p.s. And if you need oop features why use ruby instead of java?"

Probably because he values his sanity.


Why is 'symbol table hack' a 'bad' word? There is absolutely nothing wrong with the way symbol tables are used in python.


More to the point, it's a feature, not a bug. That everything is a symbol table hack makes metaprogramming much simpler.


What's a metaprogramming problem that's easy to solve in Python, and hard to solve in Ruby? Here's a metaprogramming tactic that is surprisingly annoying to duplicate in Python: "method_missing".


OK, show me how -- in Ruby -- to define a class, such that the class and all of its subclasses will have some special non-standard behavior (say, gaining or losing attributes or methods based on other things in the class definition)... without re-opening the class after its original definition or otherwise monkeypatching it once it's defined.

In Python you can fiddle with the machinery that creates class objects and use it to do whatever you need. In Ruby, as far as I know, that's simply not possible.

(and, yeah, you need to look up the attribute hooks in Python, because it looks kinda silly when your cherry-picked examples are of things you actually _can_ do in Python)


I am not entirely sure what you mean, but adding or removing methods from Ruby classes is extremely simple and there are a number of hooks in place that allow you to play with the class definition on inheritance. But here is another example of the power of Ruby metaprogramming. The example is sort of nuts, but something similar is actually used in the Camping microwebframework.

    Blah = {
      :foo => proc { puts "foo" },
      :bar => proc { puts "bar" },
      :baz => proc { puts "baz" }
    }

    def Monkey(method)
      klass = Class.new
      klass.class_eval do
        define_method :shout do
          Blah[method].call
        end
      end
      return klass
    end

    class Chimp < Monkey(:foo)
    end

    class Gorilla < Monkey(:bar)
    end

    a = Chimp.new
    a.shout # => "foo"

    b = Gorilla.new
    b.shout # => "bar"

    Blah[:foo] = proc { puts "I have changed" }
    a.shout # => "I have changed"


Well, except the example you've given isn't really "metaprogramming" in the sense I'm trying to get at. Here's a Python translation which shows why:

    def Monkey(word):
        class _Monkey(object):
            def shout(self):
                print word
        return _Monkey
    
    class Chimp(Monkey("foo")):
        pass
    
    class Gorilla(Monkey("bar")):
        pass
    
    c = Chimp()
    c.shout() # prints "foo"                                                                                                                                                                               
    
    g = Gorilla()
    g.shout() # prints "bar"
In other words, the Ruby code you've provided is basically a class factory taking advantage of closures. The Python example shows that a bit more clearly.

What I'm looking for is something equivalent to Python's "metaclass" declaration, which lets you completely control the way the class object is created. I've been told by fairly knowledgeable Rubyists that there isn't really an equivalent, and that after-the-fact monkeypatching or factory solutions like yours are the only way to come at the problem in Ruby.


Ruby doesn't have metaclasses, this is true. It won't let you subclass 'class'.

However it will let you subclass 'Module', which is the superclass of Class, and you can use this to achieve similar ends if not quite as elegantly.

The way class methods work wrt to inheritance is a bit different in ruby though, and gives you quite a lot of power to provide special behaviours to subclasses via class methods which can be called in the subclass class definition. The kind of "we provide a DSL for you to use in your class definitions to configure the subclass" tricks which (IIRC) tend to require metaclasses in python, don't require them in ruby.

There is also an 'inherited' class method callback on Class, which you can use to run code whenever a new class inherits from your class. And this can be used to achieve a lot of things that pythonistas might use metaclasses for.

On the whole I think anything possible in one language is possible in the other when it comes to metaprogramming, it's just a matter of how you go about it and how elegant it feels.


(where by 'one langauge' i obviously mean one of Ruby and Python)


One thing I dont understand is

print word

where does "word" come from?

Anyway, this setup is in no way different to ruby's super

super("foo") super("bar")

I really fail to see the point here. What is different? I simply do not see what the python example shows "a bit more clearly" here. I dont even get where "word" comes from.

Besides, "monkeypatching" is a deragotary term invented by pythonistas who do not understand Ruby or think that by adding complexity you can feel "meta" programming so clearly. In my opinion the metaprogramming demanding people are wanking hippos that continually feel a need to add needless and useless complexity on top of problems and in situations where there simply should not be any of that.

Both ruby and python are way to complicated. Can you believe this? At the same time, both are a LOT more elegant than languages like perl or php. Perl 6 still has not managed to get rid of the useless ; at line ends. They managed to eliminate () around if's.

Wow. I am soooo impressed. In 100 more years Perl 7 will be THE best language arrr!!!

But it is a shame that there are not more good languagesl ike ruby or python, because in fact there simply are not that many good languages existing anyway. It takes so much effort to grow a language....

And yes - both ruby and python are very good languages. The fact that there are idiots using the language who have a loud mouth badmouthing either of these two decent languages is annoying, but one can not do much about it.

For everyone else I recommend reading the "why it does not matter" blog. It really summarizes a lot of why ruby and python fill a very similar ecosystem, behaving like rivals who continually try to point out how incredibly stupid the other language is.

Grow up. Use what you prefer, and end this stupid war.


> One thing I dont understand is

> print word

> where does "word" come from?

    >>  def Monkey(word):
    >>        class _Monkey(object):
    >>            def shout(self):
    >>                print word
    >>        return _Monkey
Note that Monkey is a function that takes a parameter word. So every invocation of Monkey creates a class that will always .shout() the parameter word.

> Anyway, this setup is in no way different to ruby's super

> super("foo") super("bar")

No.

    >>    class Chimp(Monkey("foo")):
    >>        pass
    
    >>    class Gorilla(Monkey("bar")):
    >>        pass
You'll note that these two class definitions create a class Chimp that's descended from a class like _SomeMonkeyThatSaysFoo, and a class Gorilla that's descended from a class like _SomeMonkeyThatSaysBar.

That is what the parent poster has challenged anyone to reproduce in Ruby.

> Grow up. Use what you prefer, and end this stupid war.

Programming language wars are at least as old as the Internet, so the admonition to "Grow up" hold no water in this case.

I could quite reasonably parody your closing statement as: "Grow up. So who cares whether a hammer or celery makes a better tool? Just leave us alone, hammer-users."


OK. Like so:

module SpecialBehavioursForClass def extended(klass) klass.class_eval { ...do anything you like to classes including these behaviours as though you're in their class definition block itself... } end

  def special_class_method
    ...
  end

  def give_this_class_an_attribute(x)
    attr_accessor :x
  end
end

then

Class MySpecialClass extend SpecialBehavioursForClass

  give_this_class_an_attribute :abc
end

(note how there's already a class method 'attr_accessor' which does this - but just to reinforce how you'd go about making something similar yourself)

then: MySpecialClass.is_a?(SpecialBehavioursForClass) returns true.

However, MySpecialClass.class == Class it's not actually an instance of a metaclass as these don't exist in Ruby.

You can achieve the exact same things though, using Modules, class methods, and the .inherited / .included / .extended callbacks.


Sorry it bolloxed my formatting. Note to these people: tell us how your code formatting works, somewhere near the goddamn input field


I haven't used Ruby enough to have used method_missing, but I have used Python's __getattr__ to accomplish the same thing. Can you give an example of something that would be easy to solve in Ruby with method_missing but hard to solve in Python with __getattr__ ?


Yes: make this evaluate as Python (in Python idiom, of course):

    @bb = Bblock.make {
        push ebx
        mov ebx, dest
        pop ebx
        retn
    }
That's all method_missing.


like EliAndrewC said, __getattr__ is Python's version of method_missing: http://docs.python.org/ref/attribute-access.html

And no, that's not all method_missing. looks like method_missing plus a block.


How do you catch and transform method arguments with __getattr__? For instance:

   mov ebx, [ebp+4]
needs to detect that ebx matches a Register class constant and that [ebp+4] is not an array, but rather a register indirection expression.


__getattr__ needs to return a callable (usually a function, but you can 'call' other objects as well). And that callable will be called with the arguments to the method.

You can do all that stuff with python, though the syntax isn't as loose; you can't omit the () around method calls which is what I think you're doing here in Ruby. That restriction tends to improve readability and reduce bugs at the cost of making it harder to have a truly transparent DSL.


The parens thing is unfair; obviously, without parsing strings (avoiding which is the whole point of metaprogramming), you can't express assembly in Python.

But isn't it surprisingly annoying to do method_missing in Python? Again, you have to catch the exception case to the symbol table lookup, and cons up a callable that knows to catch the arguments the right way.

Here's the entire method_missing call I needed to make x86 work inside a Ruby block:

        def method_missing(meth, *args)
            k = Rasm.const_get(meth.to_s.capitalize)

            # If it's a class, it's an assembly opcode;                 
            # else it's a register or operand.
            if k.class == Class
                @insns << (k = k.new(*args))
            else
                k
            end
            return k
        end


Well, Python has the * args and * *kwargs thing too. So "knows how to catch the arguments the right way" isn't any more of a problem than it is in Ruby. I'm guessing you don't know much about Python; you keep saying "It must be hard not to be able to do X" when in fact you CAN do X.

No, it's not surprisingly annoying. You can override just about anything within the rules of the Python syntax. You can override what << and + and | all do. You can override [] and ().

You just have to live within the Python syntax, which unfortunately for DSLs is stricter than Ruby syntax. But when you're not doing DSLs, that stricter syntax is usually a good thing.


Instead of saying it "...isn't any more of a problem than it is in Ruby" and "I'm guessing you don't know much about Python", why don't you actually show us some Python code which does something similar? I know Ruby well but Python only rudimentarily, so I'm curious what the rough equivalent would look like. If you don't feel like doing that, fine, but I'm just going to ignore your arguments.


His example is too incomplete to translate properly (since I don't know the details of other stuff he's referencing), but the basic idea is this:

A callable object in Python (e.g., a function or method, though not necessarily limited to these) can take advantage of two special options in declaring its argument signature. One is a feature shared between Python and Ruby: you can prefix the final argument with a single asterisk, which will be interpreted as "accept any number of additional positional arguments, and store them as a list in a variable of this name".

So, for example:

    def print_args(*args):
        for arg in args:
            print arg
Which does pretty much what it looks like it should do; you pass any number of arguments, and it echoes them back, each argument printed on a separate line.

The other part is something Ruby doesn't really support, because Ruby doesn't have a true analogue of Python's keyword arguments: using a double asterisk says, essentially, "accept any number of keyword arguments, and store them as a key/value mapping in a variable of this name".

So, for example:

    def print_keyword_args(**kwargs):
        for key, value in kwargs.items():
            print "%s: %s" % (key, value)
If you then did, say, `print_keyword_args(name='Bob', email='bob@example.com')`, you'd get back the output (ordering of items may vary with the Python implementation, but usually you're not concerned with ordering -- that's what positional arguments are for):

    name: Bob
    email: bob@example.com
These can also be combined into a standard idiom for a callable which accepts any combination of any number of named and keyword arguments:

    def takes_any_arguments(*args, **kwargs):
        ...
These sorts of idioms are incredibly useful for dynamic programming; for example, I work with (and help develop) the Django web framework, and our object-relational mapper uses the `kwargs` idiom to set up query methods which dynamically adapt the arguments they accept to the particular data model you're querying against.


> That restriction tends to improve readability and reduce bugs at the cost of making it harder to have a truly transparent DSL.

I used to think this too. But, then I actually learned ruby, and it turns out to be pretty easy to discern method calls from local variables, unless you are working with horridly long methods, which is a separate issue.

Remember that an instance variable is prefixed with @ in ruby, so if you see something that looks like it could either be a method call or a reference to a local variable, it's pretty easy to quickly examine the local scope to check. It's usually so obvious that you don't need to, though.

There are definitely some potentially tricky situations (closures, etc), but in over a year of working with ruby full time, I have yet to encounter one.


  fun1 x

  fun1 x + y

  fun1 x + y.foo

  fun1 x + y.foo bar
What will happen in this perfectly valid Ruby code? Where do the parentheses belong? Do you know off the top of your head?

While any programmer who would write this deserves to be fired, I can't come up with a good reason why it should be valid to write it in the first place.


Yes, I do know where the parentheses belong. Like I said earlier, it isn't hard to read ruby like this once you get used to reading ruby.

> While any programmer who would write this deserves to be fired...

That's exactly my point. The only example you could come up with was a straw man.

> ...I can't come up with a good reason why it should be valid to write it in the first place.

Can you come up with a good reason it matters in practical, real world situations?


Looks contrived, because I dont know many ruby users who would write fun1 for a method. Why? Because in ruby there are methods. You dont find many people doing "fun" for a method - the intent clearly was a "function". But where are they? ;)

Anyway, here is the one that comes to my brain flow naturally. It seems python writers need () in order to feel happy, otherwise they think they get confused about things (hopefully they dont have a small brain):

  fun1 x

  fun1 x + y

  fun1 x + y.foo

  fun1 x + y.foo bar
What will happen in this perfectly valid Ruby code? Where do the parentheses belong? Do you know off the top of your head?

fun1(x) fun1(x + y) fun1(x + y.foo()) fun1(x + y.foo(bar))

Btw you omitted what x and y are. My first assumption is that these must be variables that allow the + method

It does not really make a lot of sense though, give the last example:

class Cat def initialize(name) @name = name end def foo(how = :h) case how when :h how = 'happily' when :u how = 'unhappily' end puts @name+' meows '+how+'.' end end

y = Cat.new 'Tom'

y.foo # "Tom meows happily." bar = :u y.foo bar # "Tom meows unhappily."

x = '"At the end of the day "

x + y.foo bar # "At the end of the day Tom meows unhappily."

etc.. I simply have no idea what fun1 should do. Maybe it will involve Jerry mouse and return a conditional story where it is explained why Tom the cat is unhappy.

Btw this is a really contrived example because I tried to model your stipulation of the above code into this. It really makes no sense at all to use variables without any real idea why one should use that.

Why do people WANT to be complex when simplicity is so much more elegant?


This comment field is not very good, it killed my newlines! :(

I demand the pre tag or a "code" tag or something that allows us to add code nicely formatted :P


Anything indented two spaces acts like it's inside pre tags.

  Like this.
  And This.
  Etc.


Yes indeed. You have phrased it better.


I've somehow forgotten to rant about ruby's totally hackish broken tools for importing code. require and include are just heinous crimes against nice programming. (I /love/ it when I clobber my global namespace with an include in ruby).


That's never caused a problem for me. It's also a tradeoff: in Python, you have to meticulously "import" every symbol you might need, which is tedious. I compared a really good piece of Python code (CORE's Impacket library) to a similar piece of Ruby code (Jamis Buck's net/ssh), and it's 3-1 in average number of important statements per file.


from module import *

tada!

it's just considered bad python style to do that... because it tromples your global namespace!!


Number of times I've been bit by global namespace pollution in Python or Ruby: countable on 1 hand.

Number of times I've been bit by forgetting the right import statement for a piece of Python library functionality: considerably worse.

I know, "plural of anecdotes" and all that. I think it's hard to argue that Ruby isn't easier to use "out of the box" than Python is, though. How do you say:

    3.days.ago - 2.hours
in Python? Because, yeah, "days" and "hours" on Numeric? Shit's all crazy! But totally worth it.


yeah... cause you know... I never forget to include 'gems' because gems has to monkey patch the include function so that it can get at my installed libraries :P


You can use ruby without gems. I think you confuse gems with "pure" ruby as such. I have seen horribly code in gems and I think the whole gems idea is the wrong solution. But I am in a minority here.

I also do not know why cpan is mentiond FIRST as perl's greatest assets. To me i think a language should easily provide the capabilities to the programmer without addons, AND I also think that there SHOULD BE ONLY ONE "CPAN" FOR ALL THE SCRIPTING LANGUAGES OUT THERE.

I find it totally silly that there are any distinctions at all.

But back to gems:

I for example am using Ruby since almost 5 years without gems. Others seem to like it that you can simply do "gem install rails" and thats it (unless the debian package manager starts to hate it again... which is btw another thing that sucks.)

I agree that there are people who are concerned with "namespace" pollution, but I simply think so many people are trying to overemphasize. The worst was when I talked to a C# hardcore guy. He basically claimed that being flexible like Ruby is ALWAYS bad (C# does not allow you to change core methods. You must subclass and change that new class then. This is not a smart solution, it simply binds and restricts the developer, and claims that this will be better in the long run. My question is - why not allow being flexible AT THE CHOOSING OF THE DEVELOPER IN QUESTION? The reason is simple. C# is a typical language that is developed from the top-down.

It would be so much better if creating good languages would be a lot easier, so noone has to cater to arrogant developers who try to impose their thinking pattern onto your brain.


I don't think you read my comment, while I did take a stab at gems, the point was to simple to provide a counter point to his statement that he commonly forgets to import the right namespaces in python. The counter is of course, that I forget to import the right namespaces in ruby as well.

In fact I can think of a common one, that many people forget, we often forget the gem include (being why rails includes it for you).


Also I would like you to name which library specifically causes this problem :)

Whenever I read it, people seem to make up contrived problems - and do not give any example.

I would like specific examples please where this interferes with your code.

So far it simply did not interfere with my own ruby code, and I have written really a lot over the 5 years here, including my own bigger "alternative" to gems. (I wanted to release it, but I was lazy and always felt it is easier to use my own idioms. The problem with this approach is that, while it really makes creating something super fast, I would either have to unbundle everything again so I can distribute it, or bundle everything. Both things have huge problems, because if i unbundle everything it will take quite some time to rewrite things really "cleanly" enough for _other_ people. For my personal needs it is totally fine. And if I would distribute things "bundled" together, which means I could release today, then people would simply complain that there are so many things "bundled" together they simply wont need.

Complaining people are annoying.

i know because I am one of them)


I don't have any good ruby examples, but I've been bitten by namespace trampling behaviors in perl and php long enough to know that any code importing in languages I use need to make it explicit when that's occurring.


its not nearly as pretty, but its not terrible either.

from dateutils import relativedelta import datetime datetime.now() - relativedelta(days=3, hours=2)


"... I lived with Python for 4 years before I lost an argument at my own company and had my project moved to Ruby. I've since moved in with Ruby and haven't looked back. ..."

Where would we be without language wars?

Having said that the one thing that Ruby does have is current developer mindset. Important for language development and progression. Is Python to Ruby what Perl is to Php? Used a lot but not mentioned as much?



I think you might be confused as to what Python's lambdas are for. The name is very misleading - it really should be called a function expression. It's just a shortcut for declaring a function with an expression. It's useful for situations where you need to pass in a very simple utility function, as is usually the case with list.sort() and its comparison function argument.

I'm not sure what points you're trying to make with your other complaints, but I guess if you "feel" things are hackish, that's OK. What you might consider feeble-minded hacks Python coders consider simple, straightforward implementations.


> Ruby is palpably slower than everything.

Try 1.9. It's usable today, and should be fully stable by January. Performance-wise, it's on par with Python.


I want to focus on one point that I find an interesting study in language design:

> * I haven't found an expression that is better written as a list comprehension than as a map/reduce/select expression.

map/select are better iff you have a concise block syntax.

For mapping with a single ready function, all styles are reasonable:

    items.map foo
    items.map { |x| foo(x) }
    map(foo, items)
    [foo(i) for i in items]
Now suppose you want to modify the mapping function to foo(bar(i)). You could cascade it:

    items.map(foo).map(bar)
    map(foo, map(bar, items))
but this quickly gets out of hand and makes modifications painful. What you really want is a place to write arbitrary expressions instead of just a function name.

With comprehensions OR a good block syntax, it's a smooth transition:

    [foo(bar(i)) for i in items)]
    items.map { |i| foo(bar(i)) }
But without one, the change is ugly and annoying:

    map(lambda i: foo(bar(i)), items)

So why wouldn't Python just embrace a nice block syntax? Precisely because this naturally leads to expressing most control structures as functions taking blocks!

Now that is not wrong in itself, but it is a question of taste. Pythonic taste favors a different approach: instead of passing the block directly to a function, have a few built-in control structures that can act as combinators.

E.g. don't write an "each" method that accepts a block - write an iterator, and use the built-in "for" loop as a bridge between the iterator and the block. Why would this be any better?

1. Because we can: it turns out that the vast majority of custom control structures can be sorted into a few patterns (iteration, pre/post guards, function wrapping), each served by one natural combinator ("for", "with", decorators). There is a price: it takes time until new patterns are recognized and the missing combinator is added (e.g. "with" is a very recent addition).

2. Decoupling: an iterator is a self-contained passive object that can be used outside of a for loop. An "each" method takes control and is less versatile.

3. Readability: seeing the combinator gives you an immediate idea about the style of flow control. This is just a matter of taste (Lisp and Ruby solve this with naming conventions).

4. Syntax taste: stupid as it sounds, passing blocks to functions is just alien to Python's syntax. Many smart people tried to marry them - and it wasn't a pretty sight...

But in the end you can't judge decisions of taste by pro/con arguments. You have to look at the sweet spots (and the sour spots) that arise in practice. A particularly nice sweet spot that arose in Python is the combination of reduction functions with generator expressions:

    sum(i**2 for i in range(10))
    any(p % i == 0 for i in range(2, p - 1))
    dict((v, k) for (k, v) in dict_to_invert)
This is very cool because the map-reduce pattern covers lots of useful computations. Of course it's just a one case and YMMV. I'm sure Ruby has its own sweet spots...


You can add inline c to ruby for the few places where speed matters.


Yes, and that simply costs you the ability to distribute your software to anything but your own servers.


My experience is that the languages are similar in terms of features, but the communities are very different and there isn't much overlap between them. Ruby types tend to be younger, focussed on the web, probably employed as full-time developers. Python types tend to be older and not employed as developers, but write code as part of their main jobs. Python people often have experienced a nightmare of unmaintainable Perl, that is why there is the insistence on there being one right way to do everything (which is the exact opposite of what Perl people believe). Ruby people (being younger and hence less experienced) haven't, which is why they talk about expressiveness and do things like monkey-patching. Neither group is "smarter" and neither language is "better". The choice is a choice of what community you want to join, not a technical one.


From my observation, the ruby community is heavily skewed by the recent influx of Rails programmers, which is web dev and younger. Old-school ruby folks (the guys who were ruby gurus when Rails was still an infant) have different characteristics: older, less confrontational, veteran programmers, Matz-like. A generalization for sure but my impression.

The python community has done significant development in science/math so they have stronger libraries in those fields. Python has had an influx of Railsy people due to Django and might get a shot in the arm from Google App Engine.

From a language perspective, I like the wealth of libraries for python. I like that many reference/experimental applications on web stuff is in python. The whitespace issue for me has disappeared and I'm actually leaning toward liking it more than ruby's block delimiters. The template/erb issue can be diffused by looking at HAML. (That's a cool way of incorporating pythonic indentation to templates.) Unicode is solid in python.

Ruby is a better choice if you like to reshape the language into something that could potentially look un-Ruby. It's possible I haven't gotten far enough into python yet, but I can see why metaprogramming and DSLs are more prevalent in ruby than python, and it's not just "one way" culture. (Ruby's optional parentheses for method calls is an example of a language feature that fosters DSL use.)


I have to agree. Ruby has incredible flexibility, but how it's been used by "the kids" in things like Rails (and especially Rails extensions) makes my skin crawl.

This also bugs me to no end: nil.to_i == 0, 0 evals true, but nil evals false.

Python's lack for me is anonymous functions. It's cumbersome to set up 40 slightly different named functions and a hash table (or some "factory pattern" thing) to do the same job as 3-4 lines of Ruby. Symbols are nice too.

But for my personal work I choose Python for the libraries, cleanliness, and performance.


What are you doing that can't be done with python's lambda functions?


What are you doing with Python that can't be done with FORTRAN?


Running on Google's App Engine :)

Seriously, though, I'm not arguing python's anonymous functions are just as good as ruby's. I'm curious about his particular situation where "3-4 lines of Ruby" is all it takes.


You could run FORTRAN on a virtual machine on Python.


Anything that is not a simple expression. assignment, if..else, etc.


Then use a function with some introspection and pass it some parameters.


You can but you shouldn't need to. Sometimes I want to do something like:

    dict['item'] = def _(var1, var2):
        fn_var = 1
        do_some_magic(fn_var, var1, var2)
There's no good reason why I should instead have to do:

    def fn(var1, var2):
        blah
    dict['item'] = fn
.. or write a decorator.

I'm frequently tempted to write a python-like scheme syntax to sit in my python programs so I can just do this stuff and to hell with the excuses used to prevent my first code block from above from working.


It's been a while since I wrote any Python but... here's a shot in Lua.

Lua:

  function dict.item (var1, var2)
    local fn_var = 1
    do_some_magic(fn_var, var1, var2)
  end

  -- note that:
    function dict.item (arg) return arg end
  -- is syntax sugar for:
    dict.item = function (arg) return arg end

  -- for an implicit "self" parameter use a : in your declaration and invocations:
    function dict:item (arg) return self(arg) end
  -- is sugar for
    dict.item = function (self, arg) return self(arg) end
You can in fact call functions with the implicit (via :) self parameter with any desired "self" by using the "." rather than ":" invocation syntax and providing an explicit self. ":" is purely sugar which is optional in all cases.

  function table:swap()
    local swapped = {}
    for k, v in pairs(self) do
      swapped[v] = k
    end
    return swapped
  end

  -- assume "Table()" returns a table which routes "method_missing" calls
  -- (which is actually the __index metamethod in Lua)
  -- to `table`
  t = Table { a = "foo", b = "bar" }
  a = t:swap()
  b = table.swap(t)

  -- a and b are both equal to:
  -- { foo = "a", "bar" = b }
One neat thing about Lua is that the user can define basically arbitrary semantics for inheritance, mixins, and all sorts of meta stuff very simply. And you can define them on a per-object basis. It's very powerful. The drawback is that you have to implement these things yourself (unless you use a 3rd-party lib which provides some common patterns like you'd see in Python or Ruby).


Thanks for that. I've looked at io a bit, which is similar to lua, and been very impressed by stuff like this. Also that you can effectively reflect against function definitions in order to create modified versions at a later time.


Another factor that pushes python forward among people for whom programming is a means not an end is that it is a primary scripting language for Ubuntu and is heavily used in the Red hat descended distros as well...

On some level choice of programming language is irrelevant, since any specified functionality can be written in any turing complete language. Arguments about programming language are arguments about style rather than substance.

I suspect that the python vs. ruby debate is like arguing about whether keyboards or guitar are superior musical instruments. They both have their place and the world would be sadder and smaller place if either one went missing.


I agree that this is the big decision point. I'm a Ruby guy and I've looked at Python several times and it never really stuck (I could work on a project that use Python, it just wouldn't be as fun as a project using Ruby to me). I could complain about various technical details, but if I'm entirely honest it would just be minute, meaningless, bitchy detail nitpicks.


"Python types tend to be older and not employed as developers, but write code as part of their main jobs."

I'm curious, how did you arrive at that conclusion?


Mainly through direct observation. Among my own circle of friends, it's surprising how neatly we (well, those of us who use either language) divide into those categories. But you can see the pattern in job ads, discussions on mailing lists and in the domain-specific libraries for each language too. As many people got into Python through NumPy as a MATLAB alternative as got into Ruby via Rails, I'll bet.

Like I say, this isn't a good thing or a bad thing, it's just interesting.


Your comment made me realize that the phrase direct observation sounds so much better than anecdotal evidence.


You'll notice I did say my experience :-) I'm not trying to "win" an argument here, which would require "evidence", just pointing out that there are more important things in language selection than the features/characteristics/quirks of the language itself, especially given there's not much to call between Ruby and Python.

But, y'know, you could try quantifying it if you like, by looking at the libraries available for each language, and looking at how many jobs are "Ruby" as their main skill and how many are "10 years of whatever + Python".


Certainly not a bad or good thing, it was just interesting to me because I've never noticed the same trend from interacting with the Python community in Chicago and at PyCon.


I don't think Python lacks much, if anything. It's a very fine language, with a great community. Over the years though, I just lost interest in it, and have come to prefer Ruby after having rediscovered it because of Rails. It's pretty much a matter of taste: I like the syntax and convenience more.

One (fairly minor) real world case where the syntax makes a difference is in web templates: you can use Ruby pretty much straight up to do templating, but Python requires more hoops and hacking, due in part to the whitespace issue. I like the fact that Ruby is flexible enough to be used as-is for templates as well as other code. BTW, it also needs to be said that that is the only place I've ever noticed the whitespace issue being any kind of problem: it's not the big deal that some python detractors make it out to be.

In short: if you're happy with Python...great! Keep using it, you made a good choice. If you want to learn another language, pick something a bit further from it... say, Erlang, Tcl, Java, or C, depending on what your needs are.


Note that Python is sensitive to indentation not whitespace per se. So long as your line is at the right level there's no difference between

    a=1+2
and

    a = 1      + 2
In fact I wish Python were more sensitive to whitespace, then I could say my-variable without it mistaking a hyphen for a minus.


"then I could say my-variable without it mistaking a hyphen for a minus"

That's something cool. It would involve a new PEP and aggressive enforcement of PEP 8


Reckon it'd break too much existing code, but hyphens are so much nicer than underscores or interCapping. Using a language that supports that, my hands are noticeably more comfortable without needing to reach for the shift key all the time.


you could just use a font that renders underscores differently (like, say, slightly stylized hyphens.) That's the correct approach, semantically--when you use an underscore, you're basically trying to say "a space, but without the syntactic meaning of one."


It's not about how it appears on screen but about the keystrokes needed to enter it. If I could I'd find a way to use only square brackets too. Ideally I'd use only ; or : and only ' or " too, and adjust my keymap accordingly.


This is one of the advantages of Lisp. It is common for Lisp programmers to map the [] keys to () and vice-versa. Since Lisp requires so few of the keys, such mappings can prevent you from needing to press the less comfortable keys.


It is not hard to remap your key bindings if you find `_` too hard to type.


Lisp? ;-)


Forth?


I really like Forth, it seems to me to be very much the right way to do things, however I've never managed to write an actually useful program in it.

Mostly I use Tcl as a sort of Lisp/Forth mashup :-)


HAML: kinda looks like python, if you stand far enough back from the monitor

Python's got dozens of ORMs, templating libs, web frameworks, unit test libs. The embarassment of riches definitely an issue, you could spend a week reading about python ORMs alone.


They're both impressive, modern languages. What I find interesting when comparing Python to Ruby is how much Python isn't like Lisp. Matz has said outright that he considers Ruby to be "MatzLisp" and it shows, whereas Guido has absolutely no problem chucking Lispy things overboard--like multi-line anonymous functions--if they do not fit the rest of the language.

Instead, Python finds another way, like powerful list comprehensions that can be used wherever Ruby would use blocks and maps.

So I would say you can learn some very interesting things from either language, and there's a good chance they will be different interesting things.


Matz might say that, but doing functional things in Ruby is a pain in the arse as well. Blocks, Lambdas, Procs, and Methods, all which are slightly different and require transformative functions to move one into the other. That's about as far from an s-expression as you can get.

That being said, having the easy ability to create lambdas or blocks is hugely benefitial. sighs and I wish python would hop on board there, but I don't think it ever will.



Yeah... sobs it's a nice band-aid, but an inelegant solution. I would much rather that they all just be Proc or all some other mythical procedure class of the future. I figure that would break the whole ruby method call chain, though I don't see any reason why blocks couldn't just become straight syntactic sugar for lambda (I would love that)


A little off-topic, and I apologise to everyone for our exercise in bikeshedding, but... :-)

The problem is that Ruby blocks were designed to imitate the behaviour of C-like blocks, while lambdas are true closures. (Don't get me started on why procs are just like lambdas only different).

The difference between a block and a lambda is most clearly seen by asking what the return keyword does in a block vs. what it does in a lambda.

So in Ruby you can write something like:

    def which_answer_is_correct(*answers)
      answers.each_with_index do |answer, index|
        return index + 1 if answer.to_s == '42'
      end
      return 'none of the above'
    end

    which_answer_is_correct('black','white',42,:symbolic_logic)
      => 3
If blocks were syntactic sugar for lambdas, this method would always return 'none of the above'. Of course, there is another, very elegant way to write this method that doesn't rely on the return keyword or the semantics of blocks, and one can easily argue that this would be an improvement.


(though my intention was not to derail the conversation. This is a niggling difference between ruby and python that irks me :-D)

Right I would be arguing as the latter.

My problem is that these small niggling differences between all the different types of callable items (including what I think is simply disgusting use of a special form "yield") confuses the whole mess.

I'm glad that all these different ways to use callables exists. That's "A good thing" in my opinion. But I can't help but feel that their quirks and differences couldn't be consolidated into a single experience.


derail the conversation

De-rails-ing conversations about Ruby is often an improvement.


Good sir I do say... that was quite the pun :-D

takes his hat off


Doesn't Ruby have call/cc?

  (def which-answer-is-correct answers
    (let like-ruby-block 
       (fn (answer index return) (when (is string.answer "42") (return:+ index 1)))
       (ccc [do1 "none of the above"
                 (on a answers (like-ruby-block a index _))])))
as a useful contribution to the topic: Python does not have a call/cc

and how would the return statement be scoped if the block was created inside a different function?


Yet more bikeshedding, this time in Lua!

This first approach doesn't use an internal lambda but is idiomatic - (do/end does not create a block in Lua - it creates a scope):

At the Lua repl:

  > function which_answer_is_correct (...)
  >> for index, answer in ipairs {...} do
  >>   if tostring(answer) == '42' then return index end
  >> end
  >> return 'none of the above'
  >> end
  > =which_answer_is_correct('black', 'white', 42, 'symbolic_logic')
  3
The next approach duplicates the semantics of the Ruby code you posted, if Ruby blocks were actually lambdas:

  > -- first a bit of magic to make Tables act more like in Ruby
  > mt = { __index = table }
  > function Table (t)
  >>     return setmetatable(t or {}, mt)
  >> end
  > 
  > function table:each_with_index (block)
  >>     for index, value in ipairs(self) do
  >>         block(value, index)
  >>     end
  >> end

  > -- now actually write our function:
  > function which_answer_is_correct (...)
  >>     local answers = Table {...}
  >>     answers:each_with_index (function (answer, index)
  >>         if tostring(answer) == '42' then return index end
  >>     end)
  >>     return 'none of the above'
  >> end
  >
  > =which_answer_is_correct('black', 'white', 42, 'symbolic_logic')
  none of the above
Now, if you want the nonlocal return properties of Ruby blocks in Lua, you need to be a bit more clever than I feel at the moment. There's probably a trick available via coroutines, because coroutine.yield() yields to the caller of the currently running coroutine, rather than to the caller of the currently running function.

Making anonymous function creation less verbose is a popular topic on the Lua mailing list. "function (args) return args end" is more verbose than "do |args| args end". There are several implementations via community-developed macro extensions. I wouldn't be surprised to see something appear in the Lua 5.2 RC candidate later this year.

In the real world, I'd probably write something like this in Lua:

  function which_answer_is_correct (...)
      return table.find({...}, function (value) return tostring(value) == 42 end)
  end
Implementation of table:find(cond) is left as an exercise for the reader.


For functional programming what Python really misses is not a decent lambda. You can get by without.

But properly optimized tail recursion.


You don't really need full tail-call optimization as long as your map/filter/reduce is optimized. Nearly everything can be expressed as combinations of those.

Actually, if you have generalized folds (folds over all data types, not just lists), all recursion can be expressed in terms of a fold. That's the point of a fold function: it captures the recursion pattern over a data type, letting you parameterize just the specific operation that replaces the constructor.

In practice, I found that the mutability of basic structures was more of a problem. By default, your subscripting/attribute assignment all mutate the original object instead of creating new ones. When I did FP in Python, I did a few decorators to hide this, but it still felt like an ugly kludge that was fighting the language.


Yes, that's a problem, too. E.g. dictonaries would need to be replaced by something persistent like balanced trees.


I've always taken the approach of learning both and deciding for myself. If you're interested in true proficiency and building something for yourself, go with whatever rings most true to you.

I liked Ruby, but found that Python clicked better for me. That, and call me crazy - but I prefer quiet competence to foaming at the mouth zealotry. There are plenty of people who rave about Python - but they've been doing it for a lot longer than the Ruby people (simply age of language).

Ruby also has gotten lots of people hooked via Rails, and that seems to be where most of the evangelism is coming from.

(edit: commented to clarify my meaning below, in another comment: http://news.ycombinator.com/item?id=283771)


>> but I prefer quiet competence to foaming at the mouth zealotry.

Do you really pick your language by your perception of its users? I'm not sure that's a great criteria for choosing a tool. If an annoying dinner guest admired the butter knives, would you butter your roll with a fork?


Well, working extensively with a language means working with its community, as a reader of news and documentation if nothing else. The size, expertise, and helpfulness of the community are all important factors in deciding whether to adopt a language. If a programmer finds the community annoying, that could be a legitimate problem.


The community also determines what is and isn't easy. This is something that a lot of otherwise smart people don't seem to get. Everytime someone into a powerful but obscure language wonders why it isn't more popular the answer is almost always something like "because Haskell's interface to Oracle is rubbish". And that's fine, because the Haskell community care about other things, if they want to be popular tho' they'll have to address that.

Concrete example: The Ruby community is very focussed on the Web, so there's Rails but they aren't really interested in scientific computing so there isn't a real equivalent to NumPy.


Concrete example: The Ruby community is very focussed on the Web, so there's Rails but they aren't really interested in scientific computing so there isn't a real equivalent to NumPy.

I'd mod this up more if I could, because this is the best answer to the original question.

The important thing is the community, not the language. Decide what your problem is, find the people who are working on that problem, and use whatever they use.

The importance of community is the reason why the number of people who praise Lisp as a language is so much larger than the number who use Lisp every day: The Lisp community is small, unfocused, and arguably broken. Meanwhile, I work as a professional Drupal developer and am (god help me) gradually becoming an expert on PHP, but that has nothing to do with my nigh-nonexistent respect for PHP as a language. I do it because the Drupal community is large and growing larger, it includes as many noncoders as coders, and it's focused on building websites rather than obsessing over tools. The result seems to be that customers like using Drupal for their sites. Rails and the like are focused on making programmers feel empowered, but Drupal is focused on making site admins feel empowered.


No sorry, my first comment was pre caffeine and didn't quite explain things as well as I would have liked.

I was reflecting on the original poster's comment:

"But there are so many really enthusiastic posts about Ruby and while Python has a lot of users and is very popular and successful I rarely see anyone rave about it."

It was a poor choice of words on my part - I meant to characterize that evangelism doesn't necessarily mean it's a better tool. I was reflecting more on his commentary about "enthusiastic posts" in my comment than any personal opinion on Ruby ( I find a bit of zealotry in the Rails people but that's neither a bad thing nor is it my place to comment on it). My preferences tend these days towards being slightly turned off by the loudly evangelised toolsets, simply from past experience of what happens to the communities when they get like that. After things calm down, and the happy masses move on to the Next Big Thing(tm), the languages, tools etc are often quietly solidified and iteratively improved (uncelebrated, in many cases) by those that stick around.

I recently came back to Perl, having joined a firm building systems in Perl, and was surprised at how much has happened in Perl in the 4 years since I stopped working with it. While so many of those that formerly evangelised about Perl moved on to Ruby and Python, the people who were forced to continue working with it every have found ways to improve it. Adding a try/catch syntax with proper exceptions, and similar constructs (albeit a bit Monkey Patch-ey) have made it much easier to work with.

It will be intresting to see what happens to Ruby when the Next Big Thing happens, and the community sheds a lot of it's more fickle members. That's not to say Ruby isn't a fantastic tool now, but I'm interested to see the maturity that comes from the difference between those who think it's really the best tool for them as opposed to the tool that everyone loves.


I think a better analogy is choosing a house to live in and its neighbors.


Two good things and one bad thing. The good things are multi-line lambdas (which Ruby calls blocks) and loose syntax rules, which I found weird at first but is the secret behind all of that DSL stuff.

The bad thing is the cultural tendency of the Ruby community towards monkey patching, which in my opinion trades long term maintainability for short term convenience.


With the rapid growth of the community I think that the monkey patching mentality will eventually subside. More and more toes are being stepped on.


To be fair... blocks are not lambda's, but things would be a lot better if they were.


I like how this conversation has gone on for so long, but on the whole, everyone's still polite and detailed in their responses. :-) warm fuzzy feeling


It isn't so much about language features, as both languages are roughly equivalent in that sense.

It is about how the language makes you feel. If you're going to be spending >5 hours a day writing in some language, it is of great importance how that language makes you feel when you write it. Simply said, writing Ruby makes me happier than I've ever been while writing code.

Python is to German as Ruby is to French. You can get roughly the same message across equally well in both languages, but French just sounds so much better.


I'll agree that it's about how it makes you feel, but Ruby (+ Rails) just made me feel sloppy, while Python (+ Pylons or Django) felt crisp & productive.

Really, I'd say to try both languages and pick whichever one you like best. They're very similar in what they let you accomplish, but have very different feel. What works for one person won't necessarily work for another.


Two words: "French Engineering".


Two counter words: Ariane, Nuclear (as in 80%+ national electricity)... not too shabby as far as engineering goes... I would add Airbus, LHC, etc... but two are enough.


yeah, as an engineer working in France, I can honestly say that their engineers are pretty good. The problem is that there's another grand école that specialises in producing bureaucrats (seriously!). And for whatever perverse accident of history, they are considered to be la crème de la France, so they call the shots in most large businesses. They consider themselves to be better than lowly engineers, so don't deign to listen to any suggestions about what is technically possible or not.

/bitter

:-)


Have you ever worked with engineers from Les Grandes écoles? You might reconsider your view.


> Two words: "French Engineering".

Mmm hmm. How's that American SST coming on? I'm English and your comment even annoyed me.


Well... unless you want to sound really angry! Then er... Python is better?

I think I'm stretching the metaphor past its breaking point.


Indeed. Whenever I'm waiting for Ruby to finish something that Python would have done faster, I like to imagine that it's taking a long lunch in a Parisian cafe, smoking clove cigarettes and picking up women.


German can be very precise.


About 6 months ago I decided to learn either Python or Ruby because I wanted a language to write webapps and simple computergames fast.

If you're after writing simple computer games fast, then you might have a look at Pygame: http://www.pygame.org/news.html

There are also a number of visual effects companies (ILM, Dreamworks) that use Python as their system scripting language. I don't know if it's because of that community, but I find a number of graphics/games libraries in Python: http://www.vrplumber.com/py3d.py and http://vpython.org/

Blender the open source 3D modeling program used Python as it's scripting language last I checked: http://www.blender.org/

I don't know if Ruby has libraries like that or not. I've only used Ruby to mess around with Rails.


For me, the question isn't so much what Ruby has that Python lacks, but the extra Python bits I find annoying and/or tedious:

* having to declare "self" in every method argument — reading code, it just clutters up the screen/page

* the big use of of double underscores for special methods (i.e., __init__, __str__, __getattr__, etc...) — IMV, it's gooberish...

* no switch/case statement

In defense of Python over Ruby:

* I prefer the whitespace over the Pascal-ish begin/end, especially for real life code solutions

* the Ruby shorthand syntax IMV at times obfuscates code clarity - is it a method or variable I am looking at?

That said, I'd much rather code in either Ruby or Python than in Java or C...


Well, they're both foundational languages, pretty much, not in the sense of this blog, i.e. most instructional language

http://mvanier.livejournal.com/998.html

but in the sense of can you put up a significant web app in 2 or 3 days, do lots of companies use it (along with C, java, C#, javascript).

r vs. p can't be reduced to 15 bullet points, but one of the best things i remember is Alex Martelli in 2003, so he was talking about ruby 1.6 and python 2.3, i believe, but still valid

http://groups.google.com/group/comp.lang.python/msg/28422d70...

and here's the last thread from May.

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

There's the other killer apps: Python: twisted, zope, SQLalchemy, mercurial. Ruby: rake, capistrano, rspec, adhearsion, merb, puppet, metasploit. I'm sure python has a bunch more, but i've been living in rails-land.


Though I'm pro-Python on maintainability grounds, there's one Lispish feature Ruby has that I wish were available in Python, that's not even in the Py3000 spec: continuations. The Ruby community doesn't seem to be too enthusiastic about using them though. We're just beginning to see continuation-based web framework experiments on Ruby, in the spirit of Seaside in Smalltalk.

The continuation-based web frameworks make state management on the server transparent; but they have a scalability problem since state can't move between servers or even be taken out of memory on the same server.

Now once somebody makes serializable continuations practical - certainly a hard problem - it would be a jolt to web development on at least the same that Rails has been.


In Lua, the Pluto serialization library has no problem persisting coroutines, which are isomorphic to one-shot continuations. Lua isn't terribly active in the web space, though this feature has been used to good effect in games.


Serializable continuations are already practical in Smalltalk: http://www.seaside.st


I think that a lot of the popularity of Ruby came not so much from Ruby itself, but Rails. I think that with the emerging popularity of Django, you are likely to begin noticing a similar influx of Python enthusiasm...


Admittedly, Django was what first got me really going with Python (we started using it for some small projects as a possible replacement for PHP a few jobs ago).

There are however also some great alternatives within the Python community, in addition to Django which I no longer tend to use.

Pylons, which is very Rails like including having similar WebHelpers functions, and a port of the Rails "routes" system.

TurboGears, which is currently re-tooling itself to be based on Pylons.

And a variety of others that I'm probably forgetting.

I'm admittedly ignorant on alternatives on the Ruby side, but would be interested to see what other web frameworks people have built and the pros cons vs. Rails.


I'm admittedly ignorant on alternatives on the Ruby side, but would be interested to see what other web frameworks people have built and the pros cons vs. Rails.

Merb is the big one. Think Rails, but more lightweight, greater emphasis on scaling and performance, and open to several ORMs (not just ActiveRecord), templating languages (not just ERB), and Javascript libraries.

Camping is a Ruby micro-framework that's been around for a while. The framework itself is 4kb, and Camping apps are designed to sit in one file. Used a bit on the side, but not especially widely for production work.

Sinatra is a newer microframework that looks similar to web.py, but in Ruby. Looks useful, and I've been meaning to get around to it.

The nice thing about Rails, Merb, and Camping is that if you know one, the others will be familiar. They're all MVC frameworks that support ActiveRecord (and other ORMs, sometimes). They all favor convention over configuration.


>> Merb is the big one. Think Rails, but more lightweight, greater emphasis on scaling and performance, and open to several ORMs (not just ActiveRecord), templating languages (not just ERB), and Javascript libraries.

Sounds exactly like the reasons why I went to Pylons. I found SQLAlchemy to be a lot more powerful than the Django ORM, and we needed more application components to be 'detached' from the web interface which got wonky in Django.

I'll have to check these out, thanks.


And a variety of others that I'm probably forgetting.

I personally find CherryPy to be great for writing small web-apps. I haven't used it for anything larger yet, but I suspect that I'll continue to prefer it over other python web frameworks.


After leaving Ruby (non-Rails) for Python this year, I've mostly noticed the difference in the obsession about testing. The Ruby crew is very into TDD (and now BDD)–that isn't to say that Python folks don't test (or do TDD/BDD), but simply that the tools available in Python aren't quite as polished. Ruby's RSpec, RCov, Flog, Autotest, & Heckle are all quite wonderful. I do like Nose, but get annoyed by lack of friendly code coverage tools in Python.


Rails. but you have Django which is better ;)

Seriously, I envy ruby's blocks and being able to redefine a class later in your code (monkeypatching-easy-syntax).

Oh, and Shoes :)


I chose RoR over Python/Django for one simple reason: RoR's tight integration with the Prototype AJAX javascript library. Personally, I like Python as a language much better than Ruby. But if I'm going to code up a Web app, I want easy AJAX integration - I don't want to hand craft a bunch of javascript. It's not that I've got anything against writing javascript, but I hate, hate, hate trying to debug it.


Tight integration with prototype is one of the things I don't like about Rails, mainly because I don't like Prototype (I'm a big fan of JQuery).


Then what you want is jRails, which subs jQ in for Prototype in all the Rails helpers and removes Prototype from your project. You "plugin install" it, forget about Prototype, and use nothing but jQuery from then on.


very cool, thanks. wish I knew about it a month ago.


I have to agree with the other commenter. I prefer to "roll my own" here. Not because I don't like it when frameworks take care of mess for me, but because I'm constantly frustrated by how frameworks handle JS. A quick and dirty RESTful JSON api is easy enough to build in either framework, and once you're there, Ajax becomes pretty trivial (especially with any of the nice JS Frameworks)


Yeah, me too. Is it a good idea to learn ruby just to use shoes? I mean is it easier that qt/tk/gtk+/wx?


you should try it out and see if you like it.. shoes is a good way to learn ruby

shoes is good for simple apps. But if you need complex controls like trees and sliders, coding in shoes would get annoying. Also the documentation for shoes leaves something to be desired.

but it is pretty fun.. i'm coding a shoes app right now and would recommend it


There really isn't a huge difference between the two. For what it's worth, I personally prefer Ruby because it has better support on the Mac - Apple use ruby a fair bit themselves. For example, the command line tool gen_bridge_metadata (supplied by Appleto make it possible to access system frameworks written in C from scripting languages) is itself a ruby script. I notice that on Linux it's the reverse - python seems to be the preferred scripting language.

But don't take my comments as saying only ruby is supported on the Mac, or only python on Linux - in reality it's only a light preference one way or the other.


The CalDAV server authored by Apple and included with OS X Server is written in Python. PyObjC receives a lot of attention from Apple employees. I don't think there's much preference exhibited by Apple one way or the other.

And vice versa, there must be some Linux distros that have tools written in Ruby, right? Particularly some of the newer ones, I seem to recall hearing that their system tools were Ruby.


As I said, it's just a slight preference. But I look at things like the official Apple support for MacRuby (Apple is employing Laurent to re-implement ruby in Objective C, so that ruby objects are Objective C objects - you'll be able to program Cocoa in Ruby without having to take the performance hit of crossing a scripting bridge all of the time!), and I don't see a commensurate support of the Python world. But as I said, it's only a slight preference - Apple s evidently right behind both languages, as they make leveraging the power of OS X so simple.


All of Gentoo's tools are written in python, bash, or C.


FWIW, the wiki that Apple includes in Leopard Server is also written in Python. Apple apears to be making much more use of Python than it is of Ruby.


Counter-counter: Podcast Producer is a Rails app. I think Apple is just letting their employees pick their tools (at least for server apps) as they see best, rather than arbitrarily enforcing the choice of a single language.


The languages are similar enough that it does not really matter. Just pick any, but make sure you balance it out by also knowing a low level language or a functional language.

Remember this: Every language you learn is a big investment in time and energy, and I don't think many people can be really proficient in more than 2 or 3 languages. Some can, but not most.

So, choose wisely, because you will likely be using that language for a long time to come. I personally prefer python because it's more widespread and right now, you have more available to you when you know it than with ruby.


I couldn't disagree more.

Even if you spend a month learning Ruby and never use it again, it will still irrevocably change the way you approach writing code.


I definitely did not have this effect on me. Usually when I hear comments like this it's from Java programmers. But coming from a background of already knowing several expressive dynamic languages (Python, Perl) and having a strong functional background in Lisp. I didn't really find Ruby that mind blowing.

Very cool? YES! worth learning? Absolutely! "changing the way I write code irrevocably? Not a chance!


Yeah, if you already know Python, Ruby just isn't that big a leap. You've got to jump further to find something that will be useful/mind altering.


I've found OCaml to be quite complementary to Python: It's excellent for functional programming and has one of the most sophisticated compile-time error checking systems I've ever used (two things relatively weak in Python). Both are very pragmatic and portable languages, as well. The OCaml community is tiny and rather quiet compared to Python's, though.


I didn't say that it would change the way you write code, I said it would change the way you approach writing code.

I'm fairly confident that it did. Once you've really learned it, Ruby creates paths in your brain that you will try to follow forever, even if you're not coding in Ruby anymore.

If it didn't, then you never gave Ruby a real chance.


I think the point your missing is aconbere already traversed those paths in his brain with other languages. Ruby, as far as I know, hasn't introduced any new programming language concepts.


It's cool that it changed the way you approach writing code, but it's more than a little presumptuous to go and apply that experience beyond yourself. I'm sorry if I didn't see much in ruby that I hadn't already seen, it's not as though ruby is pushing through a new paradigm.

Certainly the "ah-ha" moment for ruby was much less intense than my ah-ha moment of Lisp, Python, SmallTalk and Erlang. And it's definitely more straight forward to me than Haskell, Prolog, OCAML or Forth.

That's just the reality of it.


I'll join the peanut gallery and suggest that if "irrevocably changing the way you approach writing code" is the goal, you spend a month with Lisp or C before you do Ruby.


I agree that Lisp would have as much of an impact, if not more. I never said it was mutually exclusive with anything else in this benefit.


You mean that ruby has a greater learning effect than python on a C++ programmer?


If we are talking a month of involvement, you may as well learn both.

I would also throw Lisp in. And Forth. And Haskell. And Smalltalk...

But then, we are not talking about a month anymore...


maybe i'm an incredible genius or something, but give me a week or two and i'm writing code at an advanced level in any language. it's pretty easy. it more or less involves making an actual project in that language, which cold turky sink or swimly requires that you know the language at least decently

i think it's mostly mentality. if you think languages are hard to learn, then they will probably seem that way because you will allow yourself too much time to play around with mere details, whereas if you recognize there isn't much to them, you can accomplish a lot in no time at all


I think it is more likely that you do not recognize your own flaws. It takes a real genius to be able to learn the little things about C++ in a week or two.

A language is not just the syntax of the language itself, it's also the code style, the convention, the best practise, the language specific stuff, the API of the libraries available, the best way of doing things with libraries.

If you use python to write simple number crunching console applications, then switch to ruby, that is an easy switch.

But if you're writing a Web application using Python and Django and you switch to writing DirectSound using C++, and you tell me you can do this in a week, then you are a genius.

The syntax of languages are trivial, but that's like saying you can discover the colors used in a painting. That's the easy part. The difficult part is knowing how it works. Let me list a few examples of technologies that I think differ strongly from each other that make it difficult to switch

- MFC with C++

- Django with Python

- DirectShow with C++

- VHDL

- ASM

- Javascript with JQuery

- CSS with HTML

- Helix Framework with C++

- Quicktime API with C++

- OpenGL with .NET

- LISP

Have you ever had to switch between things on that level? Or are you talking more of a python to ruby switch?


I've done apps in Java/Swing, Java/Netbeans, Java/JSF, PHP4/MySQL/PEAR, Python/(web.py|Pylons|Django), Flash/MTASC, JavaScript/JQuery, raw JavaScript, and Haskell/Happy/Alex, plus several others where I don't feel I really learned the technology in-depth.

I agree with your general point though. It takes me about 6 months to feel proficient in a language. It's not just the syntax - it's the idioms, packaging infrastructure, unit testing tools, code organization principles, code conventions, etc.


To go one step further, to be at an "advanced level" in a language also means to be idiomatic in it.

I have a hard time believing that's achievable in a "couple of weeks", regardless of the level of someone's "genius".

(Also, just because something compiles doesn't mean you're good at it.)


when programming, if you keep your mind on the structures and on the problems themselves instead of on the language, you'll naturally reach points where you will demand that the language do X. sometimes the language will be able to, and it will seem "advanced." sometimes the language won't be able and you'll sob quietly for a moment because you have to implement it in another less elegant way

but if you worry about the details of the language, it will prematurely affect the structures that you create. in this mode it's harder to write "advanced" things because you are respecting the language too much, and are more confined to its syntax/semantics

if you stay above/outside the language, you will naturally pull it up


Well, you prove the point. You are incapable of seeing your own weaknesses in a language.

One can write every language the same way, but that's not programming. You can't learn python and then write C the python way. You can't write Python as you would Java.

Syntactically, it's possible, but that's a different language you are using then.

Don't confuse syntax or knowing when to use particular constructs with knowing a language. Call me slow, but it took me 3 years before I felt confident that I really knew most of C++. I know when to use Boost, when to use STD, What AtlArray is, how to write an IDL file, what extern 'C' does, what an stdcall is, how my variables are layed on my stack, what Gui toolkits are available, how Borland C++ makes properties appear in C++ classes, when one should use an int64, etc.

It takes time to learn that stuff, but to be really good at a language, you need to know it.

We're like doctors, you don't need to apply your knowledge all the time, but when you need it, you need to be aware of what exists and where to look it up.

If they ask me - write a webserver under Windows, I need to instantly be able to think of 3-4 libraries I could use for the low level stuff, and then decide which is best. All that takes time.

The syntax is nothing. A language is a whole lot more than that. You can't stay above a language. You need to delve into the language, you need to have a feeling for the language, you need to feel inside you how to express things in a particular programming language.

When you describe a problem to me, I can see the C++ structure in my minds eye. I can mentally walk through the code, see where I would use templates, where I would use an interface class, where I would subclass and so on.

I can't do the same with python, because even though I know the syntax, I've not used it long enough to get an extreme feel for the language. And the python folks like to reduce stuff down to short lines, and that's something you don't do in C++.

Learning a programming language is learning a new way to think. Not a new way to string sentences together.


> If they ask me - write a webserver under Windows...I can't do the same with python

I'd use BaseHTTPServer. Batteries included and all that. ;-)


note the word "prematurely." of course you have to follow the rules of the language, but being inside the box of the language from beginning to end will limit your creations


I'm not sure if you're being serious here or not... It's tough to tell on the interwebs... But I'll play devil's advocate and pretend that you aren't joking.

Writing Java in Lisp doesn't mean you've mastered Lisp. There is a difference between understanding the logic and creating the implementation in the best way possible, given the language.

As a very simplistic example, C and Python have two different ways to iterate. You could write a loop in Python in a C-like way, but there are much better ways to do it (list comprehensions).

On the flip side, just because C doesn't have list comprehensions doesn't mean it's less powerful as a language. It just does things in a different way. Knowing those sorts of things is why being idiomatic in a language is part of mastering it.


yes, and there is the implicit APL way of iterating. the point is to recognize that they are all instances of the same thing

i'm not talking about java. i'm talking about structures -- problems, their domains, and the machinations that can be used to solve them, independent of any language or implementation


my final project for electronics engineering required a large assembly program. that was incredibly discipline-demanding. though nothing countless macros and subroutines couldn't solve. also met VHDL in that major

all the web things, CSS HTML, JS, PHP etc. XML things like XSLT and XQuery (both of which btw are strict functional languages), etc. both JVM and .NET runtimes. API's can be their own sorts of languages. matlab, mathematica and so on

funnily, i grew up on Java. but everything changed once i met languages with first-class functions

my current favorite languages are Lua and Arc. if Arc had a solid implementation i would use it a lot


Assembler is one of the easiest languages to learn, the difficulty lies in understanding your machine.


Hah! Spoken like someone that has never had the pleasure of coding assembler for the %*$!#@@ ST20


Hmm, should that not have terminated at the $?


the difficulty with a large assembly project is that you have to write a lot of well-named and well-designed macros and subroutines and otherwise create your own modularizations, otherwise it will be completely unmanageable. the main difficulty in my case though was having to interface to multiple devices, one of which was designed to be networkable (ie pain in the ass protocol,) something with which the language didn't help


That's where you fail. The first thing we learnt about assembler was this - write in assembler, do not invent your own language and write in that language. If you do so, nobody will be able to read your program but you.

It sounds like you went and implemented your DSL on top of assembler, which is really bad practise.


i love you too


I'm nice like that :) Don't worry, pg doesn't like me too, you're in good company ;)


"Give me a week or two and i'm writing code at an advanced level in any language."

Whereas the Peter Norvigs of the world need ten years.

Sigh.


It's kinda funny how that works...

When I was in college and looking for internships, I put about 20 languages on my resume - Basic, Pascal, DCL, C, C++, Java, JavaScript, Perl, Assembler, PHP, HTML, SQL, CSS, InstallShield, Common Lisp, Scheme, Dylan, Haskell, Ocaml, and Erlang. After all, I'd written code in all of them, even if "code" was just a small 100-line program.

By the time I was looking for my first job, I'd pruned that to the C, C++, Java, PHP, JavaScript, Lisp, Haskell, and Erlang.

Now, I don't even list skills any more, just what I've done and what technologies I used to do it. But the list of languages that I consider myself proficient in is Java, PHP, Python, and JavaScript.

I used to wonder why it was that adults got so stupid between graduating from college and their mid-30s. Now I know - it's not that they're getting stupider, it's that their world and the difficulty of problems they face is expanding faster than their abilities. I feel much, much dumber than I did when I started college - but the program that took me a month then, I can whip off in a weekend now.


Obviously you've never met Haskell.

And if you hit the reply button and say that you have, then I demand to see code samples.


nay, not Haskell. F# though (using it right now on a small app that i plan on selling, hopefully it makes me enough money to support my starbucks addiction.) actually i've been meaning to play around with Haskell because it has a lot of succinct thingies with currying and whatnot, and i plan on making an experimental language or two eventually. generally though, strongly typed languages are painful for me. that is, painful to use, not painful to learn :)

one paradigm i've yet to try out is the "goal-oriented" languages a la Prolog. i'll get to them

my point isn't about me though, despite how great i am. i just think that thinking about languages as if they were huge monoliths isn't the best way of thinking about them, because it will hurt your ability to try out new languages and perspectives. they are things that you should revel in, not keep away from because they seem daunting


> maybe i'm an incredible genius or something, [...] which cold turky sink or swimly requires that you know the language at least decently

If you're such a language whiz you might want to master basic English.


I prefer Python, but I am somewhat envious of Ruby blocks. Also I like the idea that method calls are messages.


I've done quite a bit of Smalltalk programming, and I agree about the blocks. But what do you mean by "method calls are messages"?


In Ruby calling a method on an object basically sends a message to the object with the name of the method and the arguments. You can hook into the dispatch code and do pretty much whatever you want with that message at the class level. I don't know the internals of Python's method dispatch that well, so I can't say how it compares in that regard.


Are you referring to Ruby's method_missing? As I understand it's about the same as Smalltalks #doesNotUnderstand:.

Python doesn't have an equivalent, but it does have __getattr__, which is arguably more powerful but less convenient.


I believe Python's __getattr__() and __setattr__() allow you do the same thing, but I don't know enough Ruby to say for sure :-)


You couple those with ruby's method_missing and then you have some interesting functionality. But basically the way that Ruby handles operator overloading and function accessing is a lot cleaner than pythons. It would be pretty nice to get rid of a lot of the dunders.


this is never really brought up, but objects in ruby fully encapsulate their instance and class variables. the only way to get at them from the outside is by sending an object a message asking for them (like Smalltalk or Objective-C). what appears to be setting a property on an object, is really calling a method: `foo.bar = 5` isn't directly setting the property, its calling a method named `#bar=`

in my opinion, this is powerful and elegant.

that being said, i have little experience with python, but what i've seen never wowed me. it seems like it has a well written collection of libraries, but that seems to come from the community more than the language. correct me if i'm wrong.


You can do exactly the same thing using Python descriptors. No advantage to Ruby here.


but its not enforced by the language or the object model. advantage ruby ;)


_why


personally i don't like the 'one way' mantra that Python is designed by, because it seems to imply a couple things. 1, the language is probably not as flexible and powerful as it could be. and 2, the design goal is similar in nature to that of production languages, eg Java which forces object orientation. the intentions are good... to allow the construction of readable, maintainable software by normal humans, and Python is at least not as retarded about it as Java, but i have found that languages which constrict aren't for me

so to me Python seems more of a team production dynamic language than one where i can get into flow and crank shit out


The practical benefit of "one true way" is that it eliminates decision points. Most of the time in a software project is wasted in making decisions; if you eliminate all decisions that are not relevant to getting the software finished, you have a huge head start on everyone else.

There's a joke going around that a Python team will finish a project before a C++ team can decide which brace style to use...


The lack of built-in regular expressions is a pain point for me.


Consistency in class definitions (that is, not two "types" of class). Python's packaging is less consistent. Oh, and far better community sites.


First class symbols are the big one, I think. Of course, we all know about Python's brain-damaged function literals.


I really like Python, but it doesn't have an equivalent to CPAN or RubyGems.

I'm actually quite puzzled by this.


Read up on setuptools and the Python Package Index, aka the Cheeseshop. Setuptools hasn't yet been adopted as the one true packaging format by all library creators, but it gaining acceptance.


Ok, awesome. And that's the same story as RubyGems. I've noticed that Python peeps are pretty big on "show me the code" anyway, but I think a lot of untapped potential is lost by not having a dead-simple distribution mechanism, as good as Python libs tend to be overall.

That's one thing I do like about Ruby; it wasn't always this way, but RubyForge + GitHub (Oh, GitHub!) + RubyGems combine to make for a very fluid feedback mechanism and make good use of The Cloud.

The result is that new libs get announced, distributed, tested, and improved by rabid Rubyists rather... rapidly.


pypi? www.python.org/pypi


I would love to read pg's thoughts on this question.

Actually, I would love to read more of pg's thoughts on Ruby, what I have read of his thoughts on it has been brief yet highly positive.


Hype? ;-)




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

Search: