Type-safe versions of Clojure's immutable/persistent collections, an immutable alternative to Java 8 Streams, and other tools to make functional programming in Java easier.
You are on the Paguro Classic, or main branch of this project.
If you work with a mix of Java and Kotlin files, you may wish to try Paguro-KF 3.5.x in the
If you want to live dangerously, try the all-Kotlin version in the 4.0 branch when it becomes available.
Photo by Rushen
Paguro is short for the Latin "Paguroidea" - the name of the Hermit Crab superfamily in Biology. These collections grow by adding a new shell, leaving the insides the same, much the way Hermit Crabs trade up to a new shell when they grow.
Available from the Maven Repository as:
<!-- If you're using Kotlin and Java, you want the 3.5 version in the KotlinFootWetting branch. Java-only users want 3.x from the main branch. --> <dependency> <groupId>org.organicdesign</groupId> <artifactId>Paguro</artifactId> <version>3.1.3</version> </dependency>
The Maven artifact is the easiest way to use Paguro, but you can build from source if you want to.
@jafingerhut has found bugs in the RRB Tree join implementation. See issue 31 and 36. I normally try to fix bugs promptly, but the issue here is that I don't know how to fix it! I understood a new chunk of the problem last night 2020-02-01 and am probably going to use jafingerhut's algorithm for a solution. If anyone knows of a paper with a working algorithm for merging two n-ary BTrees, let us know!
An RRB Tree is an immutable List (like Clojure's PersistentVector) that also supports random inserts, deletes, and can be split and joined back together in logarithmic time. Details: https://github.com/GlenKPeterson/Paguro/releases/tag/3.0.16
This announcement is making some people nervous even as it makes others happy. The primary curator (Glen) will still continue using Paguro in both Java and Kotlin for at least a year, maybe forever. Kotlin is nearly 100% backward-compatible with Java 8. I've met several people who know Paguro but not Kotlin, but I have yet to meet the person who knows both and likes Paguro but not Kotlin.
You are probably interested in Paguro because you like Immutability, Functional Programming (maybe as pure as Haskell, maybe not), and Types. Kotlin is a briefer Java that assumes immutability, makes Functional Programming easier, and plugs 3/4 of the quirks in Java's generic type system. If you're concerned about the future of Paguro, I think the best way to put your worries to rest is to try Kotlin. It's pretty great!
If a rewrite in Kotlin sounds good to you, consider voting for this issue because without it, I'll have to maintain separate Java and Kotlin code.
Check back for more details as the 4.x release progresses.
Check the Change Log for details of recent changes.
vec("one", "two", "three")- an immutable vector/list of three strings
set(3, 5, 7)- an immutable set of three integers
tup("Alice", 11, 3.14)- an immutable 3-field tuple or record
map(tup(1, "single"), tup(2, "double"), tup(3, "triple"))- an immutable map that uses integers to look up appropriate strings.
Paguro takes advantage of Java's type inferencing. It eschews void return types, arrays, primatives, and checked exceptions in lambdas. It can decrease the amount of code you need to write by a factor of at 2x-3x. Using functional transfomrations instead of loops focuses you on choosing the right collections which leads to more readable code AND better Big O complexity/scalability.
// Define some people with lists of email addresses on the fly. // vec() makes a Vector/List, tup() makes a Tuple vec(tup("Jane", "Smith", vec("[email protected]", "[email protected]")), tup("Fred", "Tase", vec("[email protected]", "[email protected]", "[email protected]"))) // We want to look up people by their address. // There are multiple addresses per person. // For each person, find their email addresses. .flatMap(person -> person._3() // For each address, produce a key/value pair // of email and person (Tuple2 implements Map.Entry) .map(email -> tup(email, person))) // toImMap() collects the results to key/value pairs and puts // them in an immutable map. We already have pairs, so pass // them through unchanged. .toImMap(x -> x) // Look up Jane by her address .get("[email protected]") // Get her first name (returns "Jane") ._1();
Other usage examples are implemented as unit tests to ensure that they remain correct and current.
Get started now by following the Usage Tips
JimTrainer self-guided training consists of a few short problem-sets for learning Paguro
It started with a Software Engineering Stack Exchange question: Why doesn't Java provide immutable collections?
Why Java? That said, this could become a Kotlin-based project.
Java™ is a registered trademark of the Oracle Corporation in the US and other countries. Paguro is not part of Java. Oracle is in no way affiliated with the Paguro project.
Paguro is not part of Clojure. Rich Hickey and the Clojure team are in no way affiliated with the Paguro project, though it borrows heavily from their thoughts and is partly a derivative work of their open-source code.
The Clojure collections are licensed under the Eclipse Public License. Versions of them have been included in this project and modified to add type safety and implement different interfaces. These files are still derivative works under the EPL.
Unless otherwise stated, the rest of this work is licensed under the Apache 2.0 license. New contributions should be made under the Apache 2.0 license whenever practical. I believe it is more popular, clearer, and has been better tested in courts of law.
The pre-built maven artifact is the easiest way to use Paguro. Mose users do not need to build Paguro from source.
Paguro should build on Ubuntu 16.04 and later with
maven installed from the official repositories. A compiler bug in javac 1.8.0_31 prevents building Paguro, but OpenJDK 126.96.36.199 and later (or Oracle) should work on Windows or Mac.
Depending on how you installed Java and Maven, you may need to set some of the following in your
~/.profile file and reboot (or source that file like
. ~/.profile from the command line you will use for the build). Or do whatever Windows does. If your tools are installed in different directories, you will have to fix the following:
export JDK_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export JAVA_HOME=$JDK_HOME/jre export M2_HOME=$TOOLS/apache-maven-3.3.9/ export M2="$M2_HOME"bin export PATH=$PATH:$M2
# Start in an appropriate directory # You need TestUtils for Paguro's equality testing. # The first time you build, get a local copy of that and Paguro git clone https://github.com/GlenKPeterson/TestUtils.git git clone https://github.com/GlenKPeterson/Paguro.git # Build TestUtils: cd TestUtils git pull mvn clean install cd .. # Build Paguro: cd Paguro git pull mvn clean install cd ..
If you submit a patch, please:
Additional information is in: README2.md.