Hi all!
Apologies in advance if there’s already a ticket where this discussion should be had (pointers to such greatly appreciated).
I was recently thinking about what interfaces might eventually look like, and specifically one of the ideas that was batted about during the JuliaCon hack day. Writing a function that takes an array-like thing might be implemented as:
function foo(myarray::ANY{getindex(), setindex(), iterate()})
#…
end
where the functions mentioned in the type signature are required to exist for any argument passed to the function.
One potential “big win” I see in this sort of interface is that it gives the programmer the opportunity to massage types that normally wouldn’t qualify for the interface by providing custom implementations for any missing methods. For example, say you had an immutable array-like that didn’t implement `setindex()` on its own. One could, if they desired, provide an implementation of `setindex()` that was a no-op, or returned a copy with the desired update, etc.
What I particularly like with this approach is that instead of having to implement many variants of a method to handle different types, one could write the core logic in a single, clearly understandable function and segregate the custom edge-case logic elsewhere.
This works well if the non-adhering type might be passed to the method you are writing and you can add the missing methods in the same module. e.g.:
module Bar
setindex(a::ImmutableArray) = #…
function foo(myarray::ANY{getindex(), setindex(), iterate()})
#…
end
end
But what if the code you are writing is merely glue between a non-adhering type and a function that expects a particular interface? e.g.:
module Bar
function foo(myarray::ANY{getindex(), setindex(), iterate()})
#…
end
end
module Qux
setindex(a::ImmutableArray) = #…
function doit(somearray::ANY)
Bar.foo(somearray)
#…
end
end
module Main
data = ImmutableArray()
Qux.doit(data)
end
In this case I think I’d like `Bar.foo()` to use `Qux.setindex()` when called from within `Qux` with an `ImmutableArray`…but this seems like treading on dangerous scoping territory!
I don’t have a solution to propose at the moment, but I wanted to raise the issue because I see some potential parallels with Ruby’s refinements. The concept of refinements is potentially rather powerful, but Ruby’s implementation was dogged by a literally years-long debate over how scoping should work and how to implement such scoping without completely crippling performance.
Cheers,