Skip to content
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

Explore consequences of adding ImgLibStream wrapper #339

Open
tpietzsch opened this issue Sep 12, 2023 · 1 comment
Open

Explore consequences of adding ImgLibStream wrapper #339

tpietzsch opened this issue Sep 12, 2023 · 1 comment

Comments

@tpietzsch
Copy link
Member

Does it make sense to add ImgLibStream wrapper around java.util.stream.Stream?

With this we could augment Stream with additional operations. For example:

  • .materialize() could be a shortcut for .map(Type::copy).
  • We could decorate operations like .distinct() and .sort() to make sure that copies have been made before, etc.

However, wrapping all Stream methods, will add quite a lot of code, it's not clear whether it can be completely wrapped without leaky abstractions, etc. Just try it to see what the trade-offs are...

@tpietzsch
Copy link
Member Author

Originally posted by @ctrueden in #336 (comment)

About the ImgLibStream: I think this idea is almost necessary to do, because otherwise people will definitely bump into proxy-type-object-reuse-related bugs. I'm less convinced that you need a public class wrapper, though—it could instead be only an internal Stream subclass that overrides methods as appropriate while adding no new API. If we take care to override most/all of the potential pain points, the need for a method like materialize() becomes less.

We would still have to override all Stream methods to return ImgLibStream (so that the overridden methods work later in the chain, too).

I started doing it have something concrete to discuss:

static class ImgLibStream<T extends Type<T>> implements Stream<T> {
    private final Stream<T> delegate;

    ImgLibStream(Stream<T> delegate) {
        this.delegate = delegate;
    }

    @Override
    public ImgLibStream<T> filter(final Predicate<? super T> predicate) {
        return new ImgLibStream<>(delegate.filter(predicate));
    }

    @Override
    public <R> Stream<R> map(final Function<? super T, ? extends R> mapper) {
        return delegate.map(mapper);
    }
    ....
}

map is already interesting, because it cannot return ImgLibStream, so after that we influence anything in the chain anymore. (unless we add more wrappers...)

Are there other new API methods that occurred to you besides those you mentioned above?

Besides .materialize(), I thought nice syntactic sugar would be another .forEach() terminal method for the LocalizableSamplerStream (with positions), which takes a BiConsumer<Localizable, T> and pulls position and value apart. If we would add default methods like x(), y() to Localizable, and then one could write something like

Streams.localizing(myImg).foreach((pos, t) -> t.set(pos.x() + pos.y()));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: To Do
Development

No branches or pull requests

1 participant