About realizing the head of lazy seqs in with-meta:

On 5 November 2017 at 01:57, Didier <didi...@gmail.com> wrote:

> > That said, metadata and its relationship to an object is immutable - an
>>> object with different metadata is a different object. One consequence of
>>> this is that applying metadata to a lazy sequence will realize the head of
>>> the sequence so that both objects can share the same sequence.
>>
>>
On 5 November 2017 at 05:34, James Reeves <ja...@booleanknot.com> wrote:

> On 5 November 2017 at 00:57, Didier <didi...@gmail.com> wrote:
>
>> And then I'm confused as to why that would cause lazy-seq to realize
>> their head? Can't two lazy-seq share the same head?
>>
>
> This I'm not too certain about. It may just be an implementation detail.
>

They can, and indeed the point of realizing the lazy seq in .withMeta /
with-meta is precisely so that the input and output of with-meta share the
same head.

For example, in this situation:

(def xs (create-some-lazy-seq …))
(def ys (with-meta xs {:foo 1}))

the expectation is that the lazy seqs xs and ys will wrap a single
underlying sequence.

This is actually quite important – consider a lazy sequence that fully
consumes some resource at each step or that causes some other side effect
at each step, or perhaps simply one that is computationally expensive to
realize; one would expect the above to work just fine in such a case
regardless of how xs and ys are consumed, with any necessary computation,
resource consumption, side effects etc. occurring once per element, and all
the elements shared across xs and ys.

In other words, if a consumer comes along and asks for the first element of
xs, and then subsequently another consumer (or indeed the same one) asks
for the first element of ys, the latter request should be satisfied without
any further resource consumption or computation (beyond looking up a
pointer). And similarly if ys is realized first and the second request is
for an element of xs.

Now, if xs' head has not been realized, (with-meta xs {:foo 1}) can
conceivably operate in one of two ways:

1. it can copy over xs' thunk (the nullary function embedded in the lazy
seq object xs that is called – and expected to return a sequence or nil –
when xs needs to be realized) into a new lazy seq object ys;

2. it can realize the head of xs and call .withMeta on the result.

The first approach, however, breaks the promise that realizing the head of
xs will have the effect of realizing the head of ys, as neither xs nor ys
would subsequently have any way of knowing whether the other's head has
been realized when they finally need to realize their own heads, and so the
second one to be realized would be forced to recompute the sequence.

Thus the implementation takes the second approach.

Cheers,
Michał

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to