[ImageJ-devel] [fiji-devel] Significant change to ImgOpener - or - why ImgOpener.openImg() cannot return a T

Curtis Rueden ctrueden at wisc.edu
Tue Jul 31 16:21:15 CDT 2012


Hi Steffi,

Thanks for the explanation, and sorry for the delay in reply; I have been
on family leave for the past two weeks.

I really like your solution. In certain cases, I think raw types are the
only way to get around the awkwardness of the recursive typing approach.

I tested the newimgopener branch with ImageJ2, and it works. My vote is to
merge to master.

Regards,
Curtis


On Tue, Jul 17, 2012 at 4:08 PM, Stephan Preibisch <preibisch at mpi-cbg.de>wrote:

> Hi guys,
>
> this became a massive explanation. I suggest this as as solution to a
> problem we have been only partly aware of. I hope you enjoy reading ;)
>
> Steffi
>
>
> As the ImageJ conference is approaching I was talking with Johannes and we
> agreed that the ImgOpener needs to be finished. However, since its first
> version there has been a major design fault.
>
> But first the good news:
> --------------------------------
> It works perfectly fine if you say "open me an Image as float" or "...as
> UnsignedByte" or whatever, classically called by the method
> -> new ImgOpener.openImg( String id, ImgFactory<T> factory, T type );
> It can, without any problems, return you an Img<T>, and it requires that T
> is RealType (and not anymore NativeType, see at the end). So far, so good.
> Note that "T" is NOT a return parameter, but something you give to the
> openAs method.
>
> Now the bad news.
> --------------------------
> If you say "open this image as whatever RealType it is", it can do that,
> but it cannot assign a "T" to it - because T is not a return parameter. We
> made an ugly hack inside so that it seems as if it would work, but it does
> not. Now you might ask, why change it if it worked so far? Well, here is an
> easy example that would cause a ClassCastException on run time
>
> public static <T extends RealType< T >> void main( String[] args )
> {
>         Img< T > img1 = new ImgOpener.openImg( "somepic_8bit.tif" ); //
> 8-bit unsigned
>         Img< T > img2 = new ImgOpener.openImg( "somepic_32bit.tif" ); //
> 32-bit float
>
>         img1.firstElement().set( img2.firstElement() ); // run-time crash
> }
>
> It will throw a ClassCastException because img1 is of UnsignedByteType and
> img2 of FloatType. But as we cast it in a dirty way, it compiles just fine.
> So, we cannot return a "T", but what we can return is Img< which is at
> least a RealType >. And this is for sure always true, but img1 and img2 are
> not necessarily the same RealType (as above).
>
> The correct way (which doesn't work)
> --------------------------------------------------
> What we should return is an Img< ? extends RealType< ? > >. However, it is
> not ensured that the two "?" are the same, so an Img of this type is
> basically incompatible with everything else, which means an unchecked cast
> is necessary. So although correct, maybe not a good idea. And it is really
> ugly to write if necessary.
>
> The still somehow correct way
> -----------------------------------------
> Instead, it returns now an Img< RealType >. This is kind of a tradeoff. On
> one hand, this is very easy to write and will give you compile errors where
> it should, for example
>
>         img1.firstElement().set( img2.firstElement() ); // COMPILE ERROR
> (not the same RealType realization)
>
> OR
>
>        public <T extends RealType< T >> void add( IterableInterval< T >
> i1, IterableInterval< T > i2 ) { .... }
>        add( img1, img2 ); // COMPILE ERROR (not the same RealType
> realization)
>
> BUT
>
>         Gauss.inFloatInPlace( 2.0 , img1 ); // FINE (just one RealType
> realization required, inside it will be always the same "T")
>         Gauss.inFloatInPlace( 2.0 , img2 ); // FINE (just one RealType
> realization required, inside it will be always the same "T")
>
>         public < T extends RealType< T > > void add1( Img< T > img1,
> double value ) { ... }
>         add1( img1, 5 ); // FINE (just one RealType realization required,
> inside it will be always the same "T")
>
>         public < T extends RealType< T >, S extends RealType< S > > void
> add2( Img< T > img1, Img< S > img2 ) { ... }
>         add2( img1, img2 ); // FINE (explicitly two different RealType
> realizations are allowed)
>
>         public void add3( Img< RealType > img1, Img< RealType > img2 ) {
> ... }
>         add3( img1, img2 ); // FINE (both are just some kind of RealType,
> but gives a warning)
>
> On the other hand it gives a lot of Warnings because RealType should be
> more specified.
>
> Why not Img< RealType< ? > >
> ------------------------------------------
> Similar problem as in <? extends RealType< ? > >. RealType< ? > is not a
> valid substitute for any construct like < T extends RealType < T > >. One
> would have to cast to Img< RealType >, so we can take this one right away
> as it is less writing.
>
> Where did NativeType go?
> ------------------------------------
> I do not see any reason why we should enforce a NativeType. There is no
> objection to load an image into a (hypothetical) ListImg< BigDecimalType >.
>
> What are the implications?
> -----------------------------------
> We should write NOTHING except the method opening files for Img< RealType
> >. And also only if it is really required - quite often it is not. But if,
> Img< RealType > It is a completely valid input for any generic algorithm as
> show above for Gauss, add, etc.
>
>
>
> I implemented the changes on a branch called 'newimgopener'. It also
> contains four static convenience opening methods and a speed improvement.
>
> Any comments are very welcome. If somebody has a better idea how to solve
> the problem ... I am all ears ...
>
> Bye bye,
> Steffi
>
> --
> Please avoid top-posting, and please make sure to reply-to-all!
>
> Mailing list web interface: http://groups.google.com/group/fiji-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://imagej.net/pipermail/imagej-devel/attachments/20120731/04880371/attachment-0001.html>


More information about the ImageJ-devel mailing list