imperative vs functional APIs or: how to work with constant objects?

Mark S. Miller erights at
Tue Jun 21 11:11:05 PDT 2011

On Tue, Jun 21, 2011 at 9:47 AM, Claus Reinke <claus.reinke at>wrote:

> Javascript data structure operations: some of the APIs are imperative, some
> are functional, some are mixed. Having functional equivalents
> to all imperative data structure operations is necessary to support
> expression-oriented programming over constant data structures.
> "imperative" here refers to operations that are designed to be used as
> statements, changing inputs by side-effect, while "functional" refers to
> operations designed to be used as expressions, leaving their inputs
> unchanged. A familiar example is the Array API, e.g.:
>   array.concat([1])    - returns a modified copy of array, expression
>   array.push(1)        - modifies array in place, "statement"
> It does seem as if older API elements tend to be imperative while newer
> ones tend to be functional. However, not all imperative
> operations have functional counterparts yet, and with increasing
> focus on constant and frozen objects, the need for functional
> operations is going to increase.
> In particular, I have been wondering about how freezing objects
> curtails what I am able to do with them. Having worked with pure
> functional language for a long time, I really like the advantages of
> frozen/constant objects, both for avoiding bugs and to enable
> optimizations, but I'm not used to not having a full set of operations to
> work with such objects:
> Example 1: constant functions, prototypes and toString
>   The standard API for functions requires imperative operations
>   for both prototypical inheritance and for string representation.
>   const C() {}
>   // C.prototype.toString = function() { return 'C()' }
>   // C.toString = function() { return 'C()' }
> Example 2: property update
>   The standard API for object property update is imperative.
>   const obj = Object.freeze({ age : 1, .. });
>   const older_obj = // a modified copy of obj, with age : 2??

 Hi Claus, interesting idea. Given

 The idea of {x: a, y: b, ...: c} – record extension and row
for structuring and destructuring comes to mind, but ES objects are a
different animal compared to ML records. For example, which properties of c are
copied into the object being initialized by {x: a, y: b, ...: c}?
enumerable? own? etc.

(from <>)

you could say

    const older_obj = { age: 2, ...: obj };

But as the note says, there are a bunch of open questions that need to be
settled before this becomes a serious candidate. We should examine how this
interacts with other aspects of extended object literals.

> The standard APIs for these fundamental operations are imperative
> and so are not available on frozen objects (this also applies to the
> record strawman, for instance).
> How does one achieve the effects of these operations on frozen
> objects, by creating modified copies? For an expression-oriented style of
> programming where no object is ever modified in place, it seems one has to
> use a lower level API, perhaps by calling
> Object.create and Object.freeze to implement some form of
> Object.clone, then mixing in the update on the clone before freezing it. Or
> perhaps using proxies to achieve the effect..
> The situation is somewhat similar to the declarative object initializers
> being worked on as object literal extensions, but those don't seem to help
> here.
> What is the best way of doing functional/declarative/**expression-
> oriented object modification in ES5 or ES/next? Is there really an
> imperative-preferred flaw in the current design?
> Claus
> ______________________________**_________________
> es-discuss mailing list
> es-discuss at

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list