|
|
|
|
|
by tinco
1031 days ago
|
|
I really wanted to love Python. As a Ruby programmer I thought Python would be like Ruby, but with a prettier syntax because of the syntactic white space. Unfortunately this turned out not to be the case. Here's my gripes with Python as a Ruby developer that really wanted to love Python: There's a bunch of global functions that should have been methods on objects, like `len()`. OO in general seems slapped on later, as evidenced by the weird double underscores, and the explicit this object as first arguments for methods. (OO is core to Ruby and very elegantly implemented imo). Higher order functional programming is a lot more awkward than you would expect from a scripting language that's generally praised for its data processing qualities. It's nice that function definitions are closures but you can't make them anonymously as function arguments, the reason apparently being that Guido didn't want to complicate the parser. This is a contrast with Ruby's most interesting and unique feature, the do syntax which is a syntactic trick making it really easy to use higher order functions that take a single function as their last argument. Sort of an aside, but from an interview I read with Guido I understand that he actually regrets making Python have semantic whitespace, he actually doesn't like it. To me the semantic whitespace is one of Python's few redeeming qualities and I just wish Ruby would have adopted it as well. Maybe if it had we'd all be unanimously using Ruby. |
|
From some angles these are strange, but from where I sit they seem elegant and pragmatic.
The global functions and double underscore methods are part of the same thing: the language defining and enforcing a protocol that many types of objects should support. Other languages do this by having common names (.length() or whatever), but this has problems that the python way avoids:
- it's hard to add new ones because they share the same namespace as user code - they may have different meanings in different contexts (e.g. a line has a length, but isn't iterable) - the language can't enforce the protocol (e.g. len accepts only one argument, checks the result is an integer, and raises the correct exceptions)
For operator overloading, using regular methods with special names is nice because it avoids having special syntax for it, and makes it easier to interactively inspect and experiment with (as you can just call the methods).
The explicit self thing is similar, in that it avoids a load of special syntax: no this keyword, no syntax for static methods, no syntax for superclass calls (until super was added). It even means that there's only really one 'kind' of call.
I can see some confusion about where self actually comes from, but then most languages i've experienced where this is implicit also have corner-cases and awkwardness around it.
IMO these kind of simplifications seem a bit frivolous when looked at in isolation, but end up simplifying your mental model of the language, which helps beginners get more out of it quicker.
> It's nice that function definitions are closures but you can't make them anonymously as function arguments.
I thought this for a while, and it would still be nice in a few situations, but really it's not a burden to name your callbacks, and discouraging overly-clever code isn't a bad thing if you're trying to build an ecosystem that's accessible to as many people as possible. I used to use map/reduce/filter a lot, but most of the time list comprehensions and regular loops end up easier to read.