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

Running graph twice is not safe. #100

Open
tom-andersen opened this issue May 19, 2017 · 2 comments
Open

Running graph twice is not safe. #100

tom-andersen opened this issue May 19, 2017 · 2 comments

Comments

@tom-andersen
Copy link

tom-andersen commented May 19, 2017

Many of the javadsl methods are not safe when running the same graph twice.

For example, fold takes a concrete object as first parameters, such that all streams will use the same object. If you try to use with the List, then each run of the graph will reuse the same list, and results will be jumbled up together.

In the other extreme, there is Sink.lazyInit that has 2 levels of indirection. 1. the function. 2. the future. With this I can compensate for lack of methods that use Creator<> instead of concrete objects, but the code becomes a difficult to decipher mess.

@johanandren
Copy link
Member

You must use immutable collections with all such stages. I can see how this feels confusing from the Java point of things where immutable collections are not commonly used (compared to Scala where it is pretty much the default), so maybe we could improve on that by being more clear in the docs of the Java APIs.

Note that this repository is for additional community contributed stages, so if you feel we should continue discussing this, please open a ticket in the akka/akka repository instead, thanks!

@patriknw
Copy link
Member

I agree with Johan that it is intended to be used with immutable data structures.

I was thinking if there is any way to make it somewhat usable with mutable collections. Here is a sketch:

public class LazyMutableValue<T> {

  private final Supplier<T> factory;

  protected LazyMutableValue() {
    this.factory = null;
  }

  public LazyMutableValue(Supplier<T> factory) {
    this.factory = factory;
  }

  public Initialized<T> init() {
    return new Initialized<T>(factory.get());
  }

  public T getValue() {
    return init().getValue();
  }

  private static class Initialized<T> extends LazyMutableValue<T>{
    private final T value;

    public Initialized(T value) {
      this.value = value;
    }

    @Override
    public Initialized<T> init() {
      return this;
    }

    @Override
    public T getValue() {
      return value;
    }

  }
}

It can be used like:

      ActorSystem sys = ActorSystem.create("Sys");
      Materializer mat = ActorMaterializer.create(sys);

      Source<Integer, NotUsed> source = Source.range(1, 100);

      Sink<Integer, CompletionStage<LazyMutableValue<List<Integer>>>> sink =
        Sink.fold(new LazyMutableValue<>(() -> new ArrayList<Integer>()), (acc, elem) -> {
          LazyMutableValue<List<Integer>> nextAcc = acc.init();
          nextAcc.getValue().add(elem);
          return nextAcc;
        });

      RunnableGraph<CompletionStage<LazyMutableValue<List<Integer>>>> runnable =
        source.toMat(sink, Keep.right());

      CompletionStage<LazyMutableValue<List<Integer>>> result1 = runnable.run(mat);
      CompletionStage<LazyMutableValue<List<Integer>>> result2 = runnable.run(mat);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants