Skip to content

Commit a93d268

Browse files
author
Glen K. Peterson
committed
Added FAQ and fixed errors in docs based on questions received.
1 parent efe605e commit a93d268

File tree

3 files changed

+65
-6
lines changed

3 files changed

+65
-6
lines changed

README.md

+60-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
UncleJim ("**Un**modifiable **Coll**ections for **J**ava™ **Imm**utability") brings the following to Java:
1+
UncleJim ("**Un**modifiable **Coll**ections for **J**ava **Imm**utability") makes standard Java code cleaner and safer by providing:
22

33
* Type-safe versions of Clojure's immutable collections
44
* An immutable Transformable. This is a simplified alternative to Java 8 Streams, based on the ideas behind Paul Philips' Views.
@@ -29,6 +29,7 @@ vec(4, 5) // 4, 5
2929
.map(i -> i - 2) // 3, 4, 5, 6, 7
3030
.take(4) // 3, 4, 5, 6
3131
.drop(2) // 5, 6
32+
.toImList()); // Stores result in an immutable PersistentVector
3233
```
3334

3435
More extensive examples are implemented as unit tests to ensure that they remain correct and current.
@@ -42,6 +43,64 @@ More extensive examples are implemented as unit tests to ensure that they remain
4243
#Self-Guided Training
4344
[JimTrainer](https://github.com/GlenKPeterson/JimTrainer) contains a few short problem-sets for learning UncleJim
4445

46+
#FAQ
47+
48+
##Q: How does this compare to pcollections?
49+
50+
[pcollections](http://pcollections.org/) competes only with UncleJim's first bullet point: immutable collections.
51+
Clojure's vector (list) and hashMap/hashSet have "big O of log base 32 of n" asymptotic performance, which theoretically scales better than the binary tree structures it looks like pcollections uses (those are log base 2 of n).
52+
You can see this for yourself by using the change-base formula to Google: y=(ln x)/(ln 2), y=(ln x)/(ln 32)
53+
54+
#[Graph of Log base 32 (red) vs. Log base 2 (blue)](logBase2VsLogBase32.png)
55+
56+
This graph shows how many operations each lookup requires (vertical axis) when there are a given number of items in the collection (horizontal axis).
57+
Daniel Spiewak explains all the ramifications of this really well: https://www.youtube.com/watch?v=pNhBQJN44YQ
58+
59+
The Clojure collections also walk the sibling nodes in the internal data trees of these structures to provide iterators, which is pretty cool performance-wise.
60+
At least in the list implementation, pcollections starts from the top of the tree doing an index lookup for each item, then increments the index to look up the next.
61+
62+
Clojure's (and Java's) sorted/tree map/set implementations are log base 2, so pcollections could theoretically be as fast or faster for those two collections.
63+
If someone does performance testing to verify these theories, please let me know so I can link to it here.
64+
65+
UncleJim has additional benefits listed in the bullets at the top of this document.
66+
67+
##Q: Do these Transforms create intermediate collections between each operation (like the Scala collections)?
68+
69+
No.
70+
Xform is a lazy, immutable builder for transformations.
71+
It records the operations you specify without carrying any of them out.
72+
When you call foldLeft() or one of the "endpoint" methods like toImList(), it creates the lightest-weight execution path and performs simplified operations in a for loop with only 3 if statements (some have sub-branches).
73+
On my machine, single-threaded, with 30 million items in an ArrayList source, Xform takes an average of 122ms as opposed to 120ms for the native for loop - better than 98% as fast as the fastest iteration available on the JVM, but with much more functionality.
74+
The heart of the implementation is [_foldLeft() in Xform](src/main/java/org/organicdesign/fp/xform/Xform.java), but it's kind of where "useful and easy to code" meets "fast to execute" and is probably some of the hardest code in the project to read and comprehend.
75+
The Transfom implementation is loosely based on [Paul Philips concept of a "View,"](https://www.youtube.com/watch?v=uiJycy6dFSQ&t=26m19s) not on Clojure's Sequence abstraction.
76+
77+
There is only one exception: a second version of foldLeft() that takes an extra terminateWhen parameter to stop processing based on an output condition instead of an input condition.
78+
I think I've used it once, ever, in a real-world situation (normally you use takeWhile to terminate based on an input condition).
79+
It uses a temporary internal ArrayList to accumulate results for the termination test, then later converts them to whatever output format you specify.
80+
81+
##Q: How does this compare to Streams and lambda expressions in JDK8?
82+
83+
* When you process data with a Java8 stream, you end up with a mutable collection.
84+
You can choose to do that with UncleJim, but it's safer to store your result in an immutable collection.
85+
java.util.Collections can wrap mutable collections in an unmodifiable wrapper, but UncleJim's wrappers also deprecate the mutator methods so that your IDE and compiler warn you if you try to call them.
86+
87+
* If you later want a near-copy of a collection, (with a few items added or removed), Unmodifiable collections require an expensive defensive copy of the entire collection.
88+
The Clojure-derived collections in UncleJim only duplicate the tiny area of the collection that was changed
89+
to return a new immutable collection that shares as much data as practical with the old one.
90+
As immutable collections go, they have excellent performance.
91+
92+
* The [java.util.function interfaces do nothing to help you with Exceptions](src/test/java/org/organicdesign/fp/TradJavaStreamComparisonTest.java#L258).
93+
[UncleJim wraps checked exceptions in unchecked ones](src/main/java/org/organicdesign/fp/function/Function1.java#L29) for you, so that you can write
94+
anonymous functions more like you would in Scala.
95+
96+
* Complexity: For up to 2-argument functions, java.util.function has 43 different interfaces.
97+
The functional methods on these interfaces have 11 different names, depending on which of the 43 interfaces you use: accept(),
98+
apply(), applyAsDouble(), applyAsInt(), applyAsLong(), test(), get(), getAsBoolean(), getAsDouble(), getAsInt(), or getAsLong().
99+
UncleJim has 3 equivalent interfaces, named by number of arguments: Function0, Function1, and Function2.
100+
All have an applyEx() that you override and an apply() method that callers can use if they want to ignore checked exceptions (they usually do).
101+
If you don't want to return a result, declare the return type as ? and return null.
102+
For example: `Function1<Integer,?>` takes an Integer and the return value is ignored.
103+
45104
#Change Log
46105
See [changeLog.txt](changeLog.txt)
47106

logBase2VsLogBase32.png

7.49 KB
Loading

src/main/java/org/organicdesign/fp/function/package.html

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<html>
22
<body>
33
<p>Exception-friendly functional interfaces named by the number of arguments: Function0, Function1, Function2....
4-
All of these have an <code>apply()</code> method that that throws an Exception and returns a result.
5-
Implementers should override the apply method.
6-
Each interface also has a default <code>apply_()</code> method for consumers of this function to call.
7-
It re-throws all exceptions after wrapping any checked exceptions in unchecked <code>RuntimeException</code>s.</p>
4+
All of these have an <code>applyEx()</code> method that that throws an Exception and returns a result.
5+
Implementers should override the <code>applyEx()</code> method.
6+
Each interface also has a default <code>apply()</code> method for consumers of this function to call.
7+
It re-throws all exceptions after wrapping any checked ones in unchecked <code>RuntimeException</code>s.</p>
88

9-
<p>For simplicity, there are no primitive versions of these functions, no "void" return types (except SideEffect), and no special-purpose funny names.
9+
<p>For simplicity, there are no primitive versions of these functions, no "void" return types, and no special-purpose funny names.
1010
If you don't want to return a result, declare the return type as <code>?</code> and return null.
1111
Comparing just the Consumer interfaces from { @link java.util.function}:</p>
1212

0 commit comments

Comments
 (0)