April 14

Why I don’t object to Array#sum

Posted by mtoledo
Filed under ruby | 7 Comments

Raganwald has written a very elaborate piece about his “objection to Array#sum“. Since I patircularly like Array#sum, I thought I might weight in on my own blog.

First, I think that his piece has 2 different objections:

1) Array shouldn’t return true for a “responds_to? :sum” call if it has contents that can’t be summed ( like [1, 2, 'three'])

2) Some other object should be responsible for providing the “sum” service, as well as being responsible for inspecting the contents of the array for making sure they can be summed

Even though in his article he doesn make this distinction, I believe they are different issues.

So, my opinion to the first objection: “Should ‘responds_to? :sum’ always return true?”

Of course the answer to this is “yes”, even if ’sum’ was declared somewhere else instead of on the Array. The reason is that, as long as this function is not implemented in the array object, there’s no way to inspect its contents unless we pass a parameter to the ‘responds_to?’ method. And there’s no way to do that. The only parameter that ‘responds_to?’ receives is the method name. You can’t pass the method argument’s values to have a conditional return. The class either always responds to that method, or it doesn’t.

The same is true when you are writing interfaces for a statically typed language like Java. Interfaces only define 4 things: The method name, and the type of parameters it receives, the type of object it returns, and which errors does it throw. There’s no way to know if the method is supported for some particular set of parameters. The only thing you can know is what kind of errors the method throws if something goes wrong.

That’s exactly how an interface written in java would be if Array implemented a ’sum’ method. If you ignored generics, there’s no way you can conditionally implement that method on the Array class based on its contents. And there’s no way you can conditionally implement that interface in any other object either. There’s not even a way to support the method ’sum()’ on only ‘Array<Integer>’.

My point is, there’s no way you can inspect parameters or state to conditionally implement an interface. The interface is always tied to the class, not to the parameters of the method or to its state, and it will throw the declared errors if the situation arises.

The second quetion is: “Well, should then array#sum be moved to some other object or a standalone function which actually guarantees the semantic of the sum method?”

Well, I do think there’s a valid alternative to this, but I don’t think it’s neither having a standalone function ’sum()’  nor having some other ‘ArrayUtils#sum()’.

The reason why I don’t like any of the former alternatives is that there’s really no semantic gains or distinction by using any of the above compared to the old Array#sum. If you can call Array#sum in situations which are invalid and therefore it shouldn’t be supported, then there’s nothing that ArrayUtils#sum helps you with. If calling Array#sum doesn’t really tell you if that’s a semantically valid operation, calling sum() in any other fashion doesn’t really help either.

Besides, those alternatives create a pattern in code which I don’t like, which is the pre-chaning of calls. So, instead of:


['1', '2', '3', nil, '5'].compact.map(&amp;:to_i).map {|i| i * 10}.sum

You now have:


sum(map(map(compact([1, '2', '3', nil, '5']), lambda {|i| i * 10}, lambda &amp;:to_i )))

Or something like this (didnt really check this code for errors). Now, you have to read code from right to left. And if you argue that some things like map belongs to it and compact don’t, than you’ll have to read both from left to right and from right to left.

Particularly, having to read code from right to left sometimes is what I don’t like about lisp, and being able to chain a lot of calls and to read code from left to right is one of the reasons I like ruby so much.

So, given that exporting the method ’sum’ to another class still doesn’t help me tell if I can use it with a correct semantic meaning on an array any more than calling array#sum, I think it only brings the drawbacks above, without any of the benefits.

Now, I do think there could be a valid alternative to this: If had a NumberArray class. Then, I could check for the types of all the methods which change the state of the Array to make sure that whenever #sum was called, it would have a correct semantic meaning, since I’m enforcing its semantics both on my class name and on all my methods. And then I could remove the #sum method from the Array class and move it to the NumberArray class.

But then, that’s a design decision as any other when you have the following question: “Should I create a new type for providing this service? Or should I throw an error if it hasn’t been called correctly?”. The former has the benefit of having more semantically correct classes and services provided on them. The later has the benefit of not numerous numbers of types, and of being able to easily handle cases where both types are needed.

For instance, if you have Users that can delete another user, you could create a Admin specialization that implements the ‘delete_user’ service, so that you don’t have to throw errors when normal users try to delete users, which really doesn’t make sense. But if a user can delete another user if he has the same email address as the other user, then you’ll run into trouble, since you can’t inspect state to implement the Admin interface conditionally.

Being able to throw errors conditionally according to the state, rather than counting on object types and interfaces, can yield code that’s easier to read  than moving functions to some other objects, without being any less semantic. And it also allows for code that’s more flexible and extensible than moving code to specialized classes that carry more semantics. That’s really why I like Array#sum the way it is.

This entry was posted on Tuesday, April 14th, 2009 at 9:49 pm and is filed under ruby. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

7 Responses to “Why I don’t object to Array#sum”

  1. Reg Braithwaite on April 15th, 2009 at 9:09 pm

    “Being able to throw errors conditionally according to the state, rather than counting on object types and interfaces, can yield code that… allows for code that’s more flexible and extensible than moving code to specialized classes that carry more semantics.”

    This really says it all. If you’re trying to build the most flexible, do anything components possible, you want to avoid constraining your entities. On the other hand, if you’re trying to build a specific solution to a specific problem, I believe the opposite is true.

    I think our opposing viewpoints come from valuing different things about a design.

  2. mtoledo on April 15th, 2009 at 10:55 pm

    Yup, your point is actually correct. I guess we are always doing this trade-off when designing our applications, and in some situations semantic is more valuable than flexibility and extensibility, and in other situations its not.

    Its possible we just draw the line in different places, and fall in different camps on regards to how the Array class should be designed. :)

  3. Michael Feathers on April 16th, 2009 at 12:12 am

    Sometimes I think the hardest thing in programming is knowing what you can count on when you walk into an unfamiliar area of code. And, we all make it better to the degree that we can give people those assurances. Array#sum is an easily understandable example, but in practice I don’t think it is so bad. Anyone looking at an array and deciding to call sum is probably going to immediately think “gee, this should contain numbers and what if it doesn’t?” unless they are expecting string concatenation or something.

    The thing which troubles me is when this mistake is made on domain abstractions, things which are far less obvious than arrays and summing. That’s were it all hits the wall. I’ve run into that enough times that I share raganwald’s unease with the whole thing. In general, I think it a very good idea to create classes which can not get into states which invalidate their methods. When I walk into code where people share that point of view, I’m not quite as fearful and, really, that makes all the difference in the world.

  4. Sean O'Halpin on April 16th, 2009 at 1:47 am

    $ xmpfilter ~/scratch/array-respond_to.rb
    class Array
    def respond_to?(method)
    case method
    when :sum
    if all?{ |x| x.kind_of?(Numeric)}
    true
    else
    false
    end
    else
    super
    end
    end
    def sum
    if respond_to?(:sum)
    inject(0) { |sum, n| sum + n }
    else
    raise NoMethodError, “Cannot apply sum to non-numeric items”
    end
    end
    end

    Array.respond_to?(:sum) # => false
    a = [1,2,3]
    a.respond_to?(:sum) # => true
    a.sum # => 6
    b = [1, "hello", 3]
    b.respond_to?(:sum) # => false
    b.sum # =>
    # ~> -:18:in `sum’: Cannot apply sum to non-numeric items (NoMethodError)
    # ~> from -:29

    # P.S. Ruby is not Java :)

  5. You Go! on April 16th, 2009 at 7:03 am

    You herd what unca Reg said!

  6. jes5199 on April 20th, 2009 at 7:27 pm

    Some languages DO have parameterized types that can implement their own methods.
    In Scala, Array really is a subclass of Array.

  7. jes5199 on April 20th, 2009 at 7:30 pm

    uh, I mean “Array<Integer> is a subclass of Array”.
    HTML eats arrow brackets

Leave a Reply