bodar/totallylazy

When join lazy sequence map functions invoked multiple times

Closed this issue · 1 comments

Issue description

When joining lazy sequences, it seems each mapper function was invoked twice. For pure code this seems ok but slow. But for Mapper Functions with side effects (IO actions) this will certainly results an error. The following code demonstrates this issue.

    Sequence<Integer> nums = sequence(1,2,3,4,5,6).take(3).map(new Callable1<Integer, Integer>() {
        @Override
        public Integer call(Integer integer) throws Exception {
            logger.debug("side effect with int = {}", integer);
            return integer + 10;
        }
    });

    logger.debug("seq = {}", empty(Integer.class).join(nums));

script output

side effect with int = 1
side effect with int = 2
side effect with int = 3
side effect with int = 1
side effect with int = 2
side effect with int = 3
seq = 11,12,13

possible workaround

Eagerly evaluate the list will eliminate this problem like the following code demonstrates:

    Sequence<Integer> nums = sequence(1,2,3,4,5,6).take(3).map(new Callable1<Integer, Integer>() {
        @Override
        public Integer call(Integer integer) throws Exception {
            logger.debug("side effect with int = {}", integer);
            return integer + 10;
        }
    }).realise();

    logger.debug("seq = {}", empty(Integer.class).join(nums));

script output

SampleFactory:53 - side effect with int = 1
SampleFactory:53 - side effect with int = 2
SampleFactory:53 - side effect with int = 3
SampleFactory:58 - seq = 11,12,13

I've tried this on both java7 and java8 versions and can not reproduce the bug.

    StringWriter out = new StringWriter();
    PrintWriter writer = new PrintWriter(out);
    Sequence<Integer> nums = sequence(1,2,3,4,5,6).take(3).map(integer -> {
        writer.printf("side effect with int = %d%n", integer);
        return integer + 10;
    });
    writer.printf("seq = %s%n", empty(Integer.class).join(nums).toString());
    assertThat(out.toString(), is("side effect with int = 1\n" +
            "side effect with int = 2\n" +
            "side effect with int = 3\n" +
            "seq = 11,12,13\n"));

I think we might have fixed this with a previous change to the default toString implementation.