All the streams in core are in some half state between declarative and 
composable.

http.ServerResponse is probably the biggest/worst example where:

http.writeHead(status, headers)

can, in some cases, entirely opt out of the composable headers set:

http.setHeader(name, value)

in particular, this happens when you pass an array of tuples as the headers 
argument to writeHead.

Then there is http.ClientRequest, which is not composable at all and has no 
setHeader() method.

I have a similar problem with every stream in core except sockets. All of the 
streams in core take, at some point, a set of parameters that set a bunch of 
internal state and *start* an IO operation. Until that IO operation hits a 
particular event, in the future, none of that internal state is actually used. 
Some of that state can be mutated (is composable), some currently isn't (is not 
composable), and some of it is mutable if you access internal properties 
(ewwww).

If the goal of core is to reach API stability we need to get core to a place 
where it's extensible. There is a similar thread to this effect about exposing 
core constructors, but I'd like to stay on track in this thread and just talk 
about composability because it doesn't have many of the same concerns people 
have about exposing core constructors.

*Most* of the objects in core are accessed by userland as the subject of an 
event. When those objects are not composable we incredibly limit the 
extensibility of core, even when we expose the constructors, and it leads to 
the worst kind of monkey patching. There are even cases where core objects that 
get exposed by libraries have certain methods entirely removed because they 
break composability (I know TJ was considering removing writeHead when exposed 
by Express).

A few things would need to happen to make core more composable.

1) Internal state needs to become external state.
and
2) The removal, or "re-integration", of methods that currently break 
composability.

We may also need to add more events to some objects. Some good examples, which 
have been added, are the 'open' and 'socket' methods on 
fs.ReadStream/fs.WriteStream and http.ServerResponse.

Anywhere we can expose internal state publicly we increase composability 
because we allow new mutations that depend on that state the way internal logic 
depends on it. As we do this we'll also realize more places where we break that 
mutability.

Thoughts?

Reply via email to