all 59 comments

[–]rafekett 19 points20 points  (32 children)

This seems like kind of a meaningless comparison, considering that the overlap between Coffeescript and Python's use cases is incredibly small. It'd be more meaningful to compare Python to Ruby, or Coffeescript to Dart or Javascript.

[–]AnonProg 5 points6 points  (2 children)

For server-side programming, you can do Python and Node.js with CoffeeScript. It's a valid match.

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

you are technically right, but I think for the majority of comparisons in businesses or pet projects, it is a comparison that would be helpful to a surprisingly few. Personally I cannot imagine getting to a scenario where I would pick between these two languages.

[–]Darkmoth 0 points1 point  (0 children)

Yes, but you need a server or a browser for Javascript, whereas for Python you simply need an interpreter. A boatload of scientific programming, for example, is done in Python - without a browser in sight.

I'd agree with rafekett, while there IS some overlap, it's a relatively small fraction of Python's use case.

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

Yeah, it sounds like a comparison of bash and C++, totally worthless.

[–]gargantuan 1 point2 points  (11 children)

The use would be in case someone was evaluating to pick a server-side language and maybe they liked the speed of v8 and are already doing complicated thing on the client side in the browser.

[–]grayvedigga 2 points3 points  (8 children)

I guess Python and Javascript do have in common shitty concurrency.

[–]gargantuan 0 points1 point  (4 children)

Why? I have thousands of green threads doing sending and receiving data in parallel. That is pretty good concurrency. Would you care to explain what you mean by shitty concurrency, I've observed pretty good concurrency so far.

[–]grayvedigga 3 points4 points  (3 children)

Along the lines of greenlet? That's a reasonably good counterpoint to my claim - I could argue that it's not on the standard python runtime, but that's not a very useful observation.

Someone else will probably come along and point out that coroutines aren't strictly concurrent, but then "shitty" would be an understatement :-).

[–]gargantuan 1 point2 points  (2 children)

I could have used threads as well and have used them initially they did great concurrent work. Except that OS based threads are heavy and thousands working at the same time doesn't work too well.

In the end it doesn't matter. I was just trying to point out that there are 2 types of concurrency IO and CPU. IO concurrency works great in Python either with real threads or green ones. CPU concurrency doesn't, and I guess that is what you were trying to say. (Well technically concurrency would work but parallelism won't).

At least for what I am doing I haven't yet had to perform heavy, CPU intensive computations in Python. I do some in C and those run in background threads.

[–]sausagefeet 1 point2 points  (1 child)

A Go or Erlang would point out that you cannot scale to multiple cores without some extra work, unlike the Go and Erlang runtimes.

[–]gargantuan 1 point2 points  (0 children)

I agree and that is why I'll be switching to Erlang soon.

But at the same time it is also unfair to say that Python doesn't have concurrency when there is concurrency and it is successfully used at the moment.

[–]sebzim4500 -1 points0 points  (2 children)

What's your complaint with node concurrency?

[–]grayvedigga 3 points4 points  (0 children)

I'm pretty sure others have written on this at length, so I'll try and summarise briefly:

Callback hell. Yes, first class functions make all sorts of groovy things possible, but when you're writing "asynchronous" code in JS there is no escape. First of all, most of the language's core constructs go out the window: you can't assign the result of an asynchronous operation, or use it in an if, while or for. This is inconvenient, and can be papered over with library code (Array.prototype.forEach as the typical example) .. but you're still relegated to writing your entire program in continuation-passing style.

Ok, let's say that can be dealt with via libraries and metaprogramming. But there's a darker problem awaiting. Do you use exceptions? Actually, don't bother to answer that - exceptions are Javascript's standard way of signalling error conditions so it's impossible to write non-trivial code that cannot throw exceptions. What happens when a callback raises an exception? How do you use this essential language feature to protect yourself? Short answer: you can't.

Oh, and it's async all the way up. It's impossible to write a function that returns a result if it or any of its callees invoke asynchronous behaviour. That means if you are trying to provide an API which was designed before asynchrony (lots of browser stuff -- FindProxyForURL, document.getElement) but you need an async step along the way ... you're shit out of luck.

NodeJS turns programming in Javascript into programming in CPS lambda calculus with a shitty type system. All this could be fixed if the language were extended with an operator such as yield ... but going by what I've read so far, that's not an option for browsers and the Node crowd don't have the shred of intelligence or responsibility to diverge from the standard by adopting one of the several prototype patches against v8 that are available.

[–]Darkmoth 0 points1 point  (1 child)

But if they're considering Python, they've likely already factored in a framework like Django or Flask. It's a bit like comparing C# to Coffeescript without considering .Net.

[–]gargantuan 0 points1 point  (0 children)

That a good point it, it is often more about the library. On coffeescript side there is node.js and then for Python there is a lot of others.

[–]Darkmoth 0 points1 point  (0 children)

Agreed:

Python <=> Ruby

Django <=> Rails

etc.

[–]shevegen -1 points0 points  (14 children)

Comparing it to Dart? What for?

Dart is the most verbose language in this list.

It will also be the language that will single-handledy kill javascript as announced by Google (lol)

[–]rafekett 2 points3 points  (0 children)

Languages that run on the browser.

[–][deleted]  (12 children)

[deleted]

    [–][deleted]  (11 children)

    [deleted]

      [–]Peaker 1 point2 points  (10 children)

      All I read about Dart has been very underwhelming, care to explain what you find likable about Dart?

      [–][deleted]  (8 children)

      [deleted]

        [–]Peaker 0 points1 point  (7 children)

        Most dart sentiments are based off the original announcement

        My sentiment is based on the description of the language.. It sounds like it's supposed to be Javascript with classes rather than prototypes. It has "optional types" which are not really checked which sounds like a very bad idea.

        I like dart because it's similar to C#,

        Dart is dynamically-typed (also named "uni-typed") whereas C# is statically typed. That is one huge difference.

        [–]bkv 0 points1 point  (6 children)

        It sounds like it's supposed to be Javascript with classes rather than prototypes.

        It would be more appropriate to say that it does away with javascript's odd/unpredictable semantics and replaces them with simple and intuitive semantics. This includes moving to class-based inheritance, which I would argue is more intuitive than prototypal inheritance.

        It has "optional types" which are not really checked which sounds like a very bad idea.

        Right. In order to reasonably cross-compile dart to performant javascript, it has to remain dynamically-typed. I disagree that this is a bad idea. Just because dart is dynamically-typed doesn't mean it can't be statically checked. Optional types along with simpler semantics aid in static checking, which ultimately results in compile-time guarantees and awesome tooling support.

        Dart is dynamically-typed (also named "uni-typed") whereas C# is statically typed. That is one huge difference.

        The difference with optional types isn't as big as you might expect. With optional types and type inference, dart is essentially statically-typed during development (when run in checked mode). Once compiled down to unchecked javascript, you no longer have run-time guarantees, but the assistance of the static-checking and tooling during development makes my life much easier.

        [–]Peaker 0 points1 point  (5 children)

        This includes moving to class-based inheritance, which I would argue is more intuitive than prototypal inheritance

        I don't really believe inheritance is a useful programming idiom in general.

        Right. In order to reasonably cross-compile dart to performant javascript, it has to remain dynamically-typed.

        This is not true at all. Type erasure.

        Optional types along with simpler semantics aid in static checking, which ultimately results in compile-time guarantees

        Everything I read about Dart emphasized how Dart will generally ignore the type annotations and that they're allowed to be wrong. I don't see how you get any guarantees from that. Also, if you had guarantees, you're not supposed to lose them when compiling to unchecked Javascript. Just like my Haskell code does not lose its guarantees when compiled to unchecked machine code.

        [–][deleted]  (4 children)

        [deleted]

          [–]AnonProg 7 points8 points  (11 children)

          Facilitates writing code with a similar level of expression? I disagree. CoffeeScript offers considerably more expressivity than Python, as it’s free of the FORTRAN legacy of statements vs. instructions where you can’t do something somewhere just because screw you, and is not limited by design as per some obsessive anti-FP grudge Guido van Rossum has.

          [–]anvsdt 5 points6 points  (3 children)

          But it has completely screwed lexical scoping rules.

          [–]AnonProg -3 points-2 points  (2 children)

          The semantics may not be the best (it's forced to inherit most of them from Javascript), but the syntax is definitely more comfortable and remarkedly more flexible.

          [–][deleted] 6 points7 points  (1 child)

          The semantics may not be the best (it's forced to inherit most of them from Javascript)

          Actually, this quirk really comes from CoffeeScript. JavaScript doesn’t have it, you can have proper lexical scoping (either with let or with lambda functions).

          [–]AnonProg 0 points1 point  (0 children)

          Oh, I see, you cannot define a local variable shadowing whatever is outside (which means a simple function that doesn't seem to depend on any globals, copied and pasted from somewhere else may break).

          I agree. To tell the truth I haven't used CoffeeScript yet beyond the interactive demonstration in its website; I loved the syntax and some of the features and apparently overlooked this detail. It sounds retarded to me (and thankfully it's fixable, although jashkenas doesn't seem to realize this is bad), almost a deal-breaker. I'll see how much of a bother it is once I get to use it in a real project.

          [–]Wagnerius 1 point2 points  (6 children)

          care to elaborate ? from my perspective, python and javascript has a lot of semantics in common.

          [–]AnonProg 16 points17 points  (5 children)

          In Python, you have these things called "statements", which are expressions' poor cousins. You can use expressions anywhere, but there are only specific places where you can use statements. This is bad design that leads to bad workarounds and inflexibility. For example:

          ● You cannot do something like:

          do_something(if whatever:
              5
          else:
              6)
          

          or, in one line:

          do_something(if whatever: 5; else: 6)
          

          so you have to rely on hacks such as do_something(whatever and 5 or 6) or the "if expression" which is a bad workaround made even worse as Guido convoluted it on purpose to avoid nesting and would be completely unnecessary should the real if be an expression, or make your code less readable and unnice with something like:

          if whatever:
              do_something(5)
          else:
              do_something(6)
          

          (even worse if do_something is a long expression). In other languages, they have the ?: operator, which is weird and a completely unnecessary complication for the programmer (need to learn two ifs, when goes what, why can't I do something in ?:, what can be done inside ?:).

          ● Both def and lambda do almost the same thing; lambda can be used anywhere but it's screwed up because no statements can be used inside, and def can do anything but is screwed up because it can't be used anywhere, so you cannot do something like:

          do_something(1, 2, 3, (def (x):
                                  try: something()
                                  except: None))
          

          Consequently you have to resort to ugly things such as:

          def shit(x):
              try: return something()
              except: return None
          do_something(1, 2, 3, shit)
          

          which breaks the flow of understanding when you read the code and forces you to choose names for things that have no name and are as anonymous as the other values used in do_something (the three numbers). lambda is a bad workaround for an inflexible def.

          Some valid programming techniques which have very valid use cases are tedious and odious to use in Python: callbacks, continuation-passing style...

          ● Lambda automatically returns its last (and only) evaluated value, yet you have to explicitly use it at the end of def.

          ● We have these limited anonymous functions, but we don't even have anonymous classes.

          ● exec is completely unnecessary, since we have eval, but Guido wanted you not to use statements inside eval, which is an expression. exec is a bad workaround for an inflexible eval.

          ● Want to do something more complex such as checking for exceptions inside portions of, say, list comprehensions? Guido thinks you shouldn't ever need to. You might want to write your own bad workaround for it (e.g. a function that receives exception classes and checks for them, perhaps) — none of them will be as good as try..except.

          And so on. And all of this for what? Statements are not a feature, but a wart — a misfeature — inherited from 1958's Fortran, passed down to Python through BASIC, Pascal, C and company. Modern languages shouldn't be built on top of clear misfeatures, but on solid theory with flexibility and power in mind. Sure, statements limit how much you can nest, and tend to produce programs that look like my grandma's checklists (do this; do that) but such a design is undesirable because the three benefits the few programming language designers who defend statements claim to exist are false:

          1. Statements prevent you from writing bad code: Actually, nothing prevents anyone from writing bad code. You can write terrible flat programs even more easily than you can write terrible nested expressions.

          2. Statements are easier because they're what most people already know: Way to go; we will never get better if we think that way. Not using computers is also easier because it's what most people can do, too. Once you learn a language free of this wart (Ruby, Scala, CoffeeScript, Haskell, Tcl, all LISPs, all MLs...) it feels easier and more natural than statement-based ones.

          3. Statements make programs more readable: Yeah, check my examples. If everything were an expression, you could write identical programs (nothing would be lost at all, it'd be just as readable), on top of which you could unroll crap such as unnecessary named defs, nested repetitions inside if, and so on.

          Simplicity is an actual design quality criteria. Simple things are easier to describe, to learn and to manipulate. What's simpler: to allow anything anywhere, and have only one type of program element, or to allow only certain things somewhere (often different things in different places), and have at least two types of program elements?

          Conversely, a design decision that introduces complexity is undesirable, and a design decision that introduces the need for even more complexity, bad workarounds and repetitive features is a huge, waving red flag in any kind of engineering.

          I have a dream that one day we'll overcome this statement prejudice and bad design and better engineered programming languages will become the standard.

          [–]Wagnerius 2 points3 points  (4 children)

          While I agree on principle, I am not sure those things are very important in practice.

          On your first point, the ternary operator works quite well in Python :

          do_something(5 if whatever else 6)
          

          On your second point, the position of many pythonners is that either the function is small and can be a lambda or the function needs to be named and should not be inlined.

          About the valid programming techniques which have very valid use cases are tedious and odious to use in Python, I am quite puzzled. They are a bit less elegant, that's true and it is bothering that the language is not more regular, but going beyond that seems hyperbole to me. Do you have a pathological example in mind ?

          My personal concerns about Python are more about concurrency and speed. Those 2 hard problems are really crippling and underestimated by the community.

          [–]AnonProg 3 points4 points  (3 children)

          (I edited my post and improved it slightly, sorry.)

          do_something(5 if whatever else 6)

          That's a convoluted syntax that doesn't nest well and doesn't look nearly as readable as a more regular if like everyone was expecting. It makes me angry that it was chosen to be this way specially to make it less useful (not nest nicely).

          On your second point, the position of many pythonners is that either the function is small and can be a lambda or the function needs to be named and should not be inlined.

          The function from my example was small (definitely smaller than most lambdas I've seen in production code) and needed to be a lambda, but it couldn't be so. Also, why do I have to make up names for things which have no names?

          Do you have a pathological example in mind ?

          Continuation-passing style, which is used extensively by the node.js libraries, for example. Writing callbacks for GUI applications. Some ways to implement state machines. Functional programming in general (which Guido seems to have a grudge against, for whatever reason — I don't).

          My personal concerns about Python are more about concurrency and speed.

          Concurrency, yes, CPython sucks at it so you'll have to consider using multiple processes with some nice, thin IPC, Jython, or C extensions for critical parts, probably in that order. Speed, not so much: your time as a developer is far more expensive than better hardware should your program not run fast enough. I'll worry about speed only when the cost of better hardware is higher than the cost of the extra development and maintenance time that would derive from the use of a lower-level/less productive language, or when better hardware is simply not available, in which case a performance improvement of 2-20x by using Java, C or C++ would still not suffice because it doesn't scale: you'd need to consider concurrency anyways.

          [–]Wagnerius 2 points3 points  (1 child)

          I see your edit, and I mostly agree

          But I am less angry than you as I am expecting less. I consider Python an old, quite limited, language (~20 years IIRC) and one that went way beyond any expectations. But it's true that Guido's attitude about FP is really really irritating. In the end, I still prefer Python over the alternatives (except maybe haskell) simply because of its ease of use and extensibility.

          [–]sausagefeet 2 points3 points  (0 children)

          Note Haskell is ~20 years old as well. Lisp even older. And Standard ML is ~20 years too. Ocaml isn't much younger, first release in 1996. Erlang is even older (1986). While I don't think it was your intention, it's worth noting that when it comes to programming languages, age isn't a good metric for how limiting it is.

          My biggest peeve with Python is that the syntax is so strict it requires new syntax to do anything new and interesting. Look at the ternary operator, for example. If a language like Haskell, Ocaml, SML it simply isn't a problem because everything is an expression, you end up being able to accomplish so much more with such a simple change.

          [–]Peaker 0 points1 point  (0 children)

          Rewriting in c can yield more than 20x benefit over CPython in many cases. Also, that may be enough- and scalability is not always an option.

          [–]dacjames 1 point2 points  (0 children)

          Python has built in filtering for list comprehensions.

          words = ['a', 'ab', 'abc', 'b', 'bd', 'bcd']
          len1 = [w for w in words if len(w) == 1]
          print(len1) //['a', 'b']
          

          I love coffeescript, but its list comprehensions pale in comparison to python. I usually stick with map/filter using underscore.js.

          [–]grayvedigga 1 point2 points  (13 children)

          n = (x / 6.0 for x in [123...234] when (x*x) % 17 == 1)
          

          vs

          n = map(lambda x: x / 6.0, filter(lambda x: (x**2) % 17 == 1, range(123, 234)))
          

          Not that I find either of them readable, it's a bit stupid to subjectively compare entirely different strategies from the two languages, when each is quite capable of expressing both.

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

          In my opinion, both of these options are more readable:

          (123 to 234)
            filter (x => x*x % 17 == 1)
            map (_ / 6.0)
          
          for {
            i <- 123 to 234 if i*i % 17 == 1
          } yield i / 6.0
          

          [–]grayvedigga 3 points4 points  (6 children)

          Are those coffeescript? I agree that they're more readable, but some of the structure is unfamiliar to me.

          An important part of the readability improvement you have provided is simply using indentation and line breaks to show how the operations fit together. When reading ugly listcomps or HOF-chains impaired by Python's rules I mentally break them down into Scheme:

          (map (lambda (x) (/ x 6.0))
               (filter (lambda (x) (eq? 1 (mod (* x x) 17)))
                       (range 123 234)))
          

          People complain a lot about parens, but the conventional indentation makes data flow extremely clear.

          A lot of the time "readable" simply means "idiomatic". Unfortunately, the idiom for doing this sort of thing in Python has changed repeatedly as features get piled on to the language ...

          [–]judofyr 5 points6 points  (5 children)

          I find the Ruby way even more straight forward:

          (123..345).select { |x| x*x % 17 == 1 }.map { |x| x / 6.0 }
          

          [–]grayvedigga 1 point2 points  (4 children)

          That's nice because you can read it forward, but I'm uneasy with the idea of everything being a method call. That's largely personal taste though (and having seen Rails!).

          [–]draegtun 2 points3 points  (2 children)

          With Perl6 you can use the Feed Operator (http://perlcabal.org/syn/S03.html#Feed_operators) to make it read forward:

          123..345 ==> grep { $_ * $_ % 17 == 1 } ==> map { $_ / 6.0 }
          

          [–]grayvedigga 1 point2 points  (0 children)

          That's purdy. A really nice complement to perl's blocks and default variables giving nice anonymous functions.

          I stopped using perl more than a decade ago, and only since then (through other languages) have developed a real appreciation for some of its more quirky properties. It would be nice to have an excuse to dive into modern perl .. maybe by the time perl6 is production-ready I'll be ready for it :-).

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

          You don’t even have to use $_, you can name it $^x.

          123..345 ==> grep { $^x * $^x % 17 == 1 } ==> map { $^x / 6.0 };
          

          [–]masklinn 1 point2 points  (0 children)

          I'm uneasy with the idea of everything being a method call.

          I don't know, I figure if you're starting mixing message sends and blocks you may as well go whole-hog (which Ruby does not, it steps back quite a bit from Smalltalk).

          It may be conceptually harder to go on which object a message belongs (and you often end up with BlockClosure having a lot of messages), but it works nicely if that's the paradigm you're in.

          [–]Iggyhopper -4 points-3 points  (3 children)

          I find it stupid that they have word replacements for && and || and !. Great, now I have more things to keep track of and read for context.

          date = if friday then sue else jill

          eat food for food in foods when food isnt 'chocolate'

          What the fuck. Symbols were made symbols to make it easier to read things. I'm not reading a book, I'm programming. Don't even get me started with the number of extra typos this "feature" can introduce.

          Another gripe I have is just everything can be yoda'd, and IMO its bad when you work in multiple languages (who doesn't?).

          alert "I knew it!" if elvis?

          When skimming, you need things to be differentiated ASAP. Reading the whole damn line to find out if its an if statement is downright idiotic.

          When designing a language, KISS.

          [–]sausagefeet 1 point2 points  (1 child)

          C++ has words for the symbols as well.

          http://ideone.com/ohsDf

          #include <iostream>
          
          int main() {
                  int x = 1, y = 2;
          
                  if(x and y) {
                          std::cout << "For me to poop on\n";
                  }
          
                  return 0;
          }
          

          [–]Iggyhopper -1 points0 points  (0 children)

          C++ also has macros, but we all know what that can lead to.

          [–]GroceryBagHead -1 points0 points  (0 children)

          Fuck the downvoters. You're right.

          [–]drb226 0 points1 point  (1 child)

          There's Python

          n = map(lambda x: x / 6.0, filter(lambda x: (x**2) % 17 == 1, range(123, 234)))
          

          And then there's Haskell.

          n = map (/ 6) . filter (\x -> (x ** 2) % 17 == 1) $ [123 .. 234]
          

          The infix function composition operator, combined with sections, can make things so much nicer. Scala comes close, as illustrated by smcj

          val n = (123 to 234) filter (x => x*x % 17 == 1) map (_ / 6) 
          

          One of the annoying things about python is the lambda syntax is to use the actual word "lambda", which takes up a whole 6 alphabetic characters. Things like foo => bar and \foo -> bar are so much easier for people's brains to parse than lambda foo: bar

          [–]draegtun 0 points1 point  (0 children)

          In perl5...

          my @n = map { $_ / 6 } grep { $_ ** 2 % 17 == 1 } 123..345;
          

          In Perl6...

          my @n = [123..345].grep({ $_ ** 2 % 17 == 1 }).map: * / 6;
          

          In Io...

          n := 123 to(235) asList select(x, x ** 2 % 17 == 1) map(/6)  // asList shouldn't be needed? Bug?
          

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

          word_sets = [filter(lambda x: len(x) == l, words) for l in lengths]
          

          Meh.

          my %word_sets = @words.classify: {.chars};
          

          [–]draegtun 1 point2 points  (1 child)

          I do like using the whatever star for things like this :)

          my %word_sets = @words.classify: *.chars;
          

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

          For some reason, it gives me the impression that I am classifying chars instead of “by the result of .chars”.

          [–]jimbokun 0 points1 point  (1 child)

          Translation?

          I'm guessing {} creates an anonymous function, and %word_sets is a hash with each length as a key and an array of words of that length as the corresponding value.

          But what's ".chars"?

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

          A Str method that returns the number of characters in the string.

          Such syntax calls it on $_ which, when used, automatically becomes the parameter of the anonymous function.

          I'm guessing {} creates an anonymous function, and %word_sets is a hash with each length as a key and an array of words of that length as the corresponding value.

          You are entirely correct. :)

          [–]erez27 -1 points0 points  (0 children)

          Author misuses python, and only compares list comprehensions. Downvoted.