You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: README.md
+60-1
Original file line number
Diff line number
Diff 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:
2
2
3
3
* Type-safe versions of Clojure's immutable collections
4
4
* 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
29
29
.map(i -> i -2) // 3, 4, 5, 6, 7
30
30
.take(4) // 3, 4, 5, 6
31
31
.drop(2) // 5, 6
32
+
.toImList()); // Stores result in an immutable PersistentVector
32
33
```
33
34
34
35
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
42
43
#Self-Guided Training
43
44
[JimTrainer](https://github.com/GlenKPeterson/JimTrainer) contains a few short problem-sets for learning UncleJim
44
45
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(),
0 commit comments