A value at a moment in time. This could be UI status, data from endpoints, configuration, user input, or any number of other variables.
As complexity grows, so does shared state. Design patterns like OOP and FP are a way to manage that complexity.
Object-Oriented Programming segregates shared state into object instances with interface methods, allowing each object to manage state independently.
Functional Programming seeks to minimize state and restrict it to carefully controlled portions of your application.
It embraces strategies from category theory to enable compositional programming. Complex abstractions are built up from smaller, pure operations that can be combined in solid and predictable ways.
Ensures that a variable’s value always matches the variable’s static type.
This can be accomplished at compile time, runtime, or a combination.
Type inference allows annotations to be omitted.
Polymorphism allows types to vary.
Ensures your program can’t get into certain invalid states. A sound type system means you can never get into a state where an expression evaluates to a value that doesn’t match the expression’s static type.
Functional programming was introduced in the 1950s with LISP. It actually came before OOP!
At the time, memory was very expensive. OOP required less memory.
Even today, mutation gives Object-Oriented code a performance advantage while sacrificing predictability.
In practice, it works! Errors and unpredictable side effects are much less of an issue. Complexity remains a constant foe, however, especially in languages with terse syntax and user-defined operators.
What started as a simple document markup language has grown into a full-scale, cross-platform, accessible, realtime engine for rich applications.
The browser is turning into an embedded operating system, built around JavaScript - a very loose and dynamically typed environment.
An object-oriented focus inherited from Java coupled with very loose and often-silent error handling resulted in the proliferation of buggy, difficult-to-maintain front end applications.
Race conditions and runtime errors became the bane of browser-based development.
Elm focuses on strict, sound type safety coupled with a strong emphasis on developer experience, with features like friendly error messages and rich tooling.
Interop is restricted to JSON messaging, allowing for exhaustive validation to ensure soundness.
Benchmarking shows that Elm's opinionated implementation of the virtual DOM is extremely performant, outdoing competitors with room to spare.
🎉
The lack of polymorphism and higher-kinded types leads to some frustration when trying to avoid boilerplate and repetition.
Because Elm code is built for the browser, code sharing across environments is not well-supported.
Projects to bring Elm to the server or to native clients like iOS or Android are experimental, and not ready for prime time.
The unfamiliar representation of HTML presents challenges for collaboration.
Monomorphic Types
Abstraction by convention -
Restrictive Interop
Via JSON message-passing -
Single Environment
Currently browser-only -
Strict Immutability
Values change through - events
Polymorphic Types
- Generic types
- Extensible records
- Higher-kinded types
Foreign Function Interface
- BuckleScript
- Convenience macros
Flexible Build Targets
- Windows, Linux, Mac, JavaScript, iOS, Android
Optional Mutability
- Refs to differentiate mutable values explicitly
"Codify" your domain knowledge as custom types, and use a switch statement to make decisions based on them.
Exhaustive checking ensures you don't miss a case. Type arguments allow you to pass additional data with a variety of uses.
Custom, flexible types that don't have to be defined and imported in order to be used. The types can be used interchangeably in many situations.
The sound type system allows for powerful abstractions based on category theory.
Allows you to pre-process your OCaml code, transforming it before it is compiled.