Joshua Ballanco
2016-07-22 01:37:00 UTC
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,
Josh
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,
Josh