Iterable type signature?

Say I have a function that iterates over some values (e.g., vector, range, iterator):

function f(xs)
  for x in xs
    println(x)
  end
end

Can I give it a type signature that indicates the function requires xs to be iterable?

It should work for f(rand(3)) or f(1:3) or f(Iterators.product(1:2, 1:3).

What should it do if xs is not iterable?

The most idiomatic way is to not annotate and just let it fail when they are not iterable. But if you want the same function to work for scalars, you have two options:

  • Annotate the scalar, and use the iterator one as fallback. This works well if you know what type of scalar you expect
  • Annotate the iterator, and make a scalar fallback. This is what you’re asking for. You’ll need to constrain the available iterators. AbstractArray will catch quite a few of possibilities. Add Tuple and you have a lot.

There is no built-in interface system.

1 Like

I’d like the type checker to throw an error. Just like it would if I passed a scalar to a function argument that was annotated AbstractVector.

Thanks. I’m not interested in handling scalar types. I just like to document the types of my functions. Perhaps I’ve used Haskell and Rust too much.

There is no type checker. Any errors you get happen at run-ish time. And when you get to the iteration, you will get one.

Consider writing that the input should be iterable in the docstrings.

You will already get an error from iterate:

julia> for i in :sym
       end
ERROR: MethodError: no method matching iterate(::Symbol)

You could use applicable(iterate, xs) to check, and then throw your own custom error if you want, but

The most idiomatic way is to not annotate and just let it fail when they are not iterable.

is the real answer.

It will fail in this case, but it won’t be obvious whether the problem is:

  1. I am misusing the function by passing a scalar argument, or
  2. The function itself has an implementation error

Even if Julia doesn’t have a formal type checker, it’s still possible and useful to use static analysis on annotated types with something like lsp-julia. I do the same with python.

1 Like
No method `iterate(::MyType)`

(or similar) is pretty clear to me. You can of course define your own catch for this, but you’ll never really know whether the error is pebcac or an error in the package. If I get an error as above, and I read the documentation which says "xs is an iterable collection of …" then I can assume it’s on my end.