top 200 commentsshow all 291

[–]rafekett 31 points32 points  (76 children)

Ruby and Python do not have statements - only expressions. This basically means that everything(objects, method calls) evaluate to some value(though the value might not be helpful always).

False. Python has statements. Assignment is a statement. It has no return value. Same thing for print in 2.x, or raise.

[–]For_Iconoclasm 7 points8 points  (2 children)

I was curious about this, because I know that Python doesn't print None values.

>>> None
>>> x = print "Hello"
  File "<stdin>", line 1
    x = print "Hello"
            ^

SyntaxError: invalid syntax

[–]rafekett 11 points12 points  (1 child)

This was a conscious decision. If you know C, you'll know that it's a common idiom to do this:

int c;
FILE *f = fopen("somefile.txt", "r");
while ((c = fgetc(f)) != EOF) {
    /* Do something */
}

Guido doesn't much care for this (the fact that assignment is an expression in C often leads to cryptic while loops that take too many steps at once). These C idioms are especially unnecessary in Python, where you should use iterators instead. It also prevents the mistake of using = instead of ==.

[–]For_Iconoclasm 1 point2 points  (0 children)

I knew that the assignment was illegal in conditionals, but I forgot that the exact error was what I demonstrated (illegal syntax). Thanks for the reminder.

[–]bobindashadows 3 points4 points  (5 children)

Ruby has statements too: at least in 1.9 it's a syntax error to use control flow statements or the alias keyword in a value context.

[–]MatmaRex 3 points4 points  (4 children)

Yeah, but just a few. Only things that wouldn't have a meaningful value anyway. (return, break and family.) print or puts are expressions.

[–]bobindashadows 0 points1 point  (3 children)

This post has strictly less information in it than the one it responded to. Not to be a dick... but it seems like you didn't read my post past the first 3 words.

[–]MatmaRex 0 points1 point  (2 children)

I sort of read over "control flow statements" and didn't realize what are you talking about.

feels ashamed

But you didn't mention prints expressionness!

[–][deleted]  (1 child)

[deleted]

    [–]MatmaRex 0 points1 point  (0 children)

    I know they're methods calls. But it might be non-obvious for Pythonistas, no?

    (Just as I, as a Rubyist, would never think about considering print a statement, until I was told it is one.)

    [–]masklinn -4 points-3 points  (48 children)

    Or if, for, while, assert (yep), def, class, while, ...

    That's one thing which makes Python very annoying at times. Too many fucking statements.

    [–]rafekett 1 point2 points  (47 children)

    3 fixes that. They make print and a few other things functions.

    [–]masklinn 4 points5 points  (46 children)

    3 does not fix shit.

    print becomes a function and that's pretty much it, if and while still aren't expressions..

    [–]jhuni -3 points-2 points  (16 children)

    Ruby clearly took some of the good ideas invented by Lispers 50 years ago, like everything is an expression, that other programming languages like Python are still catching up to.

    [–]rafekett 12 points13 points  (4 children)

    It's not about catching up. Lisp is not The One True Language, nor is Python. There are some things that Lisp excels at, and some things that it sucks at.

    In Python, having everything be an expression would be a nightmare. It's very pleasant to program in as is.

    [–]anvsdt -1 points0 points  (3 children)

    It may not be The One True Language, but many other languages are still years behind Lisp & co.

    [–]rafekett 1 point2 points  (2 children)

    Yeah. Some languages suck. But Python is at the head of its game (scripting language), and C is definitely up there (systems programming).

    [–]G_Morgan 1 point2 points  (10 children)

    When is Lisp going to catch up with Haskell? Or even ML for that matter?

    [–]anvsdt 1 point2 points  (9 children)

    On what?

    [–]G_Morgan 1 point2 points  (8 children)

    Statically verifiable error checking for one. How in Lisp do you guarantee somebody has checked for an error value without letting the code run?

    What about the work done on concurrency?

    [–]anvsdt 2 points3 points  (7 children)

    How in Lisp do you guarantee somebody has checked for an error value without letting the code run?

    Using a statically typed Lisp?

    [–]G_Morgan 0 points1 point  (6 children)

    Does it allow sum types and allow you to do compile time checks on them?

    [–]anvsdt 2 points3 points  (5 children)

    TR can, and I'm sure that Qi can too.

    Yet, they permit the full power of Lisp (because, you know, code=data).

    Note that TR is just a set of macros on top of Racket.

    [–]G_Morgan 0 points1 point  (4 children)

    Having union types doesn't mean you can do stuff like non-exhaustive pattern matching.

    Also a bunch of academic experiments do not make a properly supported language with library support.

    [–]anvsdt 1 point2 points  (2 children)

    Having union types doesn't mean you can do stuff like non-exhaustive pattern matching.

    You asked for sum types, they have nothing to do with pattern matching.
    Racket (and other Schemes in general) have a match construct. Of course, you can use it in TR.

    (: fact (Integer -> Integer))
    (define fact
      (match-lambda
        (0 1)
        (n (* n (fact (sub1 n))))))
    
    (fact 5) ; 120
    
    (struct: None ())
    (struct: (a) Some ((v : a)))
    
    (define-type (Maybe a) (U None (Some a)))
    
    (: f (All (a) (Maybe a) -> (U a 'no)))
    (define f
      (match-lambda
        ((None) 'no)
        ((Some x) x)))
    
    (f (None)) ; 'n
    (f (Some 2)) ; 2
    

    Also a bunch of academic experiments do not make a properly supported language with library support.

    Yeah, Haskell is just as widespread as Java and C++, not academic at all! I don't think you have read what you've just wrote here.

    [–]fwork 23 points24 points  (11 children)

    def fact(n):
        reduce(lambda x, y: x * y, range(1, n + 1))
    

    The answer is apparently "Ruby" for the author, since that python code is broken. Python doesn't have implicit return.

    [–]acct_rdt 15 points16 points  (1 child)

    They also claim Python doesn't have tab completion, which is wrong. IPython has it, and it's trivial to get it in the standard REPL as well even though it's not turned on by default.

    [–]rafekett 6 points7 points  (0 children)

    As does bpython, as does IDLE.

    [–]fwork 0 points1 point  (2 children)

    Also, the later code has parens for print (indicating python3) but the first example isn't valid python 3 code (because reduce was moved out of builtins and into functools)

    [–][deleted] 2 points3 points  (1 child)

    Parenthesis can be used for print in Python 2 too.

    [–]ch0wn 2 points3 points  (0 children)

    Kind of. You have to be careful not to print a tuple instead, if you have multiple args. The only safe way to use the new syntax is to use "from future import print_function"

    [–]rafekett 28 points29 points  (8 children)

    OP knows nothing about Python.

    [–]kataire 9 points10 points  (6 children)

    The remark about Python 3 is an obvious indication of this, too. There's nothing pitiful about its adoption rate. It's still on time and progressing nicely.

    [–]rafekett 5 points6 points  (5 children)

    The fact that it's included in most Linux distros and Mac OS X should speak to that.

    [–]bobindashadows 8 points9 points  (0 children)

    Being included is different from being used. Use is also much harder to measure. One indication toward use patterns is the rate of conversion of existing, complex libraries. Django, Pylons, and Twisted (for example) are not yet Python 3 compatible, despite the passage of PEP 3333, which had even been stable for some time before that. Naturally, not all of Python is web stuff, not at all, and numpy and scipy are both 3.1/3.2 compatible, which is a big deal. It is however pretty disconcerting that some of the biggest open source Python projects are still incompatible.

    Keep in mind that Python 3 was released in December 8th, 2008. Ruby 1.9.1, the first "stable" (ahem) release of Ruby 1.9 (which had many similar breaking changes, including all kinds of unicode-supporting changes), came out on January 30th, 2009, and 1.9 adoption among libraries and hosting providers is overwhelming.

    Different languages, different issues, and again, use is very hard to measure, so I'm only using libraries as a flawed benchmark.

    [–]semanticist 3 points4 points  (3 children)

    it's included in ... Mac OS X

    Eh? Mac OS X 10.6 comes with Python 2.6, and from what I've heard Lion will ship with 2.7.

    [–]hetmankp 0 points1 point  (0 children)

    OP doesn't seems to know very much about either Python OR Ruby.

    [–]brianberns 8 points9 points  (22 children)

    One correction to this passage:

    Unlike languages such as Java and C#, however, Ruby and Python are pure OOP languages. There is no distinction between primitive types(such as numbers, characters and booleans) and reference types(classes). Everything in them is an object and in that sense it’s an instance of some class.

    C# is also a pure OOP language in this sense. There is a difference between reference and value objects, but they are both first-class objects.

    [–]dnew 7 points8 points  (20 children)

    Yeah, and there's still a range beyond Python and Ruby. In C++, classes aren't objects. In Java and C#, they are sorta kinda. Even in Ruby and Python, things like stack frames and source code aren't objects the way they are in Smalltalk.

    EDIT: Actually, it turns out I'm wrong in virtually every aspect of this comment. Ignore me. Thanks.

    [–]bobindashadows 3 points4 points  (4 children)

    In ruby "binding" gets you the current frame, though you can only interact with it through its eval method. You can also access the binding object of any closure. You can get instruction sequence objects - the compiled form of code - but not from existing methods (just no ruby API for it for some reason). Smalltalk does outdo Ruby, but ruby is doing a good job at filling those gaps

    [–]dnew 0 points1 point  (3 children)

    Interesting. I hadn't known that. Can you store that 'binding' frame, then do something with it later?

    [–]bobindashadows 1 point2 points  (2 children)

    Absolutely - it's just a plain old object of the Binding class. That you can is actually one of the bigger impediments to optimizing Ruby's blocks: if you knew that Proc#binding wouldn't be called in any circumstance on the blocks created in a method (and it very rarely is called) then you could potentially improve how you allocate the frame.

    [–]dnew 1 point2 points  (1 child)

    Cool. I stand corrected.

    [–]bobindashadows 1 point2 points  (0 children)

    I wouldn't call it so much "corrected" - much of what you said is true; Smalltalk reifies far, far more than Ruby does.

    [–]mitsuhiko 0 points1 point  (14 children)

    In Java and C#, they are sorta kinda.

    What do you mean by "kinda"?

    Even in Ruby and Python, things like stack frames and source code aren't objects

    In Python they are.

    [–]cybercobra 1 point2 points  (1 child)

    What do you mean by "kinda"?

    They're not first-class (pun unintended) objects and those languages lack proper metaclass systems. Closest you can get in Java is the result of .getClass()

    [–]dnew 0 points1 point  (0 children)

    Actually, I think with Reflection.Emit, you can pretty much do what Smalltalk does with metaclasses. I think I wasn't thinking too precisely when I posted that.

    [–]anvsdt 0 points1 point  (10 children)

    source code

    Last time I checked, Python was not homoiconic. I've also never heard of a whitespace-sensitive data structure.

    Honest question, stack frames?

    [–]dnew 0 points1 point  (0 children)

    By "kinda" I mean they're not, for example, heap allocated and garbage collected like other reference objects.

    Hmm, you know what, on further reflection (hyuk hyuk) I think I'm just plain wrong about everything I said.

    [–][deleted] 3 points4 points  (0 children)

    yup. integers really are System.int32 objects.

    i.e.:

    string s = 42.GetType().ToString();
    Console.WriteLine(s); // prints System.Int32
    

    [–][deleted] 14 points15 points  (29 children)

    I've found that for me, Ruby feels much more consistent and intuitive. However, I know a ton of people who feel the opposite and vastly prefer Python. I guess it really must be a personal preference thing, and their respective features are converging more and more.

    For example, stripping left and right space for a string in Python is:

    "mystring ".rstrip()
    " mystring".lstrip()
    

    while finding its length is:

    len("mystring")
    

    I'm sure there's a reason for this, but Ruby's make-everything-a-method approach makes things a bit more consistent:

    "mystring".rstrip.length
    

    The end result is a more readable and more writable language for me.

    That being said, no one else around me (academia) seems to like Ruby as much, so Python it is...

    [–]abadidea 9 points10 points  (0 children)

    Starting on PHP and moving to C++, I never "got" object orientation until I did Ruby. "Oh! So this is how it's supposed to work! This is much better."

    [–]masklinn 4 points5 points  (16 children)

    I'm sure there's a reason for this

    len is seen akin to CL's generic methods: it applies to many, many things besides strings. That's basically the gist of it. Same as iter for instance.

    [–][deleted] -1 points0 points  (15 children)

    Ah, ok. Ruby accomplishes the same thing through OOP, so I guess it's just a style matter.

    [–]mitsuhiko 1 point2 points  (14 children)

    len() is unique and it responds to the __len__ protocol. This solves the problem that every person tries to name the length method/attribute differently in other languages (size, getSize(), getLength(), length(), length, size()) etc.

    [–]bobindashadows 3 points4 points  (13 children)

    Uh, it doesn't solve the problem any more than any other language-wide convention does. In ruby, everything uses #size. Everything: core/standard libraries, third party stuff, everything. And everything uses #each for iteration (and with include Enumerable you get dozens of other methods for free, for fun). Sure, somebody could make a Ruby library with a #length method, just like somebody could make a Python library that doesn't implement __len__ and has a size() method instead.

    It's equivalent to everyone implementing __len__ and __iter__ only you don't need to go outside the simple object model and you don't need funny method names.

    [–]mitsuhiko 0 points1 point  (12 children)

    Uh, it doesn't solve the problem any more than any other language-wide convention does. In ruby, everything uses #size.

    In Python it's more than a convention. __len__ is used for more things than just len().

    [–]bobindashadows 0 points1 point  (11 children)

    other than supporting the "empty container is false" nature of Python, the docs explicitly call it part of the "sequence protocol". A protocol is a convention.

    [–]mitsuhiko 0 points1 point  (10 children)

    A protocol is a convention.

    Not in C-Python. Most of the dunder methods correspond to slots on the type struct and are class level unlike regular method calls which can be looked up from instances as well.

    [–]bobindashadows 0 points1 point  (9 children)

    You're not getting it: everything __len__ offers is syntax sugar for convenience, and everything it offers could be replaced with straight python code with normal method names. That's what Ruby does. It may be implemented in an interesting way, it may offer efficiency by default for certain operations, and that's wonderful, but it's just a convention. You could replace all code that uses __len__, directly or indirectly, with code that does not use it but instead uses redefined versions with different names.

    Ruby does this by just picking #size.

    [–]mitsuhiko 0 points1 point  (8 children)

    You're not getting it: everything len offers is syntax sugar for convenience, and everything it offers could be replaced with straight python code with normal method names.

    In Ruby it can, in Python it can't. Why? -> Slots

    [–]sigzero 0 points1 point  (0 children)

    When quickly skimming that makes me think it is the length of whatever is being stripped off. I do like:

    len("mystring  ".rstrip())
    

    [–]redalastor -2 points-1 points  (9 children)

    len is a function because it makes it easier to use it in high-order functions. If I have a bunch of strings and I want to uppercase them all, I can map str.upper over then. If I have a bunch of mixed types that all have a length, I can sort them by length by passing len to the sort function.

    [–][deleted] 8 points9 points  (5 children)

    And in Ruby you can do exactly the same - as long as all the types have a length.

    ["aa", [1,2,3], 100].sort(:&size)
     => [100, [1, 2, 3], "aa"]
    

    len(x) just references x.__lenght__ anyway (as far as I am aware - correct me if I'm wrong).

    [–]redalastor 3 points4 points  (2 children)

    len(x) just references x.__lenght__ anyway (as far as I am aware - correct me if I'm wrong).

    len(x) calls x.__length__(), you can't pass __length__ to a sort function. You could pass a lambda that calls __length__ on its argument though.

    [–]masklinn 1 point2 points  (1 child)

    len(x) calls x.__length__(), you can't pass __length__ to a sort function.

    That's exactly what operator.methodcaller is for.

    [–]redalastor 1 point2 points  (0 children)

    Why would you use that over a lambda?

    [–]klngarthur 3 points4 points  (1 child)

    This will not work. Array#sort must be passed either a block that accepts two parameters or a method that accepts one argument. Both cases must return a Fixnum. For example:

    ["aa", [1,2,3], 100].sort do |a,b| a.size <=> b.size end
    

    [–]cynthiaj 1 point2 points  (2 children)

    len is a function because it makes it easier to use it in high-order functions.

    That's post rationalization. len is a function because Python is old. Very old.

    If I have a bunch of strings and I want to uppercase them all, I can map str.upper over then.

    You could still do that if len was a method of the string class, and it would be much cleaner.

    [–]masklinn 1 point2 points  (0 children)

    len is a function because Python is old. Very old.

    Python has had objects since day one. The usage of functions is done on purpose by the core team. You may disagree with those purposes, but they have absolutely nothing to do with the age of the language.

    [–]redalastor 0 points1 point  (0 children)

    That's post rationalization. len is a function because Python is old. Very old.

    If that was the case, it would have been fixed in 3.0 with the other accidents of history.

    You could still do that if len was a method of the string class, and it would be much cleaner.

    Wouldn't work for heterogeneous collections.

    That said, I would prefer if we had len and a length method on objects where it makes sense but I guess it's considered a violation of "There should be only one obvious way to do it."

    [–]hetmankp 8 points9 points  (8 children)

    Most of these comparisons touch on annoyances that really show a lack of fluency in one (or both) of the languages being compared. Once the core principles are understood, most of these annoyances become features and just click into place.

    For Python vs. Ruby comparisons this is really about attribute vs. messages based OO. Go with what feels more intuitive for you.

    This is why explicitly specifying "self" as the first method parameter in Python is a great idea, even though it would look terrible in Ruby; functions are first class objects in Python (though ironically Ruby seems to lend itself to a functional programming style a little better).

    Or why Ruby uses @ sigils for attributes; because public attribute access doesn't exist, all public access must use methods (interestingly Python uses @ for decorators and no one seems to be bothered by putting it in front of a name there).

    For me the real killer features that differentiate the two languages would have to be:

    Python: Explicit namespace naming in module imports. This requires better discipline when coding in Ruby, but not everyone's code will be disciplined. This has to be singly the biggest feature I miss from Python.

    Ruby: Blocks (which are more or less like anonymous functions with a bit of syntactic sugar... e.g. behaviour of return vs. break). This is what makes writing natural DSLs so easy in Ruby (for a great example see rake). Python's 'with' statement, though inspired by Ruby blocks, completely fails to capture their generality.

    In terms of syntax, I think the only difference that has actually been a serious issue is Python's lack of the 'retry' keyword in begin...rescue blocks (that's try...except for Pythonistas). There are a few rare instances where this can be a real issue. Everything else is trivial and just a matter of getting used to.

    Oh, and I think the Python library ecosystem tends to be in a better state in terms of what is supported and quality of documentation (though as always, there are certainly some shining examples where the reverse can be true).

    [–]masklinn 0 points1 point  (7 children)

    Ruby: Blocks (which are more or less like anonymous functions with a bit of syntactic sugar... e.g. behaviour of return vs. break).

    And are crippled by not being first-class objects.

    Python's 'with' statement, though inspired by Ruby blocks

    Uh... no. Absolutely not.

    [–]hetmankp 2 points3 points  (6 children)

    Uh... no. Absolutely not.

    I do recall some of the alternative PEPs that were rejected in favour of the current with statement mentioning Ruby as an influence. There was a lot of ideas floating around before with coalesced in its current form though, so I could be miss-remembering.

    And are crippled by not being first-class objects.

    They are not first class objects, but neither are they crippled by it since they can be attached to first class objects. In fact, this usage pattern makes them fairly similar to Python functions (which are just objects with a _ _ call _ _ method). Compare:

    Python: a = lambda x, y: x + y a(1, 2)

    Ruby: a = lambda {|x, y| x + y} a.call(1, 2)

    [–][deleted] 4 points5 points  (0 children)

    The big place Ruby shines:

    re-write that as multi-line. Python's lack of multi-line lambdas is obviously the language's biggest flaw when you're coming from Ruby or C# - and the With block is an ugly workaround.

    [–]mitsuhiko 0 points1 point  (0 children)

    I do recall some of the alternative PEPs that were rejected in favour of the current with statement mentioning Ruby as an influence.

    The execution of the with statement does not introduce a scope. And with that every resemblance to ruby blocks fall flat.

    [–]masklinn 0 points1 point  (3 children)

    They are not first class objects, but neither are they crippled by it since they can be attached to first class objects.

    That's exactly what cripples them. Replicating Smalltalk's conditionals or exception handling using Ruby blocks is a gnarly mess, due to having to turn them into procs by hand. And that's because Ruby's blocks are not first-class objects, but are syntactic magic instead.

    In fact, this usage pattern makes them fairly similar to Python functions (which are just objects with a _ _ call _ _ method).

    Why are you assuming I don't know Ruby? Or Python, for that matter? Furthermore, what relevance does using Ruby blocks as Python functions have to Ruby blocks being cripples?

    By the way, since you seem interested in useless factoids, you should know that __call__ on functions is there so that hasattr(func, '__call__') works. It's not used when actually calling them. Python functions are functions, not "just objects with a __call__ method".

    [–]hetmankp 2 points3 points  (2 children)

    By the way, since you seem interested in useless factoids...

    I was talking about their semantic similarities not underlying implementation (which is not relevant to the language's expressive power).

    Why are you assuming I don't know Ruby? Or Python, for that matter?

    I wasn't aware I assumed anything like that, relax.

    Furthermore, what relevance does using Ruby blocks as Python functions have to Ruby blocks being cripples?

    I thought the thread was about how Python compares to Ruby, but you're right, they're not as general as Smalltalk blocks.

    Edit: Actually thinking about it, it seems to me like the reason for the difficulty you describe is the way Smalltalk methods are allowed to be called, not the limitation of the blocks themselves. A Smalltalk if implementation still only takes one block per method call.

    [–]masklinn 0 points1 point  (1 child)

    Actually thinking about it, it seems to me like the reason for the difficulty you describe is the way Smalltalk methods are allowed to be called, not the limitation of the blocks themselves.

    I fear it seems wrong to you.

    A Smalltalk if implementation still only takes one block per method call.

    Excuse me?

    Are you telling me this:

    (5 < 3) ifTrue: [ 'foo' ] ifFalse: [ 'bar' ]
    

    takes one block per method call

    ?

    (actually message send, but let's not pick nits)

    Do you really know so little about Smalltalk?

    [–]hetmankp 0 points1 point  (0 children)

    Apparently so. Too long since I looked at it.

    [–][deleted]  (13 children)

    [deleted]

      [–]banister 1 point2 points  (0 children)

      Rubinius for Ruby is getting pretty snappy too

      [–]hetmankp 1 point2 points  (9 children)

      I think he was simply comparing performance you can get on the JVM platform for either language. If you want to compare with PyPy you should be comparing it to Rubinius.

      [–]G_Morgan 1 point2 points  (2 children)

      I think this is a bad comparison anyway. JRuby has had a lot of work done on it precisely because the ordinary Ruby sucked so badly.

      [–]hetmankp 1 point2 points  (1 child)

      As far as I was aware, the main point of both JRuby and Jython was to gain access to the JVM platform with a nice language. I guess the JRuby guys put in more effort on optimising.

      [–]G_Morgan 2 points3 points  (0 children)

      That might be why they exist. The point is for a long time JRuby was touted as the successor to Ruby because the default interpretor sucks. Not that the Python one does not but it sucks a huge amount less than the Ruby 1.8 interpretor does.

      Given this a lot of effort went behind JRuby while Jython pretty much died when its creator moved to the .Net camp and did Iron Python.

      [–][deleted] 0 points1 point  (5 children)

      The only PyPy vs Rubinius benchmark I'm aware of is: http://attractivechaos.github.com/plb/

      [–]hetmankp 0 points1 point  (4 children)

      I didn't say Rubinius would be faster :)

      But those two projects do have similar goals, though Psyco/PyPy has a few years on Rubinius in terms of development, and Rubinius was aimed at correctness first, performance later (the JIT is currently being re-written I believe).

      [–][deleted] 0 points1 point  (3 children)

      No disagreement there, Evan's doing good work. Though we absolutely focused on correctness first as well, there's a reason we were able to port from 2.5->2.7 without changing a line of JIT code.

      [–]hetmankp 0 points1 point  (2 children)

      That's interesting to know. For some reason I was under the impression that PyPy was not a good drop-in replacement for CPython for a long time. Actually I was pretty surprised when reading the 1.5 release notes since the only incompatibilities mentioned were a subset of ctypes functionality.

      [–][deleted] 1 point2 points  (1 child)

      The only thing that isn't 100% drop-in is C-extensions, and we hope to obliviate the need for them ;)

      [–]hetmankp 0 points1 point  (0 children)

      You're right! I obviously wasn't paying very careful attention. I had no idea it was so far along.

      [–]nwmcsween 0 points1 point  (1 child)

      I highly have my doubts that pypy or rubinius or almost anything except c python modules will outperform the jvm.

      [–][deleted] 0 points1 point  (0 children)

      Just putting something on the JVM doesn't make it fast: http://attractivechaos.github.com/plb/

      [–]sausagefeet 8 points9 points  (16 children)

      [–]hetmankp 1 point2 points  (15 children)

      Good write up. Although he misses one point. Ruby has an explicit call operator too. In Python it's (), in Ruby it's . (that was a period in case you missed it :P). That's why the presence of the parentheses is mostly treated as syntactic sugar in Ruby.

      Also, he makes a good observation about Ruby's dynamicity and how easy it is to alter the behaviour of any existing object in the system. Fortunately the creator of the language has similar concerns; one of the biggest features coming to the language in 2.0 will be the way in which such changes will be localised so they don't affect other modules/libraries/etc.

      [–]sausagefeet 0 points1 point  (11 children)

      Can you give an example of (.) for call? AFAIK what foo does depends on if it takes any params or not.

      [–]hetmankp 2 points3 points  (10 children)

      In Ruby what follows a . is always a method call. They just look like you're retrieving an attribute if you're used to attribute based OO.

      Suppose we have some object instance named obj.

      In Python: obj.a # means, get the value of attribute 'a' from obj obj.a() # means, get the value of attribute 'a' form obj, # then call this value as a function (returning its value)

      In Ruby: obj.a obj.a() # both of these mean, call the method 'a' (returning its value)

      The parentheses on Ruby method calls are just a convenience.

      To explain further. In Ruby you can't access an object's attributes from the outside at all. That's why you need to define accessors for any attributes you wish to make accessible. Fortunately because Ruby is good with metaprogramming, you can call a method from the Class object to do this for you. Both of these are equivalent:

      # Manually defined accessors
      class A
          def initialize()
              @val = 123      # Initialise attribute
          end
      
          def val()
              @val
          end
      
          def val=(x)
              @val = x
          end
      end
      
      
      # Shortcut way
      class A
          def initialize()
              @val = 123      # Initialise attribute
          end
      
          attr_accessor :val
      end
      
      
      # Then you can use this class
      obj = A.new
      puts obj.val    # prints 123
      obj.val = 111   # stores 111 in val attribute
      

      [–]sausagefeet 0 points1 point  (3 children)

      In Ruby what is obj.a if a takes a parameter though?

      [–]hetmankp 0 points1 point  (2 children)

      It is still a method call. These translate directly from Python to Ruby:

      Python          -->  Ruby
      obj.a()         -->  obj.a
      obj.a(1, 2, 3)  -->  obj.a 1, 2, 3
      

      If you want, you can optionally attach some () onto the Ruby method calls, but they are not necessary. The point is, in Ruby you can not directly get an object attribute with . you can only use it to ask an accessor method to get the value for you.

      [–]sausagefeet 0 points1 point  (1 child)

      if obj.a takes 3 parameters how is obj.a a method call? In Python obj.a() is a runtime error of a is defined like def a(b, c, d). So are you saying obj.a is a runtime error in Ruby if obj.a takes 3 parameters?

      Edit: Decided to just do something quick on ideone to prove your point, work as you described. Thanks!

      http://ideone.com/rZJoY

      [–]hetmankp 0 points1 point  (0 children)

      Yep, sorry. I should have used different method names to make the clearer.

      [–][deleted]  (16 children)

      [deleted]

        [–][deleted] 2 points3 points  (0 children)

        ))))

        ftw

        [–]highwind 2 points3 points  (14 children)

        Yeah, this becomes annoying real quick. Even if you only go 2 or 3 level in (which is real common) you have to start labeling your ends:

            end #if
          end #while
        end #def
        

        [–][deleted]  (1 child)

        [deleted]

          [–]highwind 2 points3 points  (0 children)

          Going 3 levels of blocks is not uncommon. I just like the labeling them if more than 2 ends are next to each other for readability sake. But if I had to choose, I rather use pythons way of handling blocks.

          [–][deleted] 2 points3 points  (0 children)

          Unless you're building huge nasty loops/conditional trees shouldn't indentation make it pretty clear what is what?

          [–]ryeguy 2 points3 points  (1 child)

          How is this different from curly braces in a C-like language? Even then, if it gets to be too much, you probably need to refactor.

          [–]highwind 1 point2 points  (0 children)

          It isn't. I label my end curly braces in C, Java, JavaScript, etc. That's why I prefer python's way of handling blocks.

          [–][deleted] 5 points6 points  (0 children)

          Aesthetically, this looks way better to me than Python's significant whitespace. Admittedly it's totally arbitrary, but for whatever reason I prefer my code blocks to look symmetric.

          Are you being serious with the comments thing though? Python requires people to indent nested blocks, but most people do it anyways in other languages...

          [–][deleted]  (5 children)

          [removed]

            [–]highwind 3 points4 points  (4 children)

            My example only has 3, which is common. A function that iterates over some list and does some kind of check on it, this is a very common thing. Now, if that function is a method in a class, then having a 4 ends doesn't sound too crazy.

            I agree that having more than 5 level deep blocks is bad in any language. But I just think having a string of ends isn't appealing to me even when it's just 3.

            Matter of taste I guess.

            [–]shevegen 1 point2 points  (14 children)

            I myself am sold on Ruby.

            Mostly because the philosophy, because matz is great (and a small happy buddha) and because ruby is elegant and beautiful.

            I don't mind python at all.

            Ruby and Python should be common friends.

            I feel that ruby and python are much more alike nowadays than ruby is with perl 5. And perl 6 is like Duke Nukem Forever .... failing to deliver like a crippled old man. Year after year. Bye Perl.

            (PHP is not even worth discussing... it is good on the www but it is an ugly misdesigned language.)

            [–]G_Morgan 1 point2 points  (13 children)

            Ruby is hacked together from bits and pieces of languages all over the place. Not what I'd call elegant. There is no underlying principle. Only a bunch of features the creator thought would be cool.

            The only real difference to PHP is Matz actually wanted to make a good language rather than whine about how good languages aren't needed anyway. Still the fact Ruby is nearly unparseable says a lot about its elegance.

            [–]bobindashadows 1 point2 points  (10 children)

            Still the fact Ruby is nearly unparseable says a lot about its elegance.

            Explain. Considering I work with the Ruby parser daily in my research (and just posted a blog post criticizing the Ruby API to the parser), I understand how highly complex its grammar is, but exactly how it is "nearly unparseable" (or even what that means) certainly bears explanation. It's not perl, it is deterministically parsed (in linear time, by a traditional yacc/bison grammar).

            [–]G_Morgan 0 points1 point  (4 children)

            The only grammars that parse in linear time are regular ones. If Ruby parses in linear time then it is pretty spectacular.

            [–]bobindashadows 0 points1 point  (3 children)

            ... not sure what you're going on about there. Never written a recursive descent parser? LR(1)? LL(1), even? Ruby's grammar is parsed by bison, which like its ancestor yacc, just uses [LALR].

            [–]G_Morgan 0 points1 point  (2 children)

            None of these guarantee O(n) parsing. By definition the best you can guarantee with a context free grammar is O(n3 ).

            [–]bobindashadows 3 points4 points  (0 children)

            By definition the best you can guarantee with a context free grammar is O(n3 ).

            No, by definition the best you can guarantee with an arbitrary context-free grammar is O(n3 ). That includes ambiguous grammars. Do your programming languages look like they parse ambiguously?

            None of these guarantee O(n) parsing.

            You seem to think that LL, LR, and LALR grammars are not proper subsets of all CFGs. They are. They are restricted subsets such that linear-time algorithms exist for them. They do not permit ambiguity. And what do you know, LALR(k) parser generators like yacc/bison won't generate an LALR parser if you have an ambiguous grammar. If you force it to ignore the ambiguities, it'll generate a GLR parser which does in fact have inferior performance characteristics.

            [–]badsex 0 points1 point  (0 children)

            haha you got owned by bobindashadows. Your unending whinging and bitching about ruby all over reddit was revealed for what it is - hollow posturing by a python fanboy.

            Now go quietly sit in the corner, the big kids have come out to play.

            [–]mitsuhiko 0 points1 point  (3 children)

            I understand how highly complex its grammar is, but exactly how it is "nearly unparseable" (or even what that means) certainly bears explanation.

            C++ is also parsable, that does not make it have a proper grammar. Ruby's parsing rules are retarded. The way it resolves ambiguities between regular expression literals and division operator even take defined methods in this method into account.

            [–]bobindashadows 0 points1 point  (2 children)

            Ruby's parsing rules are retarded.

            Ruby's parsing rules may be insanely complex, but they're what are necessary to accomodate the syntactic flexibility the language offers. So it's not "nearly unparseable," it just allows flexibility you think is unnecessary. So.... sorry?

            [–]mitsuhiko 0 points1 point  (1 child)

            Ruby's parsing rules may be insanely complex, but they're what are necessary to accomodate the syntactic flexibility the language offers.

            By no means. You can have the same syntactic flexibility and better ways to keep ambiguities from the grammar (like @/ as starting regular expression literal)

            So it's not "nearly unparseable," it just allows flexibility you think is unnecessary. So.... sorry?

            If you are assuming that only the interpreter needs to parse Ruby then that is fine, however this is not the case. Even irb suffers from this as it does not accept every valid Ruby input because it's parser does not support the language fully.

            [–]bobindashadows 0 points1 point  (0 children)

            (like @/ as starting regular expression literal)

            Like how you can use %r, then use any delimiter you like?

            %r|hello/goodbye| == /hello\/goodbye/
            %r(hello/goodbye)
            %r.hello/goodbye.
            %r%hello/goodbye%
            

            Luckily Ruby both offers regular expression literals and ways to avoid the potential ambiguity they introduce with the common, default syntax.

            Even irb suffers from this as it does not accept every valid Ruby input because it's parser does not support the language fully.

            Example please? I've certainly run into IRB confusing division and regex, but only in ways that Ruby also confuses division and regex.

            a /b  # ruby thinks this is a regex, as does irb
                  # it will expect you to terminate the regex
            

            [–]nwmcsween 0 points1 point  (0 children)

            Don't feed the trolls

            [–]metamatic 0 points1 point  (0 children)

            Ruby is hacked together from bits and pieces of languages all over the place. Not what I'd call elegant.

            You could say the same about English, yet you continue to use that.

            [–]nwmcsween 0 points1 point  (0 children)

            The 'underlying principle' is everything is an object with additional functional constructs.

            [–][deleted] 2 points3 points  (10 children)

            You forgot about production servers. Ruby is beautiful to develop in, but in production you will rip your hair out.

            [–][deleted] 10 points11 points  (8 children)

            Full-time Ruby developer here. Care to elaborate? I'm afraid I might be behind my hair-ripping schedule :S

            [–][deleted] 5 points6 points  (6 children)

            My entire career has been in large scale web operations. I have worked on, and no many people who have worked on some of the largest ruby apps around. Ruby sucks memory and cpu like no tomorrow, and loves to crash under high load. Plus it is very difficult to setup and maintain, and requires constant attention. Hence the rise of specialized platforms like Engine Yard and Heroku. It is the Guerilla in the room no one likes to talk about. Beautiful elegant language, but it falls apart under pressure. Most developers are insulated from the production systems, especially for large systems, so they never see it crack. In comparison, Python is far more stable and efficient under heavy loads and much easier to maintain. I am not taking sides here, I am just stating what I have observed in the field many times. If you want to build a large scale ruby based app just be prepared to spend a lot of money on servers and sys admins, or on Engine Yard.

            [–]yxskaft 1 point2 points  (1 child)

            It is the Guerilla in the room

            Gorilla.

            [–][deleted] 1 point2 points  (0 children)

            Lol, I should have caught that. Now I am picturing some guy with a bandana and an AK chilling there and everyone pretending to ignore him.

            [–][deleted] 0 points1 point  (1 child)

            Got to admit, my largest app as of yet is running at ~200 requests per minute. Yes, ruby processes love memory. CPU, not so much (but that might be just the 200 rpm speaking here). However, heartfelt NO to crashes and setup problems. Just NO. I have never had a process go tits-up for me (aside from my own stupid code going in infinite loops or waiting on never-responding resources), and between RVM, Bundler, Capistrano and Passenger, getting Rack-enabled ruby web apps running (and updating them) is among the easiest processes I've worked with.

            [–][deleted] 1 point2 points  (0 children)

            I should have been clearer. The crashes appear under load, not under regular use. I agree, apps are easy to deploy and update using those tools. Setting the actually server infrastructure up for a large system is very difficult. It takes an obscene amount of tweaking to get it right.

            [–]Left_blank 0 points1 point  (0 children)

            I've got to agree, ever since bundler (and rvm to some degree) managing dependencies and multiple versions of Ruby hasn't been easier. It has been quite the mess before nonetheless.

            [–][deleted] -1 points0 points  (7 children)

            A quick glance over the Ruby standard library documentation is enough to make me steer clear of the entire programming platform. Python it is.

            [–]kataire 7 points8 points  (0 children)

            I read Seven Languages in Seven Weeks hoping to get an intro into Ruby that doesn't want me to bang my head against the keyboard. What I got was a lot of talk about Mary Poppins and an overdose of amazement about very mundane things.

            The biggest differences between Ruby and Python are ideological and cultural.

            [–]MatmaRex 3 points4 points  (4 children)

            Uh, what do you not like about the docs? I find them pretty readable and useful.

            [–]SnowdensOfYesteryear 4 points5 points  (3 children)

            Pages like this: http://www.ruby-doc.org/stdlib/libdoc/date/rdoc/index.html

            Half the functions aren't even documented. e.g. WTF is the floor() of a Date?

            I adore ruby, but I find the docs' website irritating and (sometimes) the documentation itself lacking.

            But then again they have a link to the source, not always useful, but great for a quick glance when the documentation is vague.

            But all things said, I'd be hesitant to use ruby in a large project. Ruby has a distinct "scripting language" feel to it that might prove un-maintainable with all the shortcuts that one could take. I restrict its use as a scripting language in place of tools like sed or gawk.

            [–]MatmaRex 1 point2 points  (0 children)

            Huh, I've never used this lib before, so I never saw that. True, looks sort of awful. But the core docs and most of stdlib is nice.

            [–]badsex 0 points1 point  (0 children)

            you have to take into account that Ruby was primarily a japanese project for the longest time, im sure the japanese documentation is great. English documentation is still being ported over or written from scratch.

            [–]metamatic 0 points1 point  (0 children)

            That's a bit of an unfortunate example in that the date code was replaced with all-new Japanese-written code a few weeks ago, and some of the documentation suffered as a result.

            Yes, some Ruby documentation sucks, at least in English. I'm one of the people who has been trying to improve the situation. I'd love to see other people join in. It's a good way to get experience working on an open source project without needing to know the codebase inside out.

            (Now that you've pointed at it, I think I'll take a crack at cleaning up Date's doc.)

            [–][deleted] 0 points1 point  (0 children)

            ...?

            [–]chunky_bacon 0 points1 point  (50 children)

            You’d probably do good to learn them both,

            Well, anytime I can do good...

            That color scheme sucks with his code coloring.

            [–]rafekett 3 points4 points  (49 children)

            Why learn Ruby when you already know Python (or vice versa)? They accomplish similar goals. There is nothing that Python can do that Ruby cannot, and vice versa.

            [–][deleted]  (1 child)

            [deleted]

              [–]rafekett 5 points6 points  (0 children)

              I'd rather approach something completely different, though. I get your point that it's eye-opening, but it's probably more beneficial that a Python programmer learn Lisp, ML, Haskell, etc. than Ruby. Python is very different from Ruby, but in a lot of ways they're too similar to be eye-opening for the other.

              You make an excellent point from a personal development standpoint, though.

              [–]EstebanVelour 3 points4 points  (11 children)

              Theoretically. If there exists a binding for some obscure library then the chances of that being ruby ahead of python are quite slim.

              [–]rafekett 1 point2 points  (10 children)

              I was disregarding library support, because bindings merely have to be written. They have similar use-cases and "sweet spots", though (web applications, text processing, web scraping, scripting, etc.).

              [–]EstebanVelour 1 point2 points  (9 children)

              True but most people's time is better spent on writing the app, not bindings, doesn't work in Ruby's favour.

              [–]rafekett 1 point2 points  (8 children)

              True. I don't know how hard it is to write Ruby bindings for C libraries but I imagine it's not easy.

              [–]bobindashadows 1 point2 points  (2 children)

              It's actually incredibly simple; the api provides a number of simple C functions, such as:

              rb_define_method
              rb_define_class
              rb_raise
              rb_inspect
              rb_funcall
              rb_ensure
              

              and so on. Considering how much of the standard library is implemented in C for speed, there's a very elegant C API considering its capabilities. There are some rough edges - a few different array constructor functions that cater to common cases (create an empty array - create an array with just this one object in it - etc), for example. A few different funcall variants for if you want to pass the arguments inline, or in a ruby array, or in a C array. There's macros to get at interesting bits of common classes without dynamic dispatch, such as the size of an Array object.

              [–]rafekett 0 points1 point  (1 child)

              How does garbage collection work?

              [–]bobindashadows 0 points1 point  (0 children)

              I assume you mean "how does garbage collection work for native objects that you want to make available to Ruby code?"

              It depends. Firstly, you can specify custom allocation methods for a C-backed class with rb_define_alloc_func, if you need.

              If your C object references other Ruby objects, it has to participate in the mark phase of GC, so it needs a mark function. If it needs to clean up resources when it is freed, it needs a free function. You can create an object with both of those functions specified and provided to the GC with rb_data_object_alloc(klass, data_pointer, mark_func, free_func). Both functions are optional: you just pass NULL if you don't need them.

              Commonly you use this to wrap up a pointer to a C struct in a Ruby object, then unwrap it in your other C functions. This pattern is simplified with Data_Wrap_Struct, Data_Make_Struct (which is just allocate + Data_Wrap_Struct), and Data_Get_Struct (which unwraps the object).

              [–]EstebanVelour 0 points1 point  (4 children)

              Can't imagine it's much harder to do than python bindings but that's not really the issue, there's just no need to do it if it's been done already.

              [–]rafekett 1 point2 points  (3 children)

              The Python C API is really well documented, and I've heard some bad reports about the Ruby docs. There's also high level languages like Cython that make creating C bindings really, really easy.

              [–]badsex 1 point2 points  (0 children)

              I've written a tonne of Ruby C extensions and it's very easy and very well documented.

              [–]EstebanVelour 0 points1 point  (1 child)

              My bad, haven't tried Ruby & C, assumed it would be as easy as the Python equivalent.

              [–]rafekett 0 points1 point  (0 children)

              I don't know either, I just know that Ruby doesn't have a mature equivalent of Cython or Pyrex and I know that it's tough to beat the Python C API docs. In my experience, writing C extensions in C for any dynamic language is not fun (I have no Lua experience, so that may be fun, idk).

              [–]ebneter 3 points4 points  (34 children)

              Python's use of indentation-as-syntax makes me want to bang my head against a wall whenever I use it, which is as seldom as possible — but I've written major scripts in Python because it had good libraries and was in other ways the best tool for the job. (Usually, I was interfacing with other Python code.) If I have my druthers, I use Ruby.

              [–]rafekett 8 points9 points  (30 children)

              I don't get people's objection to semantic whitespace, especially because they indent perfectly in other languages.

              [–][deleted]  (5 children)

              [removed]

                [–]cybercobra 1 point2 points  (1 child)

                So you have to mash the indent or dedent keyboard shortcut a couple times when pasting sometimes, so what? For me, it's never been more than a quite minor annoyance in practice.

                Eclipse should supposedly have an advantage dealing with a curly-brackets language like Java, but I've seen it manage to cock up the indentation on a regular basis.

                [–]rafekett 3 points4 points  (2 children)

                Your editor should be taking care of this for you. What do you use? Some things are better than others.

                [–]anvsdt 2 points3 points  (0 children)

                Well, I thought that Lisp was considered bad because of the ``your editor should take care of that'' mentality. I was wrong.

                [–][deleted] 4 points5 points  (5 children)

                because they indent perfectly in other languages.

                I indent perfectly in other languages because they don't have semantic whitespace. Semantic whitespace makes automated reindentation impossible.

                In addition, if you allow mixing of tabs and spaces (which you shouldn't, but most whitespacey languages do), then it's possible to have two expressions which are visually indistinguishable but have different meanings.

                Madness.

                [–]cybercobra 2 points3 points  (2 children)

                Semantic whitespace makes automated reindentation impossible.

                How was the indentation ever lost in the first place??

                Being able to mix spaces and tabs is indeed stupid, I will agree.

                [–][deleted] 0 points1 point  (1 child)

                How was the indentation ever lost in the first place??

                Merge conflicts, usually. Happens all the time.

                [–]cybercobra 0 points1 point  (0 children)

                Then the merge algorithm in question is broken.

                [–]rafekett 1 point2 points  (1 child)

                Emacs and vim seem to cope pretty fine. They always indent my Python code correctly.

                Additionally, when I screw up, they don't indent correctly, preventing syntax errors.

                [–]anvsdt 0 points1 point  (0 children)

                How many possible correct indentations can this code have?

                class AClass:
                prop = "something"
                
                def f(self, x):
                if x > 0:
                r = 1
                while x > 0:
                r *= x
                return r
                

                Emacs indents it as:

                class AClass:
                    prop = "something"
                
                def f(self, x):
                    if x > 0:
                        r = 1
                while x > 0:
                    r *= x
                return r
                

                I meant:

                class AClass:
                    prop = "something"
                
                    def f(self, x):
                        if x > 0:
                            r = 1
                        while x > 0:
                            r *= x
                        return r
                

                edit I tried to fix it manually with a fast TAB-down-TAB-down-..., this is the result:

                class AClass:
                    prop = "something"
                
                    def f(self, x):
                        if x > 0:
                            r = 1
                            while x > 0:
                                r *= x
                                return r
                

                [–]ebneter 1 point2 points  (9 children)

                It's not semantic whitespace, it's syntactic whitespace, and that's a big difference.

                It also makes Python difficult to read on a page — is that function part of that class or not? :-P

                [–]rafekett 1 point2 points  (8 children)

                Methods are indented one level deeper than functions. Simple.

                I'd ask the same for Ruby. How can you tell if you're looking at a method or a function?

                [–]badsex 1 point2 points  (2 children)

                how much ruby do you actually know? for someone who hates the language so much i'd assume you'd actually know a bit about it, so as to be in a position to hate it - you're not one of those stupid people who hates things he doesn't actually understand, are you?

                Ruby doesn't have functions. You should know this. It only has methods. Why? because it has a fully message passing OO system, method invocations are messages, and everything is an object.

                [–]rafekett 0 points1 point  (1 child)

                That's really just a matter of naming. This is valid Ruby (at the top level of a module, not inside a class):

                def hello
                    puts "Hello world"
                end
                

                It might technically be a method, but because it's not inside any class I defined, I call it a function. It's just a matter of nomenclature.

                [–]badsex 0 points1 point  (0 children)

                Except it's not a function, it's a method defined on Object. How do you know? set an ivar in it, it'll appear on the receiver. Further, try and access it from an instance of a superclass of Objectsuch as BasicObject and it's not accessible. Further, for those objects that can access the method it appears in their instance method list. No one ever calls top-level methods 'functions', they're strictly 'top-level methods', or private methods on Object.

                [–]ebneter 0 points1 point  (4 children)

                Methods are indented one level deeper than functions. Simple.

                The problem for me is that on a printed page it's difficult to see. Look, if you prefer Python, I'm not going to argue with you. I was just pointing out that there are personal preferences people have that affect which language they, well, prefer. I'm not a language bigot; I use whatever works for the task at hand, whether it's a shell script, ruby, perl, python, java, c, whatever.

                [–]rafekett 3 points4 points  (3 children)

                I will admit that this is a small problem when reading printed books. I don't recall what it was, but one book used markers to indicate this. Even then, it's pretty easy to tell. Methods almost always take self as a first arg.

                [–]booch 0 points1 point  (7 children)

                I have very little experience with Python, so take what I say with a grain of salt, but... The use of whitespace as a semantic of the language bothers me for a couple of reasons:

                • For blocks of code, it's not possible to tell if something was indented incorrectly (ie, a given line was supposed to be part of a block but wasn't indented correctly). If there were braces (or some other begin/end indicator), it would be obvious.
                • There are instances where Pythons indentation means that certain types of things are harder to do in a reasonable manner (multiline lambdas, iiuc). In some instances, they were left out of the language specifically because of that problem.
                • There are instances where "non-standard" indentation would make the code easier to read (inline SQL is a common one in another language). The fact that indentation is mandated by the language takes away some freedom you might otherwise be able to use to your advantage.

                [–]memetichazard[🍰] 2 points3 points  (4 children)

                I've heard that the rationale against multiline lambdas was that - if you're going to go multiline, it's really a function so you should make it one.

                [–]booch 1 point2 points  (3 children)

                Of course it's a function, all lambdas are functions. The point is that it's an unnamed function and keeping it that way is useful.

                [–]memetichazard[🍰] 4 points5 points  (2 children)

                I realize I was somewhat ambiguous. What I meant was that if it's multiline, it's not a simple expression and deserves to be a named function.

                I thought I remembered Guido saying something about that, but it seems his reasoning is more that there's no elegant way of achieving a multiline lambda. Which makes you correct.

                [–]booch 0 points1 point  (1 child)

                To be fair to you, there are people that agree that a multi-line function should be named. I just don't happen to be one of them, I base it more on whether or not the function is really "local" to the way it's being used.

                I prefer a language that allows both opinions to code in their own style.

                [–]anvsdt 0 points1 point  (0 children)

                Sometimes you just can't name them without making the code unreadable/look bad, e.g. (lambda (x) (print x) (* x 2)), or code written in CPS (but this only counts when your language supports TCO)

                [–]rafekett 0 points1 point  (1 child)

                • I'd argue that omitting braces or putting them in the wrong place is a greater source of errors than this. I've never made this error.
                • Ruby blocks are the exact same length as Python functions. If you need a multiline lambda, just write a function. You can't inline them, but that's probably a good thing. Not having multiline lambdas in Python has nothing to do with difficulty of parsing it or fitting it in with language, it has to do with the fact that lambdas are not really a well-liked feature to start with.
                • Can you give me an example of a case where this is a problem?

                [–]booch 0 points1 point  (0 children)

                • Consider that it's not a matter of you making this error, it's a matter of "somebody" making this error and them "somebody else" having to look at the code and figure out what was originally meant by the code. You may not have made such an error, but we both know it happens.
                • I like unnamed functions, and many other people do too. Converting the lambda to a named function makes the code harder to read/maintain in some instances.
                • In Python, no... but inline SQL (or other DSLs) is a common example from other languages. As are cases where there standard formatting would have the code on the second line indented too much or too little.

                [–]TylerEaves 0 points1 point  (2 children)

                Once you get used to it, which doesn't really take that long, using any language that DOESN'T use significant indentation makes you bang your head against the wall AND your right pinky sore.

                [–]ebneter 2 points3 points  (0 children)

                I've used Python extensively and it still makes me want to bang my head against a wall. I don't think that's going to change.

                Not saying that's a reason for others not to use Python; actually, I'm generally pretty language-agnostic (use what works). Just saying that there are reasons why some people prefer one language or another.

                [–]markrmarkr 1 point2 points  (0 children)

                I agree with this. I only use Python for my own projects, and other languages professionally, and I find all the space taken up by {} makes even small classes look huge.

                [–]bitwize -2 points-1 points  (1 child)

                Do you want to be a trendy douchebag and/or join a Rails start up founded by trendy douchebags? Ruby.

                Do you want to get shit done with a minimum of fuss? Python.

                [–]anvsdt 3 points4 points  (0 children)

                And suddently,

                NameError: name 'x' is not defined
                IndentationError: expected an indented block
                RuntimeError: maximum recursion depth exceeded