Look over my notes and add in anything I’m missing about Clojure, and let me know of any inaccuracies you see. Try to keep to the same lowercase point form writing style.

## Basics ##

Clojure
- lisp heritage
    - lisp dialect with functional emphasis
    - well designed thanks to that
    - prefix notation
        - operator comes first
- clojure.jar is the runtime environment containing the compiler and libraries
    - takes code in clojure, compiles to JVM java bytecode
- hosted language
    - JVM provides garbage collection and more
    - can also work with javascript (clojurescript) and .net (clojureCLR)
- general-purpose language
    - code represented as data structures
    - suited for distributed and parallel computing
    - immutable data, functions, structures
- no fixed types, giving flexibility
    - programming to abstractions
        - so long as a data structure fits sequence operations, it will work with any of the operations that target sequences
        - due to polymorphism
            - base functions with the same name call different function bodies based on what they receive

Leiningen
- dependency manager
    - on new launch, automatically pulls all dependencies needed for the project
- builds and manages projects for clojure
    - lein new app alkjalf TO create new project
    - lein uberjar TO create new package


REPL
- read evaluate print loop
- interactive development and testing
    - quick feedback cycle
- can be integrated with various IDEs
- like a local ssh for a running clojure process



## Concepts ##

Immutability
- cannot be changed, altered, modified once created
    - ensures data integrity and consistency
- once created, cannot be modified - any modifications result in a new data structure
    - vectors, maps, sets are data structures that follow immutability
        - can be created with vector, hash-map, hash-set
        - modified with conj, assoc, more
        - anything that "updates" just returns a new structure with different values
    - functions also immutable
    - immutability can be technically circumvented with atoms but they still follow rules
- def permanently binds a name to a value
    - defn binds a name to a function

Truthiness/Falsiness
- many functions work on interpreting values based on whether they are truthy or falsey
- true and non-nil values are considered truthy
- false and nil are considered falsey, no concept of undefined

Simplicity
- It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures. —Alan Perlis

Namespaces
- isolate and organize code in separate, named contexts to avoid name collisions
    - ns to declare
    - :require to bring things in from other namespaces
    - :import to bring in java classes
    - :alias to create shorthand

** Functional Programming
- emphasizes functions as primary building blocks of programs
    - functions can be passed as arguments and returned as values
    - avoiding state and mutable data as much as possible in favour of pure functions
        - pure functions always return the same result, and have no side-effects
- essentially everything is math and numbers, which are pure
- functions are like first-class citizens

** Higher Order Functions
- take other functions as arguments
    - or return them as results
- function that wraps over another function and returns a larger function
- many higher order functions already exist
    - eg. map, filter, reduce

State and Identity
- though not encouraged, mutable state and identity are available
    - atoms, refs, agents, and dynamic vars are mechanisms for state management
    - ideally done through transactions

Concurrency
- software trnsactional memory
    - allows multiple threads to share data without locks
    - creates transaction log
        - if attempt is made to modify, check if data has been modified
        - if so, thread can retry or abort
- clojure reduces risk of deadlocks or race conditions returning different results
    - writers don't block readers and commuters
    - readers don't block writers, other readers, or commuters
    - i/o though should be avoided in transactions since they will be retried
- concurrency commands for transactions
    - dosync for multiple operations in one transaction
    - ref-set and alter to atomically modify reference
        - ref-set-validator and alter-validator calls function before reference is changed
    - commute to atomically modify without blocking
- STM and macros assist concurrent application development

Debugging
- identify problem
    - LOOK AT REPL, LINE NUMBER IS USUALLY GIVEN
    - examine log files, run tests, use debugging tools
- isolate issue
    - use REPL to evaluate expressions
- fix problem by changing code
- test to make sure it's fixed
- write things step by step not in big chunks
- "ooooo cannot be cast to clojure.lang.IFn" means something that is not a function is trying to be called as one

Lazy Evaluation
- returns the recipe to generate requested elements
- evaluation is delayed until value needed
    - improves performance by avoiding unnecessary computation
    - evaluates a block of 32 at a time, only getting what's needed
        - lazy computing is expensive, so the block evaluation helps mitigate it
        - still worth using non-lazy functions for performance though, like mapv and filterv
    - used for infinite data structures
- lazy-seq is the main function, but many functions return lazy sequences
- opposite is eager

Destructuring
- concisely bind names to values in a collection to write more human-readable code
- supports vectors ([a b c]), maps ({:keys [a b c]}), and more complex nested patterns
    - eg put brackets or braces the defn parameter
        - (defn get-eggs [{first-egg :egg1 second-egg :egg2}]
        - (println first-egg second-egg))
        - (get-eggs {:egg1 "brown" :egg2 "bluebird"}) => "brownbluebird"
    - can also use [{:keys [egg1 egg2]} :as egg-basket]


## Tools ##

Functions
- takes input, performs operations, returns result
    - can take different inputs and return different results
    - immutable, like everything
        - same input always gives same result
- evaluated at runtime
    - executed while program is running
    - evaluated each time it is called
- function call is an operation where operator is a function
    - or a function expression (expression that returns a function)
- always returns last evaluated form
- all functions, built-in or created, are evaluated the same
- can support multi-arity, and perform different operations based on number of arguments

Anonymous Functions
- different forms
    - (fn [] body)
    - (def cool-function (fn [] body)) == (defn cool-function [] body)
    - #(body %)
        - % is argument passed in if not defined
            - can do %1 %2 and %& to indicate order of passed functions
- useful for short-lived, throwaway functions or simple ops

Macros
- didn't cover anything about macros yet
- create custom functions to manipulate code at compile time
- can create data structures etc
- can be used to create domain-specific languages
    - express complex operations in a readable way
- can be used to optimize code
    - eliminate unnecessary structures
    - replace with more efficient ones
- create custom control structures
    - eg. looping constructs
- evaluated only once
- examples: threading -> ->>, when

** Request/Response
- specifically refer to handling HTTP requests and responses
    - the framework Ring will handle these

** Dynamic Variables
- 4 different mechanisms for referencing a changing value
- Vars are usually static but can be made dynamic with ^:dynamic and binding (macro)
- Ref is atomic reference type
    - atomic means that every change to Refs made within a transaction occurs or none do
    - isolated (blind to other transactions while running) and consistent (checked with validator)
    - multiple threads can access and modify data safely and consistently
    - managed with transactions
- Agents
    - manage state in non-blocking, asynchronous way
- Atoms also allow multiple threads
    - not transactional
    - any changes are immediately visible to all threads
    - uncoordinated, independent state

Docstrings
- can be defined with the function or the def
- provide descriptions and usage examples for functions
    - improve code readability and provide in-REPL documentation

Arity
- functions can be defined to do different things depending on how many parameters are given
- variable numbers of parameters are indicated with &
- can use arity overloading to give default values if not given, etc

Let bindings
- provide clarity by letting you sassign aliases for values
    - bindings are immutable, only valid in local scope
- evaluate expression once, use result for anything
    - important for expensive calculations, side-effect causing i/o etc, or network calls
- letfn variant for mutually recursive local functions

Regex
- put regex in quotes after a hash mark
- supports java's regex using re-* functions
    - re-find, re-seq etc

Transducers
- composable algorithmic transformations
    - performs operation before deciding how many times to call what it wraps
    - into, sequence, transduce


## Data Structures ##

Values
- Booleans
    - true or false
- Symbols
    - identifiers for vars or functions
- Strings
    - double quotes
    - concatenated with str function
- Numbers
    - represented directly
    - can do integers, floats, ratio/fraction no problem
- Keywords
    - primarily used as keys in maps
    - mostly defined as :key-name but can be anything

Collections
- Vectors
    - [collection of indexed elements]
    - used when order matters, eg access by index
    - manipulate with first, rest, conj etc
    - index starts at 0
    - conj adds to end
- Sets
    - #{unordered collection of unique elements}
    - used when unique elements are necessary or to remove repeated elements from vector
        - duplicates ignored when adding
    - set operations like union, intersection, difference
    - can check membership with get or contains?
        - get returns value or nil, contains returns true or false
- Maps
    - {:key-value "pairs"}
    - used to efficiently find and organize data associated with an element
    - keys must be unique
        - keys can map to only one value, but the value can also be a collection of more key-value pairs
    - assoc-in, get-in, update-in for nested structures
    - dissoc is useful too
- Lists
    - '(linear collections of values)
    - conj adds to beginning of list
    - used mostly for macros or if you need to append to start




## Function Notes ##
- when
    - different from if in that it performs multiple operations without needing to use do
- when-not complements when, providing a body of expressions to evaluate when a condition is false.
    - cond for multiple branches instead of a simple if or when
    - case for efficient dispatch among multiple potential matches

- assert throws an exception if its condition does not evaluate to true

- -> and ->> 
    - threading macros for more readable function chaining

- or returns first truthy value or last value
- and returns first falsey value or last value **

- Reduce
    - applies a function to elements of a collection to reduce to a single value
    - flattens out sub-collections
    
- letfn for defining local functions within a let binding form

- apply
    - passes a collection's elements' vals to the function as separate arguments

- partial
    - takes function and any number of arguments
    - supplies the function and those arguments as the base for the new function

- complement for the opposite of a boolean

- Filter
    - take-while and drop-while can be more performant if data is sorted

- memoize
    - stores arguments passed to a function and the return value
    - subsequent computes just return the result immediately
    - useful for things that take time to run 

## Other Considerations ##

Java Interop
- can interoperate with java, calling java methods and using java classes
    - can create java objects, call their methods and access fields
- often uses a period to denote the interop

Testing
- unit tests commonly written using the clojure.test library
    - testing pure functions is recommended, immutability helps with reliable tests

Error Handling
- uses exceptions for error handling 
    - try and catch blocks similar to java
    - callstack based


## Common Libraries ##

core.async
- provides asynchronous and concurrent programming through the use of channels
    - things will be delivered to channels and able to be taken
    - a more fully fledged version of promises
    - can choose to buffer channels and push things out of the stack first out or last out
- built on go blocks for concurrent operation
- uses a pool of available threads instead of spinning up new threads every time, removing overhead


JDBC/PostgreSQL
- org.postgresql/postgresql and org.clojure/java.jdbc libraries are used for interacting with PostgreSQL databases using the Java Database Connectivity (JDBC) API
    - used for database operation integration
    - querying, updating records, everything you can do with SQL
SQLite
- org.xerial/sqlite-jdbc is much the same, but for SQLite databases also using JDBC
Ring
- handles middleware, adapters for web servers, session management
- models HTTP requests as clojure maps
Compojure
- routing library for Ring
    - match URL patterns to functions that handle requests
    - easy middleware integration through ring
Hiccup
- HTML interpretation library
    - can represent HTML by using vectors and maps to define elements and attributes
    - generates HTML based on those structures

Medley
- wide range of pure utility functions
    - again, pure means no side effects
- performs common operations that are missing in the standard clojure library

Cheshire
- JSON parsing and processing library

Pretty Print
- takes your garbage and makes it easier to read with formatting