How Not to Code

April 17, 2019
How Not to Code Image Credit: unsplash-logoMarkus Spiske

Things That Make Kais 😭

This is a topic that I feel extremely strongly about, but I think that I’m going to try to write a useful rather than cathartic post here. These are some things that you should always avoid in your code.

each

In other languages, each or forEach might be an accepted idiom. It seems like it would be a generically useful iterator. The problem is that it does not have a useful return value: the loop cannot affect the program state without interacting with something outside the loop.

Bad:

array = []
(0..9).each { |i| array << i ** 2 }
array

Good:

(0..9).map { |i| i ** 2 }

As shown, if you want to create a new value with an each loop, you must declare a temporary value elsewhere, reach outside the loop’s scope, and expend another line after the loop to do something useful with that return value. There are some cases where creating a new value is not important. If you are creating a higher-level iterator, such as map or reduce, then you don’t really have an alternative but to use the lower-level iterator. If you are doing metaprogramming, then you probably don’t care that define_method has a return value. There are a couple other similar situations, but broadly, if you can use a different iterator, do it. And no, I do not mean that you should use times. It has the same problems.

while and until

Again, this is a low-level iterator which has more specialized uses than it appears. You should never use either while or until when the number of iterations is knowable. If possible, these methods should be wrapped in Enumerator or Iterator (Crystal), so that they can be treated as enumerable collections.

class Collatz
  include Iterator(Int32)

  def initialize
    @current = 0
  end

  def next
    @current += 1
    collatz(@current)
  end

  def collatz(n)
    steps = 0
    until n == 1
      n.even? ? (n /= 2) : (n = 3 * n + 1)
      steps += 1
    end
    steps
  end
end

for

There are zero reasons to ever use for loops.

Okay, there seems to be an exception to this rule. There is some sense in which you can use higher-order iterators in Crystal’s metaprogramming, but it can be easiest to use a for loop. This may change in the future.

comments powered by Disqus