How can we maintain easy generics in the face of demand for a “safe” language?

I’m not sure why we don’t have (as far as I’m aware) an AbstractArrayTests package that contains a full test suite you can run against an instantiated custom type that wants to be an abstract array. It could have flags for sub-interfaces, like “read-only array”.

Similarly for any other large interface.

I’ve written such test suites for interfaces I’ve defined in my own framework. They’re quite a bit of work to get right, but once you have them, I find them extremely useful.

4 Likes

6 posts were split to a new topic: Semantics of :: in return type vs. argument type annotations

I like SimpleTraits.jl as a solution to this problem. Wish it could be done in base Julia eventually.

Since hasmethod is static on Julia 1.10, you could declare it as a trait like

hasprint(::Type{T}) where T = hasmethod(print, Tuple{T})

And then hasprint(T) defines your trait in the form of

@traitimpl HasPrint{T} <- hasprint(T)

Of course this doesn’t work for print because everything has a method, but you get the idea.

Then the function signature becomes

@traitfn function f(x::X) where {X; HasPrint{X}}

I wish we didn’t need a macro for this type of behavior though. But it gets the job done for now.

2 Likes

Actually WhereTraits.jl looks even better for this. You can literally just do

@traits f(x) where {applicable(print, x)} = ...

and it will dispatch depending on that boolean condition.

However the downside is this is not zero-overhead whereas SimpleTraits.jl is.

(Although WhereTraits allows multiple traits; SimpleTraits only permits one)

IMO the best solution for these problems is providing a test suite for a particular interface. The implementor plugs in the type or a value, and the test suite reports detailed results or a pass/fail.

This

  1. would not burden the language with extra syntax and complexity

  2. allow the users who implement an interface to check the semantics, and not just a formal presence of method signatures.

Eg I can implement the array interface and include

Base.firstindex(v::MyVector) = length(v)
Base.lastindex(v::MyVector) = 1

which does IMO is not something a formal interface spec would catch. But a test suite could. Of course in due time the test suite could be enhanced by tests for errors that slip though.

8 Likes

I can see the value of test suites. As you say, they go beyond simply having the correct methods to ensuring that the methods are implemented in a suitable manner.

1 Like

Test suites are great, just, as I was saying before, they’re a little tedious to write and require discipline to use. Ideally, I’d like to see both explicit verification of interfaces via testing and better static code analysis. But any non-trivial interface should 100% have an associated set of tests.

4 Likes