different paradigms - people find it hard to switch from one to the other - make it easier for OOPS programmers to adopt Clojure - Explain the differences - Clojure built on Java - focus on Clojure underlying workings as it relates to Java - Refrain from comparing which one is better.
based on real-world entities • Define a contract for use of entity and hide all other data. public class Adder { private int x = 0; public Adder(int x1) { x = x1; } public int add(int y) { return x + y; } } Functional Programming - Clojure Emphasis on Data Immutability • Functions return the same output for given input • Lisp-based - code-as-data • Hosted on the JVM (ns Adder) (defn add-int [x y] (+ x y))
state change. • It’s important to follow best practices to control the state change. • References also lead to null objects. public foo(Adder adder) { adder.add(10); } Adder myAdder = new Adder(5); foo(myAdder); System.out.println(myAdder);
of references. OOPs Programmer: So you make copies of data every time a function returns a value?!! Clojure Programmer: Heck No! • Efficient copies by sharing elements from original data structure while maintaining Persistent Data Structures.
on the JVM • All underlying Java functionality is available. (.trim (String. " test ")) -> “test” (type " test ") -> java.lang.String (.trim " test ") -> “test” (clojure.string/trim " test ") -> “test”
collections need to implement the Iterator interface. • Seq follows the abstraction pattern, mostly all Clojure collections implement the ISeq interface. • Stateless and persistent compared to Iterator. (every? seq ["1" [1] '(1) {:1 1} #{1}]) => true
Key concept in OOP - override or overload. Polymorphism public class Adder implements MyMath { int compute (int x) {} float compute (float f, int p) {} } public class ComplexAdder extends Adder { int compute (int x) {} float compute (float f, int p) {} } public interface MyMath { int compute (int x); float compute (float f, int p); }
Java Interface internally. • Interface can be implemented using defrecord or deftype. • defrecord generates bytecode for a Java class with the given name in a package with given namespace. Polymorphism - Clojure (def myadder1 (Adder. 1)) -> user.Adder (compute myadder1 2) -> 3 (defprotocol MyMath (compute [this y])) (defrecord Adder [x] MyMath (compute [_ y] (+ x y)))
for concurrent programming • That said, there is controlled support for shared state management using a few data types - Vars, Refs, Agents, Atoms. • Atoms - Based on underlying Java Atomic variables. For example, AtomicInteger. • Leverage machine-level compare-and-swap (CAS) - ◦ Apply a function to the atom with a given current value. ◦ Function will CAS new value only if current value = expected old value. ◦ Else retry.
codebases can end up being inefficient if best practices not applied. • Important to understand the Paradigm and the underlying workings to master any language.