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

Claus Reinke claus.reinke at
Thu Jun 23 06:37:34 PDT 2011

>> 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. ..
> Hi Claus, interesting idea. Given
> The idea of {x: a, y: b, ...: c} – record extension and row
> capture<>
>> 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.

Hi Mark,

thanks for the pointer.

Yes, there used to be a large body of literature just on the various
ways of factoring a record operations API, mostly driven by their
use for semantics of object-oriented language variations and by
their type system difficulties ('record calculi', 'semantics of
inheritance/oo', 'typing record concatenation', ..).

Record/object extension is one of the recurring ideas, and since
it is based on record/object literals + a base record/object, most
of the design choices follow from the extended object literals.

My immediate concern is simply: given the choices already made
for Javascript object operations, why don't we have a complete set
of operations for both in-place and copying updates? The current
situation at the object level is as if JS only had '+=' and '-=', but
not '+' and '-', at the level of numbers.

As for the set of operations, JS has already chosen that updating
a non-existing property extends the object, so update and extension
are mixed in one operation. There is a separate operation for removing
properties and there are tests for the existence of properties, both
locally and in the prototype chain. If there were functional equivalents
to the imperative base operations

    obj.prop = value;
    delete obj.prop;

then one could build more complex operations from there, instead
of from scratch. delete already returns the object, but assignment
returns the value, and overloading delete to produce an object copy
if the input object is frozen would be confusing, so we need new
syntax, and object extension with extended object literals could do.

Assuming that the extended object is copied as is, modified as
specifiable by the extended object literal syntax, I'd assume

    { prop : value; ...: obj }

to be a (shallow) copy of obj, identical (including prototype and
meta properties such as frozen/configurable/..) in all but prop.

If I don't want to copy prototype or meta-properties, I'd need
to use records instead of objects, or get some help from the
extended object literal syntax.

But one shouldn't try to fit everything into the object literal
syntax, either - once it is accepted that copying objects is useful,
there could be an Object.filter operation, eg, to filter out
properties based on their meta-properties (enumerable, own, ..):


would return a (shallow) copy of obj with properties filtered
according to some predicate function.

To avoid an additional operator for functional delete, one might
add a delete directive to extended object literal syntax, and have

    { delete prop; ...: obj}

be a (shallow) copy of obj, identical in all but prop.

Wouldn't that be sufficient as a baseline? If not, what is missing?

Is extended object literal syntax capable of handling this slightly
extended range of use? Btw, should there be a way to un-freeze
object copies (typical application is to make a non-frozen copy
of a frozen array, update it incrementally and in-place in a loop,
then freeze the resulting array copy for further use)?

In sum, copying object modifications are useful for programmers,
and taking them into consideration might ease the constraints
for ES language design (not everything has to fit into the simple
in-place update all-permitted-or-all forbidden scheme - copying
updates offer a third option).


>> 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
> -- 
>    Cheers,
>    --MarkM


More information about the es-discuss mailing list