-
Notifications
You must be signed in to change notification settings - Fork 91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fluent API for chaining views #364
Conversation
This pull request has been mentioned on Image.sc Forum. There might be relevant details there: https://forum.image.sc/t/recent-and-upcoming-imglib2-improvements/96083/1 |
(copied from forum post https://forum.image.sc/t/recent-and-upcoming-imglib2-improvements/96083/1) There are some open questions about naming things, API design choices, etc. Looking forward to opinions and suggestions! It works like this: DesignOne key goal is better discoverability than with the static .view() gatewayThe current approach is that extend/expand APIFor modeling First, putting them all in the extendMirrorSingle()
extendMirrorDouble()
extendPeriodic()
extendBorder()
extendZero()
extendValue(T value)
expandMirrorSingle(long... border)
expandMirrorDouble(long... border)
expandPeriodic(long... border)
expandBorder(long... border)
expandZero(long... border)
expandValue(T value, long... border) This makes discoverability of the API through IDE auto-completion a bit worse. Second, it is not technically correct to include I decided to solve this as follows: The two methods, RandomAccessibleInterval<IntType> img;
img.view().extend(Extension.border());
img.view().extend(Extension.zero()); etc. This puts the extension variants behind another API layer, leaving only the two top-level methods RandomAccessibleInterval<String> strings;
RandomAccessibleInterval<IntType> ints;
// this works:
ints.view().extend(Extension.zero());
// this does not work:
// compile error: no instance(s) of type variable(s) T exist so that String conforms to Type<T>
strings.view().extend(Extension.zero()); For consistency, the same API style is used for interpolation, e.g., ExtensibilityIdeally we would be able to incorporate We briefly considered merging the imglib2-realviews and imglib2 repositories. But it doesn't end there. Maybe we want to have a method like Unfortunately, this requires a generic parameter on interface RaView< T, V extends RaView< T, V > > extends RandomAccessible< T >
{ ...
default < U > U apply( Function< ? super V, U > function ) {
return function.apply( ( V ) this );
}
}
public interface RaiView< T > extends RaView< T, RaiView< T > >, RandomAccessibleInterval< T >
{ ...
} With the above, we have as desired: Img<?> img = ...;
Function<RandomAccessible<?>, String> fn1 = ra -> "accept RandomAccessible";
Function<RandomAccessibleInterval<?>, String> fn2 = rai -> "accept RandomAccessibleInterval";
// these work:
img.view().apply( fn1 );
img.view().apply( fn2 );
img.view().extend( Extension.border() ).apply( fn1 );
// this does not work:
// compile error: java.util.function.Function<net.imglib2.RandomAccessibleInterval<?>,java.lang.String>
// cannot be converted to java.util.function.Function<? super capture#1 of ?,U>)
img.view().extend( Extension.border() ).apply( fn2 ); There are many ways this RealViewsExample shows what a factory for RandomAccessibleInterval< IntType > affine1 = img.view()
.extend( Extension.border() )
.interpolate( Interpolation.nLinear() )
.apply( transform )
.interval( img );
RandomAccessibleInterval< IntType > affine2 = img.view()
.extend( Extension.border() )
.interpolate( Interpolation.nLinear() )
.apply( affine2D().scale( 1.1 ).translate( 2, 1.3 ).transform() )
.interval( img ); (Look at the full example for how MaterializeExample shows how ArrayImg< UnsignedByteType, ? > img = function.view()
.interval( new FinalInterval( 4, 4 ) )
.expand( mirrorSingle(), 2 )
.zeroMin()
.apply( toArrayImg() );
CachedCellImg< UnsignedByteType, ? > lazy = function.view()
.interval( new FinalInterval( 4, 4 ) )
.expand( mirrorSingle(), 2 )
.zeroMin()
.apply( toCachedCellImg( 3 ) ); (Again, look at the full example for how The cool thing about these "function factory" methods is that they can impose type constraints. For example Img< String > strings = new ListImg<>( new long[] { 1 }, "" );
strings.view().apply( toArrayImg() );
// compile error: no instance(s) of type variable(s) T exist so that String conforms to NativeType<T> Naming
Opinions? |
That's awesome! 🚀 Thanks @tpietzsch for following through with that idea! I really like having the Similarly, the The examples you cooked up are super expressive! I haven't had time to look at the code in detail yet, but I think the |
The actors nomenclature would mean calling it
There is no other materialize methods. Maybe the confusing bit is that RandomAccessibleInterval< IntType > affine1 = img.view()
.extend( Extension.border() )
.interpolate( Interpolation.nLinear() )
.apply( transform )
.interval( img ); may look like the |
Exactly. This just seems a bit clunky to me.
Yes, I think that's what confused me. Is there any downside to not having I guess what is bothering me is that there is no clear separation of lazily computed views and materialized images, which is important since both have very different access cost. Maybe just having an explicit |
Yes, agreed.
Yes, |
I see, thanks for the clarification! Still, I think that having a |
c15b51d
to
425e399
Compare
This is necessary to make apply(Function) work correctly for both, RaView and RaiView. Effectively, the function given to RaView.apply() should take RaView (or any parent, e.g., RandomAccessible). The function given to RaiView.app;y() should take RaiView (or any parent, e.g., RandomAccessibleInterval). I can find no other way to make this work. Hopefully this is not too inconvenient because RaView is not supposed to be used as type of variables, etc. It is just a construct to make the view- chaining API possible chains
(also handles RaiView)
425e399
to
8e5ea9f
Compare
The view gateways implement the respective interfaces and we want people to use RealRandomAccessibleInterval instead of RraView for variable types. Having an even longer name is hopefully a little push in that direction.
Updated version of #348
Add a fluent API for chaining
Views
methods onRandomAccessibleInterval
etc.This would look something like: