Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The broader idea of “pass a value between functions without naming it in the caller” crops up in a few other places outside FP.

In Rust there is the “builder pattern”[0] where the builder isn’t mentioned directly:

    ByValueBuilder::new()
        .with_favorite_number(42)
        .with_favorite_programming_language("Rust")
        .build()
In OO land they are called “fluent interfaces”[1], commonly used when building SQL queries while only mentioning the final query at the end:

    query = translations
 .Where(t => t.Key.Contains("a"))
 .OrderBy(t => t.Value.Length)
 .Select(t => t.Value.ToUpper());
Especially in the query builder example, since it is essentially building up an AST, the type of the top-level object can change in each call, but since it isn’t named it also doesn’t need to be typed, so there’s no issue with variable shadowing etc.

[0] https://blog.logrocket.com/build-rust-api-builder-pattern/ [1] https://en.m.wikipedia.org/wiki/Fluent_interface



The framing of the builder pattern as primarily a Rust feature, and fluent interfaces as primarily an OO feature, is a bit odd.

A prime example of non-builder fluent interfaces are containers in Rust.

Both builders and fluent interfaces exist pretty much in all languages that can support chaining methods on some sort of object. This includes OO languages as well as totally-not-OO languages like Rust that just stop short of calling their classes "classes."


The builder pattern [0] is orthogonal to fluent interfaces. It has merely become customary for builders to have a fluent interface. The defining feature of the builder pattern is that you don’t set configurable properties on an object itself, but that you use a separate object (the builder) to set the properties on, and then have it build the final object (on which the respective properties are then usually immutable). It’s immaterial whether the builder object has a fluent interface or not. The important thing is that the builder interface is separated from the resulting object’s interface.

[0] https://en.wikipedia.org/wiki/Builder_pattern

Both builders and fluent interfaces have little to do with point-free style. X.foo().bar().baz() is not any more point-free than baz(bar(foo(x))).


Just to add a bit of clarity: GP's second example isn't a builder pattern, because it's missing the actual build step. Builder patterns use method chaining to configure an object, but the final result is an object of a different class, something that doesn't have those initial methods but instead lets you use the result of what was built up. Java's StringBuilder is a classic example, which exists to avoid the O(n^2) of concat'ing multiple values sequentially, after which you use .toString() to return the actual String object built up. GP's first example is one where the builder pattern lets you name constructor arguments, and during the final build it would throw an exception if you have an incompatible combination.

Whether GP's second example counts as a fluent interface is a bit iffy just because of SQL keywords and how it works in general, but possibly a good way to think of fluent interfaces is madlibs: "Find a ___(noun) that is ___(adjective)". Instead of creating a function with complicated arguments like "find(noun, adjective)" or "find(Noun(n, adjective))", you'd mimic the sentence structure with something along the lines of "collection.find(noun).thatIs(adjective)" - the chained methods interact with each other to flexibly specify complicated arguments. The ".thatIs()" could for example be completely omitted or specified multiple times to further restrict what "noun" to return. The query builder is iffy because while it looks like one on the surface, it's actually plain method chaining where each call modifies and returns the original object without the context that's passed to the next call in a fluent interface.

Method chaining is the simple syntactic pattern that enables both of these other patterns. An umbrella term they both fall under.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: