Last week, I wrote about how I set up Xcode to run Python. It’s been working great. Xcode may not be everyone’s cup of tea, but I love it. Syntax highlighting, familiar keybindings, symbol completion. I couldn’t be happier. A lot of people pushed me to use Pycharm community edition, but while I’ve installed it and tried it a few times, I keep going back to Xcode. Warts and all.
I haven’t logged many hours in Python but it’s been a fascinating language experience. Let me go all metaphor on you. Way back in the 90’s there was this show called “Sliders“, about a bunch of people moving between parallel worlds. Almost everything was the same from world to world — normal humans, trees, buildings, whatever — but there were always fundamental differences in the culture and the people that always reminded you that you weren’t home.
Python is the Sliders version of Swift, the one where Chris Lattner was never born. Everything is eerily familiar and nothing is quite right. Where are my value types? My generics? My type extensions. Let me throw out another metaphor — one that will probably resonate with even fewer people: Python is the language version of the Nethack Rogue Level, where you enter “what seems to be an older, more primitive world.” It’s all familiar. Nothing is exactly the same.
This morning, I attempted to extend a type. I’m working with Anki’s Cozmo robot SDK, which is written for Python 3.5.1 or later. I’m trying to reconfigure many of the basic calls into more appropriate chunks suitable for teaching kids some programming basics.
Instead of focusing on asynchronous callbacks and exceptions, I want to provide really simple blocks that extend the robot type API in a way that hides nearly all the implementation details. I’m trying to build, in a way, a Python version of Swift Playgrounds but with a real robot. (And it’s going well, but more about that in another post.)
What I found was that Python really doesn’t want to extend types. You can subclass. You can compose. But so far, I haven’t found a way to add an extension
that services an existing type. When I asked around, the Python gurus on freenode recommended I stop worrying about polluting the global namespace and embrace freestanding functions as needed.
Oh, my delicate Swift sensibilities! Adding global functions and constants? Cluttering the global namespace? I find myself clinging to Swift conventions. I create enumerations and type my arguments:
class Direction(IntEnum): '''Permitted driving directions.''' forward = 1 backward = -1 def drive(robot: cozmo.robot.Robot, direction: Direction = Direction.forward): ...
The Cozmo SDK defines its constants like this:
LEFT = 1 RIGHT = 2 TOP = 4 BOTTOM = 8
I don’t think I’m in Swift-land anymore.
A lot of the things I like most about Python appear to be fairly new, like that ability to type arguments. I’m assured by some Pythonistas that this is almost entirely syntactic sugar, and there appears to be no type-checking, inference, or casting applied to calls.
I thought I would really hate the indentation-based scoping but I don’t. It’s easy to use (start a scope with a colon, indent 4 spaces for that scope). It reads well. It’s clean. Non-braced scoping ended up being a complete non-issue for me, and I mildly admire its clean look.
I’m less excited by Python’s take on structured documentation. The standard is outlined in PEP-257. Unlike Apple’s Swift Documentation Markup, Python markup doesn’t seem to support specific in-line tool use in addition to document generation. I’m sensitive to how much better Swift creates a structured system for detailing parameters, error conditions, return types, and descriptions, and how it scales from types to functions and methods to individual instances and provides Xcode integration.
So much in Python is very similar to Swift but with a slight twist to it. Closures? Lambdas are in there. Mapping? That’s there too. Partial application? Seems to be. Most times that I reach for a tool in my existing proficiencies, I can usually find a Python equivalent such as list comprehension, which is basically mapping across sequences and collections.
I’m sorely missing my value types. One of the first things I did when trying to work through some tutorials was to try to create a skeleton dictionary rather than type out full dictionaries for each instance. I quickly learned Python uses reference types:
# the original dict was more complicated studentDict = {"name" : "", "tests" : []} joe = studentDict # create joe joe["name"] = "joe" bob = studentDict # create bob bob["name"] = "bob" # reference type print(joe) # {'tests': [], 'name': 'bob'} print(bob) # {'tests': [], 'name': 'bob'}
Oops.
In any case, I’m still really really new to the language given my full-court-press on finishing Swift Style. As much as I wish I were writing this code in Swift, I’m glad that I have the opportunity to explore Python and hope I get to spend some time with Scala in the near future. This project is offering me a lot of valuable insights about where Swift came from and increased appreciation for the work the core Swift team put in to give us the language we have now.
4 Comments
Perhaps you should also try Pascal by Free Pascal (freepascal.org) and its Lazarus IDE (lazarus-ide.org). Have fun! 🙂
You can extend classes. So if you have a previously existing class that has a member y, and you want a function that multiplies that y by an argument:
The googlon is ‘monkey patching’.
Cool. I will investigate!
For years, I’d maintained that my ideal language would be Python with Haskell’s type system grafted on top. When Swift came out, I said, “Close enough!”