zcwease / guava-libraries

Automatically exported from code.google.com/p/guava-libraries
Apache License 2.0
0 stars 0 forks source link

FluentIterable #11

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Hi,

Last weekend I thought:
"Why not to use functional programming with Java? More precisely using
Google Collections!"
...

Minutes later... Voila!!!
I can to write pieces of code as:

names.select(new Regexp(".*e$")).transform(new GetLength()).select(new 
OddNumber())

I wanted to move this code to a fluent interface. Now, I dont need the
verbose syntax of the static methods, and, mainly, this code is more easy
to read.

The attached jar file contains the full source code with:
- FunctionalIterable interface, with all methods documented
- StandartFunctionalIterable class, the default implementation
- StandartFunctionalIterableTest class, the show case class

About Fluente Interface:
http://martinfowler.com/bliki/FluentInterface.html
http://en.wikipedia.org/wiki/Fluent_interface

Original issue reported on code.google.com by jonhnnyw...@gmail.com on 22 Oct 2007 at 5:12

Attachments:

GoogleCodeExporter commented 9 years ago
Thanks!

Also see these blog posts (and my comments on them)

http://blogs.warwick.ac.uk/chrismay/entry/writing_functional_java
http://stephan.reposita.org/archives/2007/10/17/creating-a-fluent-interface-for-
google-collections/

In short, the "FP" features of the library could definitely be made a lot 
better,
although we have to make a decision about whether it's central or tangential to 
what
our library is trying to offer.

Original comment by kevin...@gmail.com on 22 Oct 2007 at 5:47

GoogleCodeExporter commented 9 years ago
Hi Kevin,

I read your comments. But I dont liked a little of the one in url:
http://stephan.reposita.org/archives/2007/10/17/creating-a-fluent-interface-for-
google-collections/
You wrote:
"The other fix that I had in mind: make Function and Predicate into abstract 
classes
which have the transform(), filter(), and other related methods right there on 
them."

I think that Function and Predicate must to continue as interfaces. 
However, you can to make abstract classes that implements each one them.
Thus, the API continues flexible.

Original comment by jonhnnyw...@gmail.com on 23 Oct 2007 at 6:50

GoogleCodeExporter commented 9 years ago
Of course there must be interfaces.

In my experience it's very rare that people wouldn't extend the abstract class. 
 But
I have had a case where I wanted some predicates to be enums, and I wouldn't 
close
off that possibility.

The interesting question is:  if usage of the abstract class proves to be 10, 
20, 50
times more popular than usage of the interface, does it merit a reversal of the 
usual
naming practice?  That is, instead of "class AbstractPredicate" and "interface
Predicate", is there justification for "class Predicate" and (don't spew your 
coffee,
please) "interface IPredicate"?

Heresy, I know, but I get paid to consider heresy :)

What I really fear is making the line

   Predicate<Set<? extends Number>> containsFive = new Predicate<Set<? extends
Number>>() {

yet another eight characters longer, due to the need to instantiate 
AbstractPredicate
instead.

Original comment by kevin...@gmail.com on 23 Oct 2007 at 6:58

GoogleCodeExporter commented 9 years ago
Hi Kevin,

While using google-collections in my project, I created FunctionChain class 
that may
solve this problem. You can look at the code here:
http://docs.google.com/View?docID=d35w57w_0fc5tk2&revision=_latest

Usage example:
Iterables.any(annotations,      
self(Annotation.class).function(annotation_type).select(isInstanceOf(Foo.class))
);

I tried to address 2 things: (a) keep Function as interface (b) get rid of 
NPE's by
creating NullSafeFunctionChain, the idea is to let functions that declare 
@Nullable
parameter in apply() to handle nulls, and skip invocations of the ones that 
don't
declare @Nullable so that null just gets passed up the chain. 

What do you think?

-- Yardena.

Original comment by ymeym...@gmail.com on 4 Nov 2007 at 4:14

GoogleCodeExporter commented 9 years ago
We have been experimenting internally with "fluent" versions of common types.

The notion here is to follow the lead of the pair:

   java.util.Comparator (interface)
   com.google.common.collect.Ordering (abstract class)

The latter implements the former, has a from() method taking the former, and is 
in
all ways the same thing as the former except having more awesome functionality 
built-in.

This seems like a pattern that, while not totally 100% awesome, is worth 
following
because we don't have any better idea how to do this.

So what we're playing with:

  Comparator --> Ordering
  Iterable --> FluentIterable (??)
  Predicate --> Matcher (??)
  Function --> FluentFunction (??)

For example, FluentIterable looks like this:

abstract class FluentIterable<T> implements Iterable<T> {
  FluentIterable<T> unmodifiable()
  FluentIterable<T> filter(Predicate<? super T>)
  <S> FluentIterable<S> transformWith(Function<? super T, S>)
  FluentIterable<T> append(Iterable<? extends T>)
  FluentIterable<List<T>> partition(int)
  FluentIterable<T> skip(int)
  FluentIterable<T> limit(int)
  FluentIterable<T> cycle()

  int size()
  boolean isEmpty()
  boolean contains(@Nullable Object)
  boolean elementsEqual(Iterable<?>)
  T[] toArray(Class<T>)
  String toString()

  ImmutableList<T> toList()

  T getOnlyElement()
  T getLast()

  int frequency(@Nullable Object)

  T firstMatching(Predicate<? super T>)
  boolean anyMatches(Predicate<? super T>)
  boolean allMatch(Predicate<? super T>)
}

Any input?

Original comment by kevin...@gmail.com on 17 Mar 2009 at 4:49

GoogleCodeExporter commented 9 years ago
Years ago I had experimented with returning "ExtendedIterable" (and other such 
types) 
from methods, which offered filtering and other utilities, but I came to 
dislike 
these and prefer the simplicity of google collections, in the form of not 
introducing 
new types for just syntactical "niceties", like calling "x.m(y)" instead of 
"m(x, y)" 
(modulo polymorphism, which you don't need, it's merely a syntactical twist). 
Would 
you feel comfortable with having FluentCollection, FluentSet, FluentMap, 
FluentMultimap etc? I doubt. Or for example:
What if a method wants to return a _Set_ (to denote element uniqueness)
that is also "fluent"?
- Return a FluentIterable, which is not a Set?
- Return a Set, which is not FluentIterable?
- Return a FluentSet?

In the case of Ordering, I see comparator as a SPI and Ordering as its 
respective 
API. "You implement just this method(s), and you get for free all these". It 
looks 
good, I think static methods would be fine too. I understand you like the 
ability to 
hit "[dot]" and get the pop-up of your IDE, but hitting "[dot]" after typing 
"Ordering" would do the job as well. Also note that the Ordering methods are 
not also 
offered as statics, so they offer something genuine, while the types you 
describe 
would not.

So, I would hope you continue to prefer simplicity over slight syntactical 
gains, as 
you always have done in google collections.

I also want to draw some attention to the fact that this conversation wouldn't 
need 
to ever happen if the initial collection types were defined as abstract 
classes, and 
not interfaces. All convenience methods could be then defined in them. But 
then, 
existing classes with existing superclasses (other than Object) wouldn't be 
able to 
implement these collection types. This restriction doesn't exist for example in 
scala, where traits (interfaces that can have code) can be freely mixed in 
classes 
without affecting their class hierarchy, i.e. very easy reuse. So there is no 
reason 
not to define convenience methods directly in the collection types, and this is 
how 
is done. But since we talk about java, lets not try to fix the absense of 
certain 
language features by library design - this would encourage everyone to follow 
suit. 

Original comment by jim.andreou on 17 Mar 2009 at 6:14

GoogleCodeExporter commented 9 years ago
You certainly are right that I'd hate to see this proliferate to Set and Map 
and all
that.

If Ordering/Comparator is a little different from the rest (API/SPI), then 
Function
and Predicate fall into this category as well.  They're very much the same 
flavor of
objects. (The point about how the functionality is not also offered with 
statics --
well, it *was*, we just undid all that is all.)

So it's really FluentIterable that is most controversial here.  Well -- I love
FluentIterable.  I think it makes code a lot more readable and library features 
more
discoverable. But I can't predict whether it will ever become part of this 
library or
not.  Your input has been useful, as will be the input of others who might wish 
to
give it here.

Original comment by kevin...@gmail.com on 17 Mar 2009 at 9:40

GoogleCodeExporter commented 9 years ago
  I second the vote for having interfaces that define all these new fluent methods.
Whatever blasphmous name they might have, they are needed. Indeed, I'm currently
missing an interface for the Ordering.

  So it goes like:
Iterable -> i Whatever -> abs Whatever
Comparator -> i Ordering -> abs Ordering
i Function -> abs Function
i Predicate -> abs Predicate

  Then, if you're introducing upgraded interface for Iterables/Comparators and
Functions/Predicates with fluent methods, you're going to use them in APIs (and 
not
only g-col ones, you're going to pass them around in your software). That way, 
even
if you almost always use abstract classes that implement all that fluency as a 
base
for your anonymous classes, the number of said anon classes would be on even, 
if not
dwarfed by interface API usages.

  From that point I'm no longer sure which names should be shorter. What I'm not
eager to see is AbcInterface or AbstractAbc. BaseAbc sounds better. IAbc even 
more.
I'd really like to have +1letter naming for abstract classes, but can't choose 
a letter.

  What about naming upgraded Iterable a Sequence?

  Predicate is a cool name, it goes better with Function and it doesn't clash with
java.util.regex.Matcher, which is much more probable to meet in the same 
context,
than all non-g-col Predicates I could find.

Hopefully, I was able to convey my thoughts :)

Original comment by earwin@gmail.com on 17 Mar 2009 at 10:22

GoogleCodeExporter commented 9 years ago
I still don't see the advantage of an interface for Ordering.  Can you try 
again to
explain it?

Whatever the "better" Iterable is, I'm convinced it must include "Iterable".  
Picking
another term out of the air like "Sequence" is just going to mislead people; 
that may
mean something else to them. An Iterable is exactly what this is, just with 
more stuff.

By this rationale the name Ordering was a mistake, and maybe it was, but it's 
one we
already made and we'll live with it.  And by this rationale, the name "Matcher" 
is
wrong for the upgraded Predicate, and I think it is indeed wrong, for these 
reasons
as well as conflict with all the dozens of other things called Matcher in the 
world.
So I think we'll have to fix that, but to what?

Original comment by kevin...@gmail.com on 17 Mar 2009 at 11:00

GoogleCodeExporter commented 9 years ago
Similar to your case - an ability to use Ordering enums.
Other case is when you have your own working hierarchy of classes and want them 
to be
FluentWhatevers. This case is shaky, it's more applicable to
iterables/functions/predicates than to ordering and you can always have a method
returning delegating FluentWhatever.

It's just a joke, but what about taking your words literally and using 
BetterIterable?

Original comment by earwin@gmail.com on 19 Mar 2009 at 7:18

GoogleCodeExporter commented 9 years ago
But an Ordering enum would be such an incredible burden to implement!  Don't 
bother;
have an enum from which you can *get* an ordering.

As well, remember than any interface we release is something we can never, ever 
add a
method to or otherwise change in basically any way.

"BetterIterable"?  Believe me, we considered it.  We tried *everything*. 
NiceIterable, RichIterable, SuperIterable, Iterabler, Iterablest, IterablePlus,
IterablePlusPlus, DeluxeIterable, Iterable2, MintyFreshIterable,
OrganicFreeRangeIterable, IterableThatIsTehHotness, PhatIterable,
BarackObamaWouldUseThisIterable, Bob . . .

Original comment by kevin...@gmail.com on 19 Mar 2009 at 7:40

GoogleCodeExporter commented 9 years ago
Maybe you should put less weight to API discoverability, and trust your users 
to know 
it, and read the documentation (assuming that at some point in time some kind 
of 
tutorial will be written, in the spirit of java collections). If this thing is 
going 
to be used as widely as java collections, which I believe that at some point it 
will, 
it will be common ground for java developers to know its basics, as much you 
take for 
granted that java developers know the existence of java.util.Collections 
utilities.

(A question, in order to understand the precise dilemma: if you introduce 
FluentIterable, you would remove the similar methods from Iterables? Or keep 
them 
redundantly?)

Original comment by jim.andreou on 19 Mar 2009 at 8:48

GoogleCodeExporter commented 9 years ago
It's too late to have any other choice but to keep them redundantly.

Original comment by kevin...@gmail.com on 19 Mar 2009 at 8:51

GoogleCodeExporter commented 9 years ago

Original comment by kevin...@gmail.com on 17 Sep 2009 at 6:02

GoogleCodeExporter commented 9 years ago
Take a look at ParallelArray: "The ParallelArray library builds on top of 
fork-join
and provides a functional style API for mapping, filtering, reducing, etc over 
an
array of Java objects. Without closure support, the API is not particularly 
pretty,
but I think it’s eminently useful. The decision was made not to standardize 
it in the
JDK yet but you can still download it from the JSR 166 site directly."

http://gee.cs.oswego.edu/dl/jsr166/dist/extra166ydocs/extra166y/ParallelArray.ht
ml

Original comment by jonhnnyw...@gmail.com on 16 Nov 2009 at 12:59

GoogleCodeExporter commented 9 years ago

Original comment by kevinb@google.com on 30 Jul 2010 at 3:53

GoogleCodeExporter commented 9 years ago

Original comment by kevinb@google.com on 30 Jul 2010 at 3:56

GoogleCodeExporter commented 9 years ago
Issue 520 has been merged into this issue.

Original comment by kevinb@google.com on 12 Jan 2011 at 8:33

GoogleCodeExporter commented 9 years ago
Do you have any plans to release your internally used FluentIterable in the 
near future?

Original comment by nvoll...@gmail.com on 13 Jan 2011 at 8:15

GoogleCodeExporter commented 9 years ago
It is not a high priority, no.

Original comment by kevinb@google.com on 13 Jan 2011 at 2:57

GoogleCodeExporter commented 9 years ago
Just for those interested, I've extended my Queryable with fold and 
orderBy/thenBy.

It's as lazy as possible. 
For example: elements.filter(...).transform(...).first() will result in one 
call to the transformer only (and filter to the first element that returns 
true).

So I think Queryable isn't a bad name for it, since its more than just fluent.

Original comment by nvoll...@gmail.com on 19 Jan 2011 at 1:04

Attachments:

GoogleCodeExporter commented 9 years ago

Original comment by kevinb@google.com on 13 Jul 2011 at 6:18

GoogleCodeExporter commented 9 years ago
Hi,

at first thanks for Guava, it helps to increase productivity a lot! My 
question: please could you describe current state of adding fluent versions of 
collection-related classes to Guava? I carefully watch these issues and am 
interested of current situation. I rate this feature very important.

If the only problem is naming, wouldn't be better to ultimately decide somehow? 
(Personally I prefer concise one-word names like Sequence, Filter/Matcher or 
Transformer but I absolutely accept anything else - rather unfavorite name than 
nothing.)

Thanks!
Tomáš Záluský

Historical comments:

http://code.google.com/p/guava-libraries/issues/detail?id=11#c5
Mar 17, 2009
We have been experimenting internally with "fluent" versions of common types.

http://code.google.com/p/guava-libraries/issues/detail?id=334#c1
Feb 26, 2010
We have great "fluent" versions of Predicate, Function and Iterable, and I hope 
we can release them soon.  The only real problem is that these classes are THE 
hardest things to name EVER.

http://code.google.com/p/guava-libraries/issues/detail?id=11#c19
Jan 13, 2011
Do you have any plans to release your internally used FluentIterable in the 
near future? - It is not a high priority, no.

Original comment by tomas.za...@gmail.com on 19 Jul 2011 at 7:26

GoogleCodeExporter commented 9 years ago
Ah, it is about time for an update.  I mentioned that we've been 
"experimenting" with fluent Iterables, Functions and Predicates inside Google.  
Most of us feel that the experiment has been a success, and we will endeavor to 
get these into Guava release 11 or 12 for you.

We will call them simply FluentIterable, FluentFunction and FluentPredicate.

Original comment by kevinb@google.com on 19 Jul 2011 at 2:23

GoogleCodeExporter commented 9 years ago

Original comment by wasserman.louis on 9 Dec 2011 at 7:08

GoogleCodeExporter commented 9 years ago
Issue 818 has been merged into this issue.

Original comment by wasserman.louis on 9 Dec 2011 at 7:08

GoogleCodeExporter commented 9 years ago

Original comment by fry@google.com on 10 Dec 2011 at 3:12

GoogleCodeExporter commented 9 years ago
This is super exciting and yay.

Original comment by wasserman.louis on 3 Jan 2012 at 7:38

GoogleCodeExporter commented 9 years ago
Recommendation: having transform() or map() methods on FluentFunction would 
allow it to be overloaded for list, collection, iterable, optional, etc., as 
opposed to adding those methods to FluentIterable alone.

Original comment by wasserman.louis on 3 Jan 2012 at 8:15

GoogleCodeExporter commented 9 years ago
We're splitting this up into separate issues; FluentPredicate is now issue 334.

Original comment by wasserman.louis on 16 Feb 2012 at 6:50

GoogleCodeExporter commented 9 years ago
Would it be possible to weave functions into a monadic structure using 
optional?  

Original comment by emily@soldal.org on 17 Feb 2012 at 12:08

GoogleCodeExporter commented 9 years ago
...Speaking as a Haskell aficionado who thinks monads are awesome...

No.  Java does not have the syntax to make it even remotely pleasant...and I'm 
not sure that even Java 8 will make monads pleasant in Java.

Original comment by wasserman.louis on 17 Feb 2012 at 1:00

GoogleCodeExporter commented 9 years ago
Trying for release 12 with this, but not certain.

Here is our API for your consideration:

First, you get a FluentIterable using FluentIterable.from(anyIterable) or 
FluentIterable.of(T...).

There are simple queries:

* isEmpty() -> boolean
* contains(Object) -> boolean
* size() -> int

There are the "element extraction" methods:

* first() -> Optional<T>
* last() -> Optional<T>
* getOnlyElement() -> Optional<T> [equiv. to Iterables.getOnlyElement, but 
should we try to find a better name?]
* get(int) -> T?  (Optional.absent() seems like a bad way to respond to an 
invalid index, but I don't know if we have a clear enough justification to be 
different from all the others.)

Then the fun stuff: chaining-style methods which all return FluentIterable:

* filter(Predicate)
* transform(Function)
* limit(int)
* skip(int)
* partition(int) (or we could take this opportunity to split into the two forms 
described in issue 451?)
* append(Iterable) (this is equivalent to Iterables.concat! We are trying to 
remember why we felt a name change was justified. Your thoughts?)
* cycle()

And lastly when you're done with all the chaining stuff, you might want to dump 
the contents into something else:

* toImmutableList() -> ImmutableList<T>
* toImmutableSet() -> ImmutableSet<T>
* toArray() -> T[]

Oh, one other thing: it will not have special equals or hashCode behavior, and 
we are not sure what to do about toString().  Generating 
AbstractCollection-style output seems useful, but we probably want to cap that 
at a certain ceiling, against the risk of 
FluentIterable.from(Ranges.all().asSet(integers())), etc.

What do you think so far, users?

Original comment by kevinb@google.com on 2 Mar 2012 at 8:29

GoogleCodeExporter commented 9 years ago
That looks good and is more or less what I'd expect.

A few thoughts:

> * getOnlyElement() -> Optional<T> [equiv. to Iterables.getOnlyElement, but 
should we try to find a better name?]

This is slightly confusing to me in this context. Does it return absent if the 
iterable is empty, a value if it has one element, and throw an exception if it 
has more?

> * append(Iterable) (this is equivalent to Iterables.concat! We are trying to 
remember why we felt a name change was justified. Your thoughts?)

Maybe it's just me, but I generally think of concat as a standalone operation 
that takes its inputs and concatenates them (as with Iterables.concat), not 
something that one object does to add another to it. Append makes sense for 
that to me; StringBuilder etc. already use it and I think it accurately 
describes what you're doing. "Append the input iterable to this one to produce 
a new iterable." Replace "append" with "concatenate" there and it doesn't sound 
quite right to me.

> * toImmutableList() -> ImmutableList<T>
> * toImmutableSet() -> ImmutableSet<T>
> * toArray() -> T[]

Would it make sense to add a method like this?

* <C extends Collection<? super T>> copyTo(C) -> C

That would allow users to easily dump the contents into a mutable collection if 
desired. On the other hand, maybe it'd be better not to encourage that?

Original comment by cgdec...@gmail.com on 2 Mar 2012 at 9:26

GoogleCodeExporter commented 9 years ago
We considered copyInto(C) as the direct analog of Iterables.addAll().  It's not 
ruled out, but we noticed that within Google, SetView.immutableCopy() has 6x as 
many usages as SetView.copyInto(C). And our internal FluentIterable has become 
pretty popular and no one's ever asked for it yet.

Original comment by kevinb@google.com on 2 Mar 2012 at 10:02

GoogleCodeExporter commented 9 years ago
Just a quick question, it produces new object for each method call right
rather than mutating itself?

Original comment by emily@soldal.org on 2 Mar 2012 at 11:07

GoogleCodeExporter commented 9 years ago
Hi Kevin,

What do you mean by that ?
> it will not have special equals or hashCode behavior

It should at least have the be the same behavior as a list or set of the 
current FluentIterable.

Also, what do you think of using the 'map()' name intead of 'transform()'.
I also would like to see the 'fold' or 'reduce' operator, which makes sense in 
this scenario.

I think naming this properly is better in the long run, just as we like to 
indicate patern names in the code. Having these known higher order function 
naming might actually help users see / understand what functional programming 
means.

Thoughts ?

Original comment by brice.du...@gmail.com on 3 Mar 2012 at 12:51

GoogleCodeExporter commented 9 years ago
> It should at least have the be the same behavior as a list or set of the 
current FluentIterable.

The hashCode and equals behavior of lists and sets is different.  
FluentIterable *really shouldn't* have any special equals or hashcode.

I have mixed feelings about map vs. transform.  I like that the name is the 
same for both Iterables and FluentIterable.

Fold or reduce doesn't make sense unless we either introduce a Pair type (which 
is in the Idea Graveyard and should never happen), or we introduce a binary 
function type, which I don't think we're ready to do.

Original comment by wasserman.louis on 3 Mar 2012 at 2:22

GoogleCodeExporter commented 9 years ago
(See issue 218 on fold/reduce.)

Original comment by wasserman.louis on 3 Mar 2012 at 2:22

GoogleCodeExporter commented 9 years ago
>> It should at least have the be the same behavior as a list or set of the 
current FluentIterable.

>The hashCode and equals behavior of lists and sets is different.  
FluentIterable *really shouldn't* have any special equals or hashcode.

I'm sorry I didn't express what I wanted to say correctly, I wanted to say the 
current FluentIterable *could* use the same behavior as the underlying iterable 
being a List or a Set. 

Anyway I'd like to rollback my after-midnight thought, because Iterable can 
have many different implementations that are not set nor list. I agree with you 
: no special behavior for equals and hashcode.

> I have mixed feelings about map vs. transform.  I like that the name is the 
same for both Iterables and FluentIterable.

Actually without the fold operator. I agree this doesn't make sense to use the 
map name instead of transform. Though it could be aliases.

I don't think Pair was a good option anyway to implement folding, it feels 
unnatural. However I would rather see a binary function type, and one of them 
being an Accumulator type.

Original comment by brice.du...@gmail.com on 3 Mar 2012 at 1:17

GoogleCodeExporter commented 9 years ago
Emily: yes.

Original comment by kevinb@google.com on 3 Mar 2012 at 2:51

GoogleCodeExporter commented 9 years ago
> * get(int) -> T?  (Optional.absent() seems like a bad way to respond to an 
invalid index, but I don't know if we have a clear enough justification to be 
different from all the others.)

Why is that a bad way? And what's the alternative? Both returning `null` and 
throwing an exception (IllegalArgumentException?) seems suboptimal to me (NPEs 
sneaking in, and overhead, respectively). The case for `getOnlyElement` is 
somewhat different, though, so throwing an exception would justified there.

Original comment by j...@nwsnet.de on 5 Mar 2012 at 9:04

GoogleCodeExporter commented 9 years ago

Original comment by kurt.kluever on 5 Mar 2012 at 7:42

GoogleCodeExporter commented 9 years ago
We've implemented something similar to this internally and I've got a use case 
I'd like to see considered that isn't mentioned above.

A means to composite Iterables, similar to Iterables:

<T> Iterable<T> concat(Iterable<? extends Iterable<? extends T>> inputs)

Note that you've got an iterable of iterables here, which naturally maps onto 
something like this:-

FluentIterable<Out> concat(Function<? super T, Iterable<Out>> function)

If T extends Iterable then the function can just be the identity.

This is much more powerful than append(Iterable) - roughly 3:1 ratio of usage 
in our code base of a concat-like operation versus append.

Original comment by MrChrisP...@googlemail.com on 12 Mar 2012 at 9:57

GoogleCodeExporter commented 9 years ago
Just hit head! 
http://code.google.com/p/guava-libraries/source/detail?r=ec452d24ada3b476ede4bbd
9c68e71d4211c0afe

@MrChrisPSimmons + others: Can you please file a separate issue for your 
requests?  Thanks :-)

Original comment by kak@google.com on 13 Mar 2012 at 8:50

GoogleCodeExporter commented 9 years ago
Awesome! I added a review for the commit with a couple questions.

Original comment by cgdec...@gmail.com on 13 Mar 2012 at 10:13

GoogleCodeExporter commented 9 years ago
This issue has been migrated to GitHub.

It can be found at https://github.com/google/guava/issues/<id>

Original comment by cgdecker@google.com on 1 Nov 2014 at 4:16

GoogleCodeExporter commented 9 years ago

Original comment by cgdecker@google.com on 3 Nov 2014 at 9:10