Skip to content

Instantly share code, notes, and snippets.

@ekozhura
Created November 7, 2015 12:43
Show Gist options
  • Save ekozhura/cb682b577a9f86be1fd8 to your computer and use it in GitHub Desktop.
Save ekozhura/cb682b577a9f86be1fd8 to your computer and use it in GitHub Desktop.
Stream.collect implementation not only creates a new FuncStream, it mutates an original stream.
(
var a, b;
a = Routine.new({
inf.do{ |idx = 1|
idx.yield;
}
});
b = a.collect({|item| item * 2;});
b.nextN(10).postln; // -> [ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 ]
a.nextN(10).postln; // -> [ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ] WTF?!?
)
@jamshark70
Copy link

Routines are stateful and -- here's a big part of the key to your problem -- they cannot be copied. For a.collect to evaluate, it must get something from a -- and there is only one a. There is no way to make a separate a.

The thing you're looking for is a pattern. Patterns are stateless: stream factories. You can nest them, filter them at will and produce any number of independent streams.

(
var a, b;
a = Prout.new({
    inf.do{ |idx = 1|
        idx.yield;
    }
});
b = a.collect({|item| item * 2;});

b.asStream.nextN(10).postln; // -> [ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 ]

a.asStream.nextN(10).postln; // -> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
)

@ekozhura
Copy link
Author

ekozhura commented Nov 8, 2015

@jamshark70 Thanks so much for explanation.

One last question. You mentioned that there's no way to create a copy of a routine object. So what really happened when I use shallowCopy method? In this example a isn't affected

(
var a, b;
a = Routine.new({
    inf.do{ |idx = 1|
        idx.yield;
    }
});
b = a.shallowCopy.collect({|item| item * 2;});

b.nextN(10).postln; // -> [ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 ]

a.nextN(10).postln; // -> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ] 
)

@ekozhura
Copy link
Author

ekozhura commented Nov 8, 2015

I found an old thread where James McCartney explained a reason of why routines could not be copied.

It would mean copying the entire call stack. Since you can non-local return out of a Routine to the parent thread, it would mean copying the parent thread(s) call stack(s) as well. Otherwise, loop counters, instruction counters, stack pointers, etc would get very confused if a frame were re-entered twice. So multi shot continuations are not easily possible.

sc-dev: strange stream embedding behaviour.

Another observation: shallowCopy worked in my previous example because b was created before a was started. Otherwise shallowCopy would simply return a reference to a (at least, it seems so). That also makes sense, considering the quote of James McCartney.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment