top | item 45994959

(no title)

jessetemp | 3 months ago

I didn't find 2 surprising either, but I'm a little surprised you never see it. If you want to treat the args to a function as immutable, what can you do besides copy, modify, and return a new object?

discuss

order

zahlman|3 months ago

> what can you do besides copy, modify, and return a new object?

You can directly produce a modified copy, rather than using a mutating operation to implement the modifications.

It should be noted that "return a modified copy" algorithms can be much more efficient than "mutate the existing data" ones. For example, consider the case of removing multiple elements from a list, specified by a predicate. The version of this code that treats the input as immutable, producing a modified copy, can perform a single pass:

  def without(source, predicate):
      return [e for e in source if not predicate(e)]
whereas mutating code can easily end up with quadratic runtime — and also be difficult to get right:

  def remove_which(source, predicate):
      i = 0
      while i < len(source):
          if predicate(source[i]):
              # Each deletion requires O(n) elements to shift position.
              del source[i]
          else:
              # The index increment must be conditional,
              # since removing an element shifts the next one
              # and that shifted element must also be considered.
              i += 1

skribanto|3 months ago

swap with last element then truncate at the end

woodruffw|3 months ago

I think copying and modifying is normal! I just almost never see it with `copy()`. Apologies if I didn't say that clearly.