Sets.difference

521 views
Skip to first unread message

Russ Abbott

unread,
Apr 26, 2012, 6:21:41 PM4/26/12
to guava-...@googlegroups.com
I got very fouled up by the apparent fact that Sets.difference is lazy and will change its result if the underlying sets change.

    Set<Integer> setA = new HashSet<>( );
    SetView<Integer> setB = Sets.difference(ImmutableSet.of(1, 2, 3), setA);
    System.out.println("SetB: " + setB);   // SetB: [1, 2, 3]
    setA.addAll(setB);
    System.out.println("SetA: " + setA);  // SetA: [1, 2, 3]
    System.out.println("SetB: " + setB);  // SetB: []   ! ! !

Not only is SetView a view, but it seems to be a view of a lazy operation. As far as I can tell, the documentation doesn't warn about this.  What am I misunderstanding?

If this is really the intent, it's a potentially useful feature. But it should be better explained.

Gregory Kick

unread,
Apr 26, 2012, 6:25:40 PM4/26/12
to Russ Abbott, guava-...@googlegroups.com
Is the word "view" in bold not warning enough?




--
Greg Kick
Java Core Libraries Team

Chris Povirk

unread,
Apr 26, 2012, 6:25:43 PM4/26/12
to Russ Abbott, guava-...@googlegroups.com
Sorry for the confusion. We mean for "view" to mean "lazy view,"
similarly to how keySet() provides a view of an underlying Map, etc.
The SetView documentation speaks a bit about this, but ultimately
we're reliant on the meaning of "view" to catch people's attention.
Are there particular places where "view" is used with another meaning
that we could better contrast this with?

Louis Wasserman

unread,
Apr 26, 2012, 6:31:57 PM4/26/12
to Gregory Kick, Russ Abbott, guava-...@googlegroups.com

Louis Wasserman
wasserm...@gmail.com
http://profiles.google.com/wasserman.louis

 Sets.difference is lazy and will change its result if the underlying sets change.

That's what the word "view" means, no?

Russ Abbott

unread,
Apr 26, 2012, 6:50:58 PM4/26/12
to guava-...@googlegroups.com
I have no problem with a View changing when the set of which it is a view changes. I simply didn't realize that sets.difference is also lazy. I assumed that Sets.difference generates a set and that one is then provided a View of that set. In this case, the fact that it is a view seemed not to make any difference since I saw no way that the difference, once computed would change. On the other hand, if one had something like

  Set<T> aSet = ...
  SetView<T> view = <a view of some set set>
  aSet.add(x);
 
This would add x to view.  That's a lot simpler than understanding saying that Sets.difference is lazy also.

It's even more than the usual understanding of lazy.

    Set<Integer> setA = new HashSet<>( );
    SetView<Integer> setB = Sets.difference(ImmutableSet.of(1, 2, 3), setA);
    System.out.println("SetB: " + setB);   // SetB: [1, 2, 3]
    setA.add(1);
    System.out.println("SetA: " + setA);  // SetA: [1]
    System.out.println("SetB: " + setB);  // SetB: [2, 3]
    setA.remove(1);
    System.out.println("SetB: " + setB);  // SetB: [1, 2, 3]

Normally I think of lazy as meaning that a computation isn't performed until its result is needed, but that once that result is computed it doesn't change.. In contrast I'd say that Sets.difference effectively constructs a symbolic expression that is re-evaluated.whenever it is referred to. That's more than lazy.

Raymond Rishty

unread,
Apr 26, 2012, 6:57:37 PM4/26/12
to Russ Abbott, guava-...@googlegroups.com
You said "That's more than lazy."

That's absolutely right--because the point is not that it is lazy, but that is a view. The documentation states this clearly, and the behavior exhibited is exactly what one should expect based on the documentation. Admittedly, the term "view" is a bit of a colloquialism, but it is generally understood to have this meaning, at least among Java programmers. This type of language is found in, e.g., the Javadocs for the Java API itself, such as in List.sublist (http://docs.oracle.com/javase/1.3/docs/api/java/util/List.html#subList(int, int))

Louis Wasserman

unread,
Apr 26, 2012, 7:20:49 PM4/26/12
to Russ Abbott, guava-...@googlegroups.com
I assumed that Sets.difference generates a set and that one is then provided a View of that set.

Sets.difference returns a view of the input sets -- a view of some newly constructed set isn't really a view at all.  It does basically no work by itself; it returns in constant time.

Russ Abbott

unread,
Apr 26, 2012, 7:40:11 PM4/26/12
to guava-...@googlegroups.com
The List.sublist example seems a bit different.  It says "The returned list is backed by this list [i.e., the object on which sublist is called], so changes in the returned list are reflected in this list, and vice-versa."  

It isn't similarly possible to change the view generated by Sets.difference and have one or another of the original sets change in response. 

The List.sublist documentation also says that "The semantics of this list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list.'  This suggests to me that there is some concrete list upon which the sublist operation is performed and that it returns a window on that list. Sets.difference is much more sophisticated in that it returns a delayed computation rather than a static window on a concrete but changeable object.

It's a neat capability. It's just far more than I expected -- and as such got me completely fouled up.


On Thursday, April 26, 2012 3:21:41 PM UTC-7, Russ Abbott wrote:
On Thursday, April 26, 2012 3:21:41 PM UTC-7, Russ Abbott wrote:
On Thursday, April 26, 2012 3:21:41 PM UTC-7, Russ Abbott wrote:

On Thursday, April 26, 2012 3:21:41 PM UTC-7, Russ Abbott wrote:
On Thursday, April 26, 2012 3:21:41 PM UTC-7, Russ Abbott wrote:
On Thursday, April 26, 2012 3:21:41 PM UTC-7, Russ Abbott wrote:

Louis Wasserman

unread,
Apr 26, 2012, 8:25:44 PM4/26/12
to Russ Abbott, guava-...@googlegroups.com
Perhaps a better comparison would be Collections.unmodifiableCollection, which performs exactly like a view ought to -- getting the view does almost no work by itself, and returns a collection backed by the argument collection, that reflects changes made to that backing collection.
 

Colin Decker

unread,
Apr 26, 2012, 8:26:32 PM4/26/12
to Russ Abbott, guava-...@googlegroups.com
On Thu, Apr 26, 2012 at 7:40 PM, Russ Abbott <russ....@gmail.com> wrote:
The List.sublist example seems a bit different.  It says "The returned list is backed by this list [i.e., the object on which sublist is called], so changes in the returned list are reflected in this list, and vice-versa."  

It's different in whether or not you can modify the view, not in the meaning of "view".
 
It isn't similarly possible to change the view generated by Sets.difference and have one or another of the original sets change in response. 

Because of the nature of the operation. It doesn't make sense to add to or remove from the difference between one set and another... the difference is fully defined in terms of its inputs.
 
The List.sublist documentation also says that "The semantics of this list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list.'  This suggests to me that there is some concrete list upon which the sublist operation is performed and that it returns a window on that list. Sets.difference is much more sophisticated in that it returns a delayed computation rather than a static window on a concrete but changeable object.

Yes, there's a concrete list upon which sublist is performed... the list it's called on. The same is true of Sets.difference... it's based on two concrete input Sets. The difference between the two methods here (i.e., the semantics of sublist being undefined if you structurally modify the original list) is again due to the inherent differences between the two operations... if you add or remove elements in a list, it becomes unclear what the already created sublist view should be since indices have shifted around. With Sets.difference, there's no such confusion: the difference view is a window on the elements in one set that are not contained in the other, and its semantics are easy to understand even as elements are added to and removed from the input Sets.
 
It's a neat capability. It's just far more than I expected -- and as such got me completely fouled up.

Note that SetView provides copyInto() and immutableCopy() methods specifically to make it easy to create a concrete copy of the view when that's what you want.
 

Louis Wasserman

unread,
Apr 26, 2012, 8:30:08 PM4/26/12
to Russ Abbott, guava-...@googlegroups.com
Would folks be satisfied if I added a more specific definition of view to the glossary page on the wiki?  I'm thinking of a definition like

A view of one or more objects in Java is an object providing query operations that "read through" to the backing objects.  In particular, views always reflect changes to the backing objects.  Additionally, some views may provide update operations which "write through" to the backing objects.

Kevin Bourrillion

unread,
Apr 27, 2012, 8:45:25 AM4/27/12
to Louis Wasserman, Russ Abbott, guava-...@googlegroups.com
I will take on some javadoc rewriting for these APIs.





--
Kevin Bourrillion @ Google
Java Core Libraries Team
http://guava-libraries.googlecode.com

Kevin Bourrillion

unread,
Apr 27, 2012, 3:28:13 PM4/27/12
to Louis Wasserman, Russ Abbott, guava-...@googlegroups.com
Hrm.

The methods like Sets.union are documented like this:

"Returns an unmodifiable <b>view</b> of the union of two sets."

... with boldfacing. And SetView says:

"An unmodifiable view of a set which may be backed by other sets; this view will change as the backing sets do. Contains methods to copy the data into a new set which will then remain stable."

This is seems as clear as can be already, provided that we can assume general knowledge of the word "view". So I definitely approve of adding "view" to our (anemic) glossary. But I wonder: to one who doesn't know what "view" means, what other definition could they infer it to mean?

Osvaldo Doederlein

unread,
Apr 27, 2012, 3:41:33 PM4/27/12
to Kevin Bourrillion, Louis Wasserman, Russ Abbott, guava-...@googlegroups.com
The JDK Collection Framework documentation (including its overview, annotated outline, design FAQ...) doesn't ever care to define "view", although that's an important concept in APIs like Map.keySet(). There's only the kind of method-level documentation like the below ("will change as the backing collection changes" etc.).  I think we can assume that Guava users should have a solid understanding of the core java.util collections framework... 

A+
Osvaldo

Louis Wasserman

unread,
Apr 27, 2012, 3:45:15 PM4/27/12
to Kevin Bourrillion, Russ Abbott, guava-...@googlegroups.com
Perhaps we should just {@linkplain SetView view}, just to make that documentation link clearer?

Russ Abbott

unread,
Apr 28, 2012, 3:15:27 AM4/28/12
to Louis Wasserman, Kevin Bourrillion, guava-...@googlegroups.com
If it were possible to begin again and step back from the term view, I would say that Sets.difference, Sets.union, etc. produce set expressions. I would distinguish between a view and an expression this way. A view is a static window over an existing object. It is allowable to change that object but only in very limited ways. An expression is a tree structure of operations the terminals of which are sets that can be changed in virtually any way one wants. 

A set expression is more like a function than like an object. It would be a function if one could actually replace the sets at the terminal positions of the expression with other sets. That is not possible, but one can rebuild the sets at the terminal positions in any way one wants and then have the expression re-evaluated.

The term view doesn't convey that degree of flexibility -- at least to me it doesn't. It is much too static a term. It seems to me that the Guava developers have come up with an interesting innovation with these operations. Instead of downplaying it by calling it a view, I would highlight it by calling it something different from a traditional view. It's like what use to be called a "thunk" (pass by name) when describing a mode of passing parameters. 
 
-- Russ 

Colin Decker

unread,
Apr 28, 2012, 10:13:08 AM4/28/12
to Russ....@gmail.com, Louis Wasserman, Kevin Bourrillion, guava-...@googlegroups.com
Have you thought of "view" in the sense it's used in databases? It's really very similar here. In a database, you have one or more concrete tables containing data and a view is something you create that _looks_ like a table but that actually lazily executes some query on the concrete table(s) when you query it, producing results that differ in some way from the original table(s). The view doesn't store data itself. Here, the backing collections are analogous to the database tables and the view collection is analogous to the database view... it looks like the same type of thing as the originals (it's a collection too) but operations on it read from the originals and apply some kind of transformations and/or filtering to produce different results.

-- 
Colin

Louis Wasserman

unread,
Apr 28, 2012, 12:44:12 PM4/28/12
to Colin Decker, Russ....@gmail.com, Kevin Bourrillion, guava-...@googlegroups.com
I have to say that the sense that Guava uses "view" is *exactly* the sense used in the JDK docs.  -1 on using any other term to describe it.

Russ Abbott

unread,
Apr 28, 2012, 7:08:04 PM4/28/12
to Louis Wasserman, Colin Decker, Kevin Bourrillion, guava-...@googlegroups.com
I agree it is very much like a view in the database sense, i.e., an unexecuted query. It's similar to the result returned by the various unmodifiableCollection/unmodifiable/Set, etc. methods in Collection as Louis suggested. 

What I had in mind when suggestion the term SetExpression is the notion that one could perform operations on a SetExpression object as an Expression.  For example, after

SetExpression setExpression = Sets.difference(a, b);

one has a SetExpression object upon which on might call a method to change its operation.

setExpression.setOperation(SetExpressionOperations.UNION)

This would turn the object into one that performs a union instead of a difference.

The other features of the object as an expression could also be made open to modification.

setExpression.setFirstArg(<some set>)

would point the expression to a different first argument.  Or even 

setExpression.setFirstArg(Sets.intersection(c, d));

at this point setExpression would represent the expression (c intersect d) union b.

You may not want to have that sort of flexibility, but it's because of that possibility that I suggested the term SetExpression. When considered in that context a SetView is something like a SetExpression with some of the possible operations on it left unexposed.

Louis Wasserman

unread,
Apr 28, 2012, 7:46:28 PM4/28/12
to Russ....@gmail.com, Colin Decker, Kevin Bourrillion, guava-...@googlegroups.com
Why would you do any of that?  It's more readable to just do it the compositional way, by building up results from the views.

In any event, it's also noticeably inefficient to have views of views of views, which means that you shouldn't be building up those sorts of complex objects anyway.

Russ Abbott

unread,
Apr 28, 2012, 8:25:57 PM4/28/12
to Louis Wasserman, Colin Decker, Kevin Bourrillion, guava-...@googlegroups.com
The point was to illustrate the difference between a view and an expression. I think I understand what the intent of a view is. I'm not sure you understand what I'm thinking of when I suggest calling it an expression. Perhaps you would never want to use it, but I'd like to know that you understand what I'm talking about and the distinction I'm trying to make.

Also, regarding views in databases, my sense is that the term "view" is used because one is thinking about an end user and one is providing him with a static view of a perhaps changing data base. That's somewhat different from what one wants as a developer.  In the documentation for SetView, the point is made that one doesn't keep a SetView around. With database views one does keep the view around. They really are intended differently even though they are both delayed computations.

Colin Decker

unread,
Apr 28, 2012, 8:38:40 PM4/28/12
to Russ....@gmail.com, Louis Wasserman, Kevin Bourrillion, guava-...@googlegroups.com
I'm really unclear on what you mean by "static" views.

And SetView definitely isn't implying that one shouldn't keep a SetView around. Note that what SetView's documentation actually says is that there "is usually no reason to retain a reference *of the type SetView*", meaning that if you're going to keep it around, there isn't much point using the SetView type... just refer to it as a Set. The SetView type is primarily there to allow stuff like "Sets.difference(a, b).immutableCopy()".

-- 
Colin

Russ Abbott

unread,
Apr 28, 2012, 9:37:01 PM4/28/12
to Colin Decker, Louis Wasserman, Kevin Bourrillion, guava-...@googlegroups.com
That's part of the point. If you convert a SetView into a Set, you can't change the banking sets and have the computed set change. With an expression, that's exactly what one wants, i.e., something that you intend to keep around and that will change when the backing elements change.

Louis Wasserman

unread,
Apr 28, 2012, 11:02:44 PM4/28/12
to Russ....@gmail.com, Colin Decker, Kevin Bourrillion, guava-...@googlegroups.com
Um...no?

A SetView is already a Set.  It implements the Set interface.  When you change the backing sets, the SetView reflects the updates.

That's what the word "view" means, as used by the JDK docs.

Louis Wasserman

unread,
Apr 28, 2012, 11:17:16 PM4/28/12
to Russ....@gmail.com, Colin Decker, Kevin Bourrillion, guava-...@googlegroups.com
Okay.  Let's try this again.

Definition: A view of one or more objects passes all queries through to the backing object(s).  Changes to the backing objects will be reflected in queries to the view.  Sometimes, views support modification operations, which always write through to the backing object(s).

Views typically have no state of their own at all -- they're not lazy, or thunks.  They're just wrappers.

Sets.difference(Set, Set), Map.keySet(), and List.subList(int, int) all return views.  The SetView class, which implements Set, is meant to help with common needs -- frequently, you just want to copy them into a concrete set to "freeze" them, and/or to avoid incurring the overhead of the wrapper.

morten hattesen

unread,
Apr 29, 2012, 3:31:24 AM4/29/12
to guava-discuss
+1

Brilliant!

Concise, unambiguous, and conveys the intent of the views as well as
providing hints of usage patterns.

/Morten

On Apr 29, 5:17 am, Louis Wasserman <wasserman.lo...@gmail.com> wrote:
> Okay.  Let's try this again.
>
> Definition: A *view* of one or more objects passes all queries through to
> the backing object(s).  Changes to the backing objects will be reflected in
> queries to the view.  Sometimes, views support modification operations,
> which always write through to the backing object(s).
>
> Views typically have no state of their own at all -- they're not lazy, or
> thunks.  They're just wrappers.
>
> Sets.difference(Set, Set), Map.keySet(), and List.subList(int, int) all
> return views.  The SetView class, which implements Set, is meant to help
> with common needs -- frequently, you just want to copy them into a concrete
> set to "freeze" them, and/or to avoid incurring the overhead of the wrapper.
>
> Louis Wasserman
> wasserman.lo...@gmail.comhttp://profiles.google.com/wasserman.louis
>
> On Sat, Apr 28, 2012 at 10:02 PM, Louis Wasserman <wasserman.lo...@gmail.com> wrote:
> > Um...no?
>
> > A SetView is already a Set.  It implements the Set interface.  When you
> > change the backing sets, the SetView reflects the updates.
>
> > That's what the word "view" means, as used by the JDK docs.
>
> > On Sat, Apr 28, 2012 at 8:37 PM, Russ Abbott <russ.abb...@gmail.com>wrote:
>
> >> That's part of the point. If you convert a SetView into a Set, you can't
> >> change the banking sets and have the computed set change. With an
> >> expression, that's exactly what one wants, i.e., something that you intend
> >> to keep around and that will change when the backing elements change.
>
> >> On Sat, Apr 28, 2012 at 5:38 PM, Colin Decker <cgdec...@gmail.com> wrote:
>
> >>> I'm really unclear on what you mean by "static" views.
>
> >>> And SetView definitely isn't implying that one shouldn't keep a SetView
> >>> around. Note that what SetView's documentation actually says is that there
> >>> "is usually no reason to retain a reference *of the type SetView*", meaning
> >>> that if you're going to keep it around, there isn't much point using the
> >>> SetView type... just refer to it as a Set. The SetView type is primarily
> >>> there to allow stuff like "Sets.difference(a, b).immutableCopy()".
>
> >>> --
> >>> Colin
>
> >>> On Sat, Apr 28, 2012 at 8:25 PM, Russ Abbott <russ.abb...@gmail.com>wrote:
>
> >>>> The point was to illustrate the difference between a view and an
> >>>> expression. I think I understand what the intent of a view is. I'm not sure
> >>>> you understand what I'm thinking of when I suggest calling it
> >>>> an expression. Perhaps you would never want to use it, but I'd like to know
> >>>> that you understand what I'm talking about and the distinction I'm trying
> >>>> to make.
>
> >>>> Also, regarding views in databases, my sense is that the term "view" is
> >>>> used because one is thinking about an end user and one is providing him
> >>>> with a static view of a perhaps changing data base. That's somewhat
> >>>> different from what one wants as a developer.  In the documentation for
> >>>> SetView, the point is made that one doesn't keep a SetView around. With
> >>>> database views one does keep the view around. They really are intended
> >>>> differently even though they are both delayed computations.
>
> >>>> On Sat, Apr 28, 2012 at 4:46 PM, Louis Wasserman <
> >>>> wasserman.lo...@gmail.com> wrote:
>
> >>>>> Why would you do any of that?  It's more readable to just do it the
> >>>>> compositional way, by building up results from the views.
>
> >>>>> In any event, it's also noticeably inefficient to have views of views
> >>>>> of views, which means that you shouldn't be building up those sorts of
> >>>>> complex objects *anyway*.
>
> >>>>> Louis Wasserman
> >>>>> wasserman.lo...@gmail.com
> >>>>>http://profiles.google.com/wasserman.louis
> >>>>>>> wasserman.lo...@gmail.com
> >>>>>>>http://profiles.google.com/wasserman.louis
>
> >>>>>>> On Sat, Apr 28, 2012 at 9:13 AM, Colin Decker <cgdec...@gmail.com>wrote:
>
> >>>>>>>> Have you thought of "view" in the sense it's used in databases?
> >>>>>>>> It's really very similar here. In a database, you have one or more concrete
> >>>>>>>> tables containing data and a view is something you create that _looks_ like
> >>>>>>>> a table but that actually lazily executes some query on the concrete
> >>>>>>>> table(s) when you query it, producing results that differ in some way from
> >>>>>>>> the original table(s). The view doesn't store data itself. Here, the
> >>>>>>>> backing collections are analogous to the database tables and the view
> >>>>>>>> collection is analogous to the database view... it looks like the same type
> >>>>>>>> of thing as the originals (it's a collection too) but operations on it read
> >>>>>>>> from the originals and apply some kind of transformations and/or filtering
> >>>>>>>> to produce different results.
>
> >>>>>>>> --
> >>>>>>>> Colin
>
> >>>>>>>> On Sat, Apr 28, 2012 at 3:15 AM, Russ Abbott <russ.abb...@gmail.com
> >>>>>>>> > wrote:
>
> >>>>>>>>> If it were possible to begin again and step back from the term *
> >>>>>>>>> view*, I would say that Sets.difference, Sets.union, etc. produce
> >>>>>>>>> set *expressions*. I would distinguish between a *view *and an *expression
> >>>>>>>>> *this way. A *view *is a static window over an existing object.
> >>>>>>>>> It is allowable to change that object but only in very limited ways. An
> >>>>>>>>> *expression *is a tree structure of operations the terminals of
> >>>>>>>>> which are sets that can be changed in virtually any way one wants.
>
> >>>>>>>>> A set expression is more like a function than like an object. It
> >>>>>>>>> would be a function if one could actually replace the sets at the terminal
> >>>>>>>>> positions of the expression with other sets. That is not possible, but one
> >>>>>>>>> can rebuild the sets at the terminal positions in any way one wants and
> >>>>>>>>> then have the expression re-evaluated.
>
> >>>>>>>>> The term *view *doesn't convey that degree of flexibility -- at
> >>>>>>>>> least to me it doesn't. It is much too static a term. It seems to me that
> >>>>>>>>> the Guava developers have come up with an interesting innovation with these
> >>>>>>>>> operations. Instead of downplaying it by calling it a view, I would
> >>>>>>>>> highlight it by calling it something different from a traditional view.
> >>>>>>>>> It's like what use to be called a "thunk<http://en.wikipedia.org/wiki/Thunk_(functional_programming)>"
> >>>>>>>>> (pass by name) when describing a mode of passing parameters.
>
> >>>>>>>>> *-- Russ *
>
> >>>>>>>>> On Fri, Apr 27, 2012 at 12:45 PM, Louis Wasserman <
> >>>>>>>>> wasserman.lo...@gmail.com> wrote:
>
> >>>>>>>>>> Perhaps we should just {@linkplain SetView view}, just to make
> >>>>>>>>>> that documentation link clearer?
>
> >>>>>>>>>> Louis Wasserman
> >>>>>>>>>> wasserman.lo...@gmail.com
> >>>>>>>>>>http://profiles.google.com/wasserman.louis
>
> >>>>>>>>>> On Fri, Apr 27, 2012 at 2:28 PM, Kevin Bourrillion <
> >>>>>>>>>> kev...@google.com> wrote:
>
> >>>>>>>>>>> Hrm.
>
> >>>>>>>>>>> The methods like Sets.union are documented like this:
>
> >>>>>>>>>>> "Returns an unmodifiable <b>view</b> of the union of two sets."
>
> >>>>>>>>>>> ... with boldfacing. And SetView says:
>
> >>>>>>>>>>> "An unmodifiable view of a set which may be backed by other
> >>>>>>>>>>> sets; this view will change as the backing sets do. Contains methods to
> >>>>>>>>>>> copy the data into a new set which will then remain stable."
>
> >>>>>>>>>>> This is seems as clear as can be already, provided that we can
> >>>>>>>>>>> assume general knowledge of the word "view". So I definitely approve of
> >>>>>>>>>>> adding "view" to our (anemic) glossary. But I wonder: to one who doesn't
> >>>>>>>>>>> know what "view" means, what other definition could they *infer* it
> >>>>>>>>>>> to mean?
>
> >>>>>>>>>>> On Fri, Apr 27, 2012 at 5:45 AM, Kevin Bourrillion <
> >>>>>>>>>>> kev...@google.com> wrote:
>
> >>>>>>>>>>>> I will take on some javadoc rewriting for these APIs.
>
> >>>>>>>>>>>> On Thu, Apr 26, 2012 at 5:30 PM, Louis Wasserman <
> >>>>>>>>>>>> wasserman.lo...@gmail.com> wrote:
>
> >>>>>>>>>>>>> Would folks be satisfied if I added a more specific definition
> >>>>>>>>>>>>> of view to the glossary page<http://code.google.com/p/guava-libraries/wiki/GuavaTermsExplained>on the wiki?  I'm thinking of a definition like
>
> >>>>>>>>>>>>> A *view *of one or more objects in Java is an object
> >>>>>>>>>>>>>> providing query operations that "read through" to the backing objects.  In
> >>>>>>>>>>>>>> particular, views always reflect changes to the backing objects.
> >>>>>>>>>>>>>>  Additionally, some views may provide update operations which "write
> >>>>>>>>>>>>>> through" to the backing objects.
>
> >>>>>>>>>>>>> Louis Wasserman
> >>>>>>>>>>>>> wasserman.lo...@gmail.com
> >>>>>>>>>>>>>http://profiles.google.com/wasserman.louis
>
> >>>>>>>>>>>>> On Thu, Apr 26, 2012 at 7:25 PM, Louis Wasserman <
> >>>>>>>>>>>>> wasserman.lo...@gmail.com> wrote:
>
> >>>>>>>>>>>>>> Perhaps a better comparison would be
> >>>>>>>>>>>>>> Collections.unmodifiableCollection, which performs exactly like a view
> >>>>>>>>>>>>>> ought to -- getting the view does almost no work by itself, and returns a
> >>>>>>>>>>>>>> collection backed by the argument collection, that reflects changes made to
> >>>>>>>>>>>>>> that backing collection.
>
> >>>>>>>>>>>>>> Louis Wasserman
> >>>>>>>>>>>>>> wasserman.lo...@gmail.com
> >>>>>>>>>>>>>>http://profiles.google.com/wasserman.louis
>
> >>>>>>>>>>>>>> On Thu, Apr 26, 2012 at 6:40 PM, Russ Abbott <
> >>>>>>>>>>>>>> russ.abb...@gmail.com> wrote:
>
> >>>>>>>>>>>>>>> The List.sublist example seems a bit different.  It says "The
> >>>>>>>>>>>>>>> returned list is backed by this list [i.e., the object on which sublist is
> >>>>>>>>>>>>>>> called], so changes in the returned list are reflected in this list, and
> >>>>>>>>>>>>>>> vice-versa."
>
> >>>>>>>>>>>>> --
> >>>>>>>>>>>>> guava-...@googlegroups.com
> >>>>>>>>>>>>> Project site:http://guava-libraries.googlecode.com
> >>>>>>>>>>>>> This group:http://groups.google.com/group/guava-discuss
>
> >>>>>>>>>>>>> This list is for general discussion.
> >>>>>>>>>>>>> To report an issue:
> >>>>>>>>>>>>>http://code.google.com/p/guava-libraries/issues/entry
> >>>>>>>>>>>>> To get help:http://stackoverflow.com/questions/ask(use the

Russ Abbott

unread,
Apr 29, 2012, 1:36:04 PM4/29/12
to morten hattesen, guava-discuss
That's a fine definition of views. The key line, which is currently not in the documentation is "Changes to the backing objects will be reflected in queries to the view."   I would recommend emphasizing that and including an example to illustrate that point. I also think that something like an expression, which is something like a view with its own state, is potentially useful--and it makes sense to be clear that views are not intended to have all the functionality of expressions

Louis Wasserman

unread,
Apr 29, 2012, 1:47:30 PM4/29/12
to Russ....@gmail.com, morten hattesen, guava-discuss
On Sun, Apr 29, 2012 at 12:36 PM, Russ Abbott <russ....@gmail.com> wrote:
That's a fine definition of views. The key line, which is currently not in the documentation is "Changes to the backing objects will be reflected in queries to the view."   
I guess our thinking has been that

a) that's supposed to be implied by the word "view"
b) it is in the documentation, of SetView: "this view will change as the backing sets do."
 
I would recommend emphasizing that and including an example to illustrate that point. I also think that something like an expression, which is something like a view with its own state, is potentially useful--and it makes sense to be clear that views are not intended to have all the functionality of expressions

I feel like mentioning that sort of comparison, when we don't actually offer any features along those lines, would only confuse people.

Louis 

Russ Abbott

unread,
Apr 29, 2012, 2:08:16 PM4/29/12
to Louis Wasserman, morten hattesen, guava-discuss
I initially assumed that a SetView performed its operation, produced a resulting set, and then provided a view of that set. Since there is no way to change that resulting set object I thought that a SetView in this context was essentially the same as an Immutable set. I had no idea why the SetView class was needed since I thought it was equivalent in this context to an Immutable set. But I didn't spend much time thinking about it.  Then when I understood that a View is really a delayed expression evaluation, I assumed that it was what I called an Expression and that it might be nice to have access to the expression to be evaluated. Since it's neither of those, it's probably worth explaining these distinctions.

Louis Wasserman

unread,
Apr 29, 2012, 2:50:21 PM4/29/12
to Russ....@gmail.com, morten hattesen, guava-discuss
On Sun, Apr 29, 2012 at 1:08 PM, Russ Abbott <russ....@gmail.com> wrote:
I initially assumed that a SetView performed its operation, produced a resulting set, and then provided a view of that set.
Why would we say that such a method returns a view?  That's...equivalent to returning a non-view.

Methods that return views basically never do any work of their own.  They just return a wrapper on their inputs.

Russ Abbott

unread,
Apr 29, 2012, 4:44:25 PM4/29/12
to Louis Wasserman, morten hattesen, guava-discuss
Answer 1. You can think of me as a naive user.  I didn't start by thinking to myself that something that returns a view doesn't do an operation. I just assumed that I knew what a view was and that Sets.difference, etc. returned one over a set that it constructed. Looking at the documentation of List.subList (and also the implementation under AbstractList.sublist) it's not obvious to me that the call to sublist is simply a wrapper over an unexecuted operation. If it were, changing the length of the backing list shouldn't  affect the sublist result -- unless the length of the backing list became too short for the specified range. I also don't understand what it means when the documentation for AbstractList.sublist  says that the length of the sublist may change over its lifetime. For that to be true, one would have to think of the result returned by sublist as something more than a wrapper. It would be an object with its own properties -- like an Expression.

Answer 2. As I said, I didn't know why you created a SetView class since it seemed to me that it was used where ImmutableSet would suffice. But then I don't always know why developers do everything they do.  As the SetView documentation says, a SetView is unmodifiable, unlike a sublist so why not just make it an ImmutableSet?  The SetView documentation does say that the view changes as the backing sets change. I misunderstood the implications of that since I thought: sure, if you change either of two sets, their difference may also change.  

I think the larger point, though, is not whether you can demonstrate (by cross examining me) that the documentation was right and that I misunderstood it but that a bit more explanation would eliminate that possibility.  Why not make life as easy as possible for users rather than writing something that could be proved to be correct even though it might be misunderstood because of what it left unsaid? The notion of a view really is a bit slippery -- especially one that disallows changes which are then propagated back to the backing information. Why not write a few extra words and make it easier for readers to be clear about what it is in Guava?

Louis Wasserman

unread,
Apr 29, 2012, 4:50:43 PM4/29/12
to Russ....@gmail.com, morten hattesen, guava-discuss
On Sun, Apr 29, 2012 at 3:44 PM, Russ Abbott <russ....@gmail.com> wrote:
Answer 1. You can think of me as a naive user.  I didn't start by thinking to myself that something that returns a view doesn't do an operation. I just assumed that I knew what a view was and that Sets.difference, etc. returned one over a set that it constructed. Looking at the documentation of List.subList (and also the implementation under AbstractList.sublist) it's not obvious to me that the call to sublist is simply a wrapper over an unexecuted operation. If it were, changing the length of the backing list shouldn't  affect the sublist result -- unless the length of the backing list became too short for the specified range. I also don't understand what it means when the documentation for AbstractList.sublist  says that the length of the sublist may change over its lifetime. For that to be true, one would have to think of the result returned by sublist as something more than a wrapper. It would be an object with its own properties -- like an Expression.
Fair enough. 

Answer 2. As I said, I didn't know why you created a SetView class since it seemed to me that it was used where ImmutableSet would suffice. But then I don't always know why developers do everything they do.  As the SetView documentation says, a SetView is unmodifiable, unlike a sublist so why not just make it an ImmutableSet?  The SetView documentation does say that the view changes as the backing sets change. I misunderstood the implications of that since I thought: sure, if you change either of two sets, their difference may also change.  
There's a distinction between unmodifiable and immutable.  Unmodifiable collections can't be modified directly, but they might be a view of other collections that could change if the backing collections change.  (This is the caveat, for example, that comes with Collections.unmodifiableXXX.)  

Immutable collections are guaranteed to never change under any circumstances, although the elements themselves might be mutable. 
I think the larger point, though, is not whether you can demonstrate (by cross examining me) that the documentation was right and that I misunderstood it but that a bit more explanation would eliminate that possibility.  Why not make life as easy as possible for users rather than writing something that could be proved to be correct even though it might be misunderstood because of what it left unsaid? The notion of a view really is a bit slippery -- especially one that disallows changes which are then propagated back to the backing information. Why not write a few extra words and make it easier for readers to be clear about what it is in Guava?
As I might have alluded to before, I think that the proper solution is to link the word "view" in the documentation to a definition, rather than to add these caveats to every Guava method which returns a view -- just because a lot of Guava methods return views, and that's a huge amount of added documentation which we'd be repeating word-for-word in dozens of different methods.  Is that acceptable?

Russ Abbott

unread,
Apr 29, 2012, 5:13:50 PM4/29/12
to Louis Wasserman, morten hattesen, guava-discuss
Sure, linking to a definition is great. It's probably even better than explaining each time it appears. A glossary of important/useful words would be very worthwhile. 

I just tried to find a relevant definition of "view" on the web and was unsuccessful.  The best I could find was view in the database sense. As was pointed out before, that is quite close. There is also the somewhat informal notion of View in MVC,which is made concrete for one case in javax.swing.test.View

Given all that it would be a nice service to say in some detail what a Guava SetView is -- and especially to provide examples  of how it might be used in ways that differentiate it from an ImmutableSet.

Louis Wasserman

unread,
Apr 29, 2012, 5:29:57 PM4/29/12
to Russ....@gmail.com, morten hattesen, guava-discuss
The notion of "view" is related to a few other object-oriented design patterns: for example, the decorator pattern; decorators can also be thought of as views -- usually of a single object, not more than one -- that provide some modified functionality, but usually exposes the same interface.  Wikipedia suggests that adapters are, more or less, views whose only purpose is to provide a different interface to the same object.

I dunno.  I'm trying to remember how I first learned the term "view," but I think it was mostly "by example, based on where the JDK docs use the term."

Russ Abbott

unread,
Apr 29, 2012, 7:00:37 PM4/29/12
to Louis Wasserman, morten hattesen, guava-discuss
OK. Thanks for looking that stuff up.  Do you know of other Java views with multiple backing objects and with a non-trivial computation between the backing objects and the view result?

Louis Wasserman

unread,
Apr 29, 2012, 7:49:19 PM4/29/12
to Russ....@gmail.com, morten hattesen, guava-discuss
On Sun, Apr 29, 2012 at 6:00 PM, Russ Abbott <russ....@gmail.com> wrote:
OK. Thanks for looking that stuff up.  Do you know of other Java views with multiple backing objects
Plenty in Guava, but none that I can think of from the JDK.
 
and with a non-trivial computation between the backing objects and the view result?
None at all.  There wouldn't be a point.  Either the result is a view, in which case the implementation of the method is no more complicated than "return new ViewClass(backingObject1, backingObject2, ...)" (and the constructor does no work for itself), or you're basically computing the contents of the result, in which case it's not a view (at least, as far as the user is concerned).
Reply all
Reply to author
Forward
0 new messages