Should I be using asserts or errors for function parameter checking?

I have a function that accepts a slice that should have length at least 1 and at most 15. Should I be using asserts to enforce this or errors?

pub fn send_datagrams(self: *Port, datagrams: []telegram.Datagram) !u8 {
        if (datagrams.len == 0) {
            return error.InvalidParamNoDatagrams; // at least one datagram must be in sent frame
        }
        if (datagrams.len > 15) {
            return error.InvalidParamTooManyDatagrams; // max 15 datagrams in a single frame.
        }

I would think that assertions are for checking program correctness, so since this is a private API (only used within my library) i should use assertions to make sure I don’t call this with incorrect parameters.

I think it’s helpful to think about the differences that come from each choice.

When using an error, you are informing the caller that there are ways this function will not work, and could possibly fail. When you assert something you are signaling to the compiler that the conditions you are testing can never happen. This allows the compiler in release mode to make assumptions about the data and optimize the function call.

With that in mind, the question then is: Is this function one where you are going to guarantee the invariant that the input Array is only of length 1 through 15, or is it one where you don’t control the input? With the former, feel free to use asserts. with the latter, you should probably use errors

6 Likes

Asserts being for invariants is a great way of describing it! thanks!

4 Likes