Recent Posts
Archives

Posts Tagged ‘FunctionalProgramming’

PostHeaderIcon [DevoxxBE2013] Lambda: A Peek Under the Hood

Brian Goetz, Java Language Architect at Oracle, offers an illuminating dissection of lambda expressions in Java SE 8, transcending syntactic sugar to reveal the sophisticated machinery powering this evolution. Renowned for Java Concurrency in Practice and leadership in JSR 335, Brian demystifies lambdas’ implementation atop invokedynamic from Java SE 7. His session, eschewing introductory fare, probes the VM’s strategies for efficiency, contrasting naive inner-class approaches with optimized bootstrapping and serialization.

Lambdas, Brian asserts, unlock expressive potential for applications and libraries, but their true prowess lies in performance rivaling or surpassing inner classes—without the bloat. Through benchmarks and code dives, he showcases flexibility and future-proofing, underscoring the iterative path to a robust design.

From Syntax to Bytecode: The Bootstrap Process

Brian traces lambdas’ lifecycle: source code desugars to invokedynamic callsites, embedding a “recipe” for instantiation. The bootstrap method, invoked once per callsite, crafts a classfile dynamically, caching for reuse.

This declarative embedding, Brian illustrates, avoids inner classes’ per-instance overhead, yielding leaner bytecode and faster captures—non-capturing lambdas hit 1.5x inner-class speeds in early benchmarks.

Optimization Strategies and Capture Semantics

Capturing lambdas, Brian explains, leverage local variable slots via synthetic fields, minimizing allocations. He contrasts “eager” (immediate class creation) with “lazy” (deferred) strategies, favoring the latter for reduced startup.

Invokedynamic’s dynamic binding enables profile-guided refinements, promising ongoing gains. Brian’s throughput metrics affirm lambdas’ edge, even in capturing scenarios.

Serialization and Bridge Methods

Serializing lambdas invokes writeReplace to a serialized form, preserving semantics without runtime overhead. Brian demos bridge methods for functional interfaces, ensuring compatibility.

Default methods, he notes, extend interfaces safely, avoiding binary breakage—crucial for library evolution.

Lessons from Language Evolution

Brian reflects on Lambda’s odyssey: discarded ideas like inner-class syntactic variants paved the way for invokedynamic’s elegance. This resilience, he posits, exemplifies evolving languages amid obvious-but-flawed intuitions.

Project Lambda’s resources—OpenJDK docs, JCP reviews—invite deeper exploration, with binary builds for experimentation.

Links:

PostHeaderIcon [DevoxxFR2013] WTF – What’s The Fold?

Lecturer

Olivier Croisier operates as a freelance Java expert, trainer, and speaker through Moka Technologies. With over twelve years in the field, he assists clients in Java 8 migrations, advanced stack development, and revitalizing team enthusiasm for coding.

Abstract

Olivier Croisier elucidates the fold concept from functional programming, demonstrating its abstraction of iteration for enhanced code expressiveness. Using Java 8 streams and Haskell parallels, he dissects implementations, applications in mapping/filtering/reducing, and performance implications. The analysis positions fold as a versatile pattern surpassing traditional loops, integrable even in pre-Java 8 environments.

Origins and Essence: Fold as Iterative Abstraction

Croisier traces fold to functional languages like Haskell, where it generalizes accumulation over collections. Left fold (foldl) processes sequentially; right fold (foldr) enables laziness.

In essence, fold applies a binary operation cumulatively: start with accumulator, combine with each element.

Java analogy: external iterators (for-loops) versus internal (streams). Fold internalizes control, yielding concise, composable code.

Implementing Fold in Java: From Basics to Streams

Pre-Java 8, Croisier crafts a utility:

public static <T, R> R fold(Collection<T> coll, R init, BiFunction<R, T, R> f) {
    R acc = init;
    for (T e : coll) acc = f.apply(acc, e);
    return acc;
}

Usage: sum integers—fold(list, 0, (a, b) -> a + b).

Java 8 streams natively provide reduce (fold alias):

int sum = list.stream().reduce(0, Integer::sum);

Parallel streams distribute: .parallelStream().reduce().

Croisier notes identity requirement for parallelism; non-associative operations risk inconsistencies.

Beyond Reduction: Mapping, Filtering, and Collection Building

Fold transcends summing; rebuild collections:

List<String> mapped = fold(list, new ArrayList<>(), (acc, e) -> { acc.add(transform(e)); return acc; });

Filter via conditional accumulation. This unifies operations—map/filter as specialized folds.

Haskell’s foldr constructs lists lazily, enabling infinite structures. Java’s eager evaluation limits but streams offer similar chaining.

Expressive Power and Performance Trade-offs

Croisier contrasts verbose loops with declarative folds, enhancing readability/maintainability. Encapsulate patterns in methods for reuse/optimization.

Performance: sequential folds match loops; parallel leverages multicore but incurs overhead (threading, combining).

JVM optimizations (invokedynamic for lambdas) potentially outperform anonymous classes. Croisier advocates testing under load.

Versus map-reduce: fold suits in-memory; Hadoop for distributed big data.

Integration Strategies and Broader Implications

Adopt incrementally: utility class for legacy code. Java 8+ embraces streams.

Croisier views fold as expressivity tool—not replacing conditionals but abstracting mechanics.

Implications: functional paradigms ease concurrency, prepare for multicore era. Fold’s versatility—from reductions to transformations—elevates code abstraction.

Links:

PostHeaderIcon [DevoxxFR2013] FLATMAP ZAT SHIT: Monads Explained to Geeks

Lecturer

François Sarradin is a Java and lambda developer, serving as a technical capitalization manager. He contributes to the Brown Bag Lunch initiative, sharing expertise through presentations.

Abstract

François Sarradin’s session introduces monads in functional programming, using Scala and Java 8 examples to demystify their utility. He addresses handling errors, asynchrony, and technical concerns without cluttering business logic, employing monadic structures like Try and Future. The talk analyzes code transformations for cleaner, composable designs, highlighting monads’ role in aspect-oriented programming and drawing parallels to AOP frameworks.

The Problem: Technical Debt Obscuring Business Logic

Sarradin illustrates a common plight: initial clean code accumulates technical safeguards—null checks, try-catch blocks, synchronization—eroding readability and productivity. He proposes separating concerns: keep business logic pure, inject technical aspects via mechanisms akin to aspect-oriented programming (AOP).

Using AOP tools like AspectJ or Spring AOP declares cross-cutting concerns (e.g., logging, error handling) separately, leveraging compilers for coherence. This maintains original code structure while addressing realities like exceptions or async calls.

An example application in Scala computes total balance across bank accounts, initially straightforward but vulnerable. Technical intrusions (e.g., if-null, try-catch) bloat it, prompting a search for elegant solutions.

Introducing Monads: Error Handling with Try

To manage errors without pervasive checks, Sarradin introduces the Try monad in Scala: a container wrapping success (Success(value)) or failure (Failure(exception)). This allows chaining operations via flatMap and map, propagating errors implicitly.

Transforming the balance app: wrap account retrieval in Try, use for-comprehensions (sugaring flatMap/map) for composition. If any step fails, the whole computation fails gracefully, without explicit exception handling.

Code evolves from imperative checks to declarative chains:

val total = for {
  account1 <- Try(getAccount(bank1))
  account2 <- Try(getAccount(bank2))
  balance1 <- Try(getBalance(account1))
  balance2 <- Try(getBalance(account2))
} yield balance1 + balance2

This yields Try[Double], inspectable via isSuccess, get, or getOrElse. Monads here abstract error propagation, enhancing modularity.

Java 8’s Optional partially mirrors this but lacks full monadic power; Sarradin implements a custom Try for illustration, using abstract classes with Success/Failure subclasses.

Extending to Asynchrony: Futures for Non-Blocking Computations

Asynchrony poses similar issues: callbacks or blocking awaits disrupt flow. Scala’s Future monad encapsulates eventual values, enabling composition without blocking.

In the app, wrap async calls in Future: use flatMap to chain, ensuring non-blocking execution. For-comprehensions again simplify:

val totalFuture = for {
  account1 <- Future(getAccountAsync(bank1))
  account2 <- Future(getAccountAsync(bank2))
  balance1 <- Future(getBalanceAsync(account1))
  balance2 <- Future(getBalanceAsync(account2))
} yield balance1 + balance2

totalFuture completes asynchronously; callbacks via onComplete handle results. This maintains sequential appearance while parallelizing under the hood.

Sarradin contrasts with Java 8’s CompletableFuture, which offers thenApply/thenCompose for similar chaining, though less idiomatic without for-comprehensions.

Monads as a Unifying Abstraction: Synthesis and Implications

Monads generalize: a type M[A] with map (transform value) and flatMap (chain computations). They inject contexts (error, future) into pure functions, separating concerns.

In the app, combining Try and Future (via Scalaz’s EitherT or custom) handles both errors and asynchrony. This AOP-like injection leverages type systems for safety, contrasting annotation-based AOP.

Java 8 approximates with lambdas and CompletableFuture/Optional, but lacks Scala’s expressiveness. Custom implementations reveal monads’ essence: abstract class with map/flatMap, subclasses for Success/Failure.

Sarradin concludes monads enhance composability, reducing boilerplate for robust, maintainable code in functional paradigms.

Relevant Links and Hashtags

Links:

PostHeaderIcon [DevoxxFR2013] Objects and Functions: Conflict Without a Cause?

Lecturer

Martin Odersky is a professor at EPFL in Lausanne, Switzerland, specializing in programming languages that blend object-oriented and functional paradigms. His research unifies these approaches, evidenced by designs like Pizza, GJ, and Functional Nets. He co-designed Java generics and authored the original javac compiler. Currently, he focuses on Scala, fusing functional and object-oriented programming while ensuring interoperability with Java and .NET.

Abstract

Martin Odersky’s lecture traces object-oriented programming’s (OOP) rise, parallels it with functional programming’s (FP) resurgence, and argues for their synthesis. Analyzing historical catalysts, methodological benefits, and modern hardware demands, he demonstrates how FP addresses parallelism and reactivity challenges. Through Scala examples, Odersky shows OOP and FP as complementary, enhancing modularity and abstraction without mutual exclusion.

Historical Roots and Catalysts for OOP Adoption

Odersky recounts his journey from Pascal compilers to modular languages, Java involvement, and Scala creation. OOP’s mainstreaming, he argues, stemmed not from encapsulation or reuse but practical necessities. Simula (1967) for simulations and Smalltalk (late 1970s) for GUI widgets inverted traditional data structures: fixed operations, unbounded implementations.

In procedural languages like C, this was cumbersome via function pointers; OOP simplified dynamic binding for unknown implementations. Odersky notes early confusion with Smalltalk, mirroring current FP bewilderment. OOP’s advantages – modeling, dependency inversion – emerged post-adoption, sparked by widget programming appeal.

Functional Programming’s Resurgence and Methodological Strengths

FP offers fewer errors, superior modularity, and productivity via higher abstractions and shorter code. Yet, despite 50-year existence, mainstream adoption lagged. Odersky identifies multicore and cloud computing as catalysts: parallelism for hardware utilization, reactivity for asynchronous events, distribution for delays/failures.

Mutable state exacerbates issues like cache coherence and non-determinism in concurrent environments. Immutable data mitigates races, enabling safe caching. Locks/threads scale poorly; even transactions retain problems. FP’s immutability fosters determinism, crucial for scalable systems.

Addressing Modern Computing Challenges with FP

Odersky outlines a triple challenge: parallel, reactive, distributed programming. Mutable state hinders each; FP excels by avoiding it.

For parallelism, he exemplifies mapping developer names: sequential in Scala, parallel via .par, yielding a parallel collection. Side effects risk chaos due to reordered executions, necessitating functional purity for correctness.

Reactivity example: an online store querying users, orders, products, stock. Synchronous calls block threads on slow services, degrading performance. Asynchronous futures prevent blocking; Scala’s for-comprehensions compose them elegantly, hiding complexity. Refactoring for parallelism pairs futures, executing concurrently.

For-comprehensions translate universally to map, flatMap, filter, allowing library-defined interpretations – sequential or async – without polluting domain logic.

Synthesizing OOP and FP: Beyond False Dichotomies

Communities often view OOP and FP oppositely, but Odersky argues orthogonality. Objects modularize (“what goes where”), providing containers with dynamic binding and inheritance. Essential for large codebases (e.g., million-line Scala systems), they prevent global namespace chaos – a Haskell limitation.

Redefine objects: eliminate mutable state dogma (e.g., immutable java.lang.String), structural equality over identity, focus on behavior. Scala embodies this fusion, modeling algebraic types with objects while importing FP capabilities.

Scala unifies scripting (winning JavaOne Script Bowl) and safe, performant systems (core for Twitter, LinkedIn). Odersky concludes OOP/FP synergy enhances development, urging exploration via Scala Days, courses, and talks.

Relevant Links and Hashtags

Links:

PostHeaderIcon [DevoxxBE2012] First Steps with Scala (Part 1/2)

In an engaging session, Dick Wall and Bill Venners, co-founders of Escalate Software and prominent figures in the Scala community, introduced newcomers to the Scala programming language. Dick, known for his JavaPosse involvement, and Bill, president of Artima and author of key Java texts, adapted their training curriculum to cover foundational elements. Their approach fused object-oriented and functional paradigms, emphasizing Scala’s blend of familiarity and innovation.

They commenced with the Scala REPL, a tool they use daily for experimentation. This interactive shell allows immediate code execution, inferring types and storing results for reuse, making it invaluable even for Java developers exploring libraries.

Dick and Holly—wait, Dick and Bill—highlighted Scala’s strong typing with inference, reducing boilerplate while maintaining safety. They demonstrated basic operations, showing how everything integrates into a unified hierarchy, unlike Java’s primitives and references.

Defining Variables and Immutability

Transitioning to variables, Dick and Bill distinguished between vals (immutable) and vars (mutable), promoting vals for reliability. This design choice encourages constant use without extra syntax, contrasting Java’s final keyword. They illustrated reassignment errors, noting REPL’s scoping allows redefinitions, mimicking nested blocks.

Type specifications, optional due to inference, follow names with colons, inverting Java’s order for natural flow. Examples showed string inferences and explicit declarations, underscoring flexibility.

They addressed mutability choices, advising private volatile vars for necessary changes, or mutable objects within immutable structures, depending on context.

Control Structures and Expressions

Dick and Bill explored control structures, revealing Scala’s expression-oriented nature. If statements return values, enabling concise assignments without ternaries. While loops, though imperative, yield Unit, encouraging functional alternatives.

For comprehensions, powerful for iteration, support guards and yields, transforming collections declaratively. They demonstrated filtering even numbers or yielding transformed lists, highlighting pattern matching integration.

Try-catch blocks, also expressions, handle exceptions functionally, with finally clauses for cleanup. This uniformity simplifies code, treating controls as value producers.

Functions and Closures

Delving into functions, they defined them as objects, enabling higher-order usage. Simple defs showed parameter typing and inference, with return types often omitted.

Function literals, akin to lambdas, capture environments as closures, allowing deferred execution. Examples illustrated anonymous functions for mapping or filtering, emphasizing Scala’s functional leanings.

They introduced by-name parameters for lazy evaluation, useful in custom controls like loops, mimicking built-in syntax without special privileges.

Collections and Functional Programming

Scala collections, immutable by default, support transformations via methods like map and filter. Dick and Bill showcased creating lists, accessing elements, and applying operations, yielding new collections without mutation.

They contrasted mutable variants, advising caution for concurrency. For comprehensions over collections generate new ones, combining iteration with functional purity.

Approaching functional style, they encouraged avoiding side effects, using recursion or folds for aggregations, fostering predictable code.

Advanced Basics and Q&A Insights

In Q&A, they addressed optimizations: Scala uses primitives internally, with @specialized for generics avoiding boxing. Profiling mirrors Java tools, with quirks in coverage.

Dick and Bill wrapped by previewing afternoon labs on Scala Koans, urging practice. Their session laid a solid groundwork, blending theory with practical demos, preparing attendees for Scala’s expressive power.

Links: