Comparing Python vs Ruby’s handling of empty Lists/Arrays

TIL Ruby is more forgiving when handling empty arrays that Python is with empty lists. If you try to access a non-existent index in Ruby you get a nil back. In Python you get an IndexError. I prefer the Python approach. It’s more straightforward.

Though Python also has a curious way that allows you to work around IndexError by trying to access a range of items in the List. And Ruby does also have an approach that will give you an appropriate error if the index is out of bounds. So who knows what the logic behind all of this is supposed to be ….

Python Version

Compare the following Python commands

empty = []
arr = ["here","are","some","words"]
empty[0]
arr[0]
empty[0:1]
arr[0:1]
" ".join(empty[0:1])
" ".join(arr[0:1])

Results of the Python commands:

>>> empty = []
>>> arr = ["here","are","some","words"]
>>> empty[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> arr[0]
'here'
>>> empty[0:0]
[]
>>> arr[0:0]
['here']
>>> " ".join(empty[0:0])
''
>>> " ".join(arr[0:0])
'here'

Ruby version

See the following Ruby commands

empty = []
arr = ["here","are","some","words"]
empty[0]
arr[0]
empty[0..0]
arr[0..0]
empty[0..0].join(" ")
arr[0..0].join(" ")

Results of the Ruby commands:

irb(main):007:0> empty = []
=> []
irb(main):008:0> arr = ["here","are","some","words"]
=> ["here", "are", "some", "words"]
irb(main):009:0> empty[0]
=> nil
irb(main):010:0> arr[0]
=> "here"
irb(main):011:0> empty[0..0]
=> []
irb(main):012:0> arr[0..0]
=> ["here"]
irb(main):013:0> empty[0..0].join(" ")
=> ""
irb(main):014:0> arr[0..0].join(" ")
=> "here"

Comparison

Python is pretty unforgiving if you try to access a non-existent element. Ruby is forgiving enough to give you a nil if the element is non-existent. Downside of the Ruby approach is that you don’t know if the nil means “there was a nil there” or “there was nothing there”.

If you want the less forgiving approach in Ruby you can use fetch like so:

irb(main):031:0> empty
=> []
irb(main):032:0> empty.fetch(0)
Traceback (most recent call last):
5: from /snap/ruby/132/bin/irb:23:in `<main>'
4: from /snap/ruby/132/bin/irb:23:in `load'
3: from /snap/ruby/132/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
2: from (irb):32
1: from (irb):32:in `fetch'
IndexError (index 0 outside of array bounds: 0...0)

 

I Wrote a Software: My Tech Stack

I’ve been writing recently about a side-project of mine that I’ve been doing to scratch a couple of itches I have: Using Excel as a Collaboration Tool in an Enterprise Setting and Seeing what all the fuss is about Haskell.

I started off, reasonably enough, by trying to write a web app. But getting started with anything in Haskell is hard enough: getting started with a website was a nightmare [1]. So I made a virtue of necessity. I figured if I’m going to make it easier for people to collaborate with Excel then what is the most natural way for people to collaborate with Excel in real life? The answer is simple: by sending email attachments.

So I forgot about any web interface (for now) and just concentrated on working with Excel Attachments on Emails. It meant I could just focus on learning Haskell and also forced me to work in a way that is going to be more natural for anyone who might use the service. And also it turns out that I’m bang on trend with this whole “No UI” movement [2].

In this post I’m going to get into what I’m using on this project and why:

  1. Ubuntu. I run this on the server simply because I’m used to using Ubuntu on the desktop from the past. I’ve run Ubuntu in production for a long time and it’s fine for me. (I’ve also run CentOS and Windows and going back far enough HP-UX and Solaris, but Ubuntu just seems… nice).
  2. Linode. Not all that much thought on this one. I’ve used AWS in the past and find the interface unbearably complex. I’ve used Rackspace Cloud with a lot of success. But I’ve also been curious as to how Linode and Digital Ocean stack up. I asked Twitter and I got an answer from someone in the Linode community. And so here I am.
  3. Postfix/Dovecot. I never imagined running my own mail server. I originally wanted to run all the email through Gmail. But I kept getting blocked for having a script running against the Gmail servers. In the end I figured I may as well run my own. Remains to be seen how well that works out. And (perhaps coincidentally) the best guide I could find to setting up Postfix/Dovecot was from Linode.
  4. MongoDB. I know that Mongo is no longer the cool kid on the block. But given that my use case for data storage is pretty straightforward, but I expect to need to store large Excel files, Mongo seemed neat. I’m using Mongo as a queueing system as much as a persistent data store.
  5. Haskell. For the heavy lifting. Learning it has been a long, hard slog. I must have read Learn You a Haskell 15 times (I even bought a copy). And also Real World Haskell several times. But you only really learn by doing and for me the best doing came from trying to follow Write Yourself a Scheme and then by trying to figure out how the HaExcel guys did it. Hat tips must also go to HaskellLive for getting an environment set up (though this now seems to be superseded by Stephen Diehl’s excellent write-up).
  6. Plain vanilla Ruby. Because with the wealth of gems in the community you can do a lot very easily.

[1] My brother who also works in tech bought me a copy of Building Web Applications with Haskell and Yesod. He thought that Haskell and Yesod were two individuals who were doing the teaching. This is in stark contrast to Ruby which I learnt from Alan Bradburne’s excellent Practical Rails Social Networking Sites.

[2] A cynic may say that mailing lists have been doing this for donkeys years. To which my reply is that the surely this validates the use of email for sending instructions around.