q-io/fs methods don't accept Reader/Writer objects

145 views
Skip to first unread message

Wout Mertens

unread,
Jun 25, 2013, 8:54:43 AM6/25/13
to q-con...@googlegroups.com
The readme says that q-io/fs is a "File system API for Q promises with method signatures patterned after CommonJS/Fileystem/A but returning promises and promise streams."

Therefore I would expect to be able to do things like FS.write(path, HTTP.read(url)). If the http read succeeds its promise resolves to a FS.Reader which the write() could consume and fulfill its promise when done. If the http read fails it will return a rejection which the fs writer will then pass on without writing anything.

However, that doesn't work, write only accepts Buffers or Strings as content.

Is this a conscious decision or an oversight?

Cheers,

Wout.

Jason Crawford

unread,
Jun 25, 2013, 12:21:50 PM6/25/13
to q-con...@googlegroups.com
I can't speak for the designers of the library, but here are my thoughts.

Yes, it would be nice to do FS.write(path, HTTP.read(url)). But presumably you also want FS.write(path, content) to work, where content is a regular buffer instead of a promise. How do you handle that? If every function has to deal with all its arguments being either promises or not, there would be an explosion in complexity.

Alternatively, you could have two methods, like FS.write(path, content) and FS.writePromise(path, promiseOfContent). But then you have a different explosion in complexity, with tons of methods in the interface.

All this gets worse when you think that maybe path will be a promise as well. Now you have 4 cases that FS.write has to handle, and you have 2^n cases for any function that takes n arguments. And what if you're handed, not a promise of content, but a promise of a promise of content?

So instead of all of the above, we standardize: all methods take non-promises as arguments; methods that do I/O output promises as return values. This lets us chain these methods together using then in a consistent way, and all the tools in our toolbox are composable.

For more on the theory underlying promises, I recommend these articles by James Coglan:


Also this article and talk by Domenic Denicola, a contributor to Q:


Hope that helps,
Jason

--
Blog: http://blog.jasoncrawford.org  |  Twitter: @jasoncrawford



--
You received this message because you are subscribed to the Google Groups "Q Continuum (JavaScript)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to q-continuum...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Domenic Denicola

unread,
Jun 25, 2013, 12:38:09 PM6/25/13
to q-con...@googlegroups.com
Actually, it's pretty easy to create methods that accept both promises and non-promise values. Just use `Q.promised`:

https://github.com/kriskowal/q/wiki/API-Reference#qpromisedfunc

Thus you could do

```js
var writeFile = Q.promised(qfs.writeFile);

writeFile(path, HTTP.read(url));
```

As to why q-fs doesn't do this by default, that's a question I'll leave for Kris :).

Wout Mertens

unread,
Jun 25, 2013, 2:05:42 PM6/25/13
to q-con...@googlegroups.com
Right. Basically, I think it would be really nice to have all methods that accept string/buffer to also accept Readers (and Node streams?) as well as promises for all.

HTTP.request('http://somesite.com').then(function(response){FS.open("dump.html","w").then(function(writer){response.body.forEach(writer.write);})});

could then be written as FS.write("dump.html", HTTP.read('http://somesite.com'))

(although HTTP.read returns the completed body instead of a Reader for the body, but that's a different story)

Wout.
> --
> You received this message because you are subscribed to a topic in the Google Groups "Q Continuum (JavaScript)" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/q-continuum/OnleeBaD3r8/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to q-continuum...@googlegroups.com.

Wout Mertens

unread,
Jul 1, 2013, 7:31:03 AM7/1/13
to q-con...@googlegroups.com
On Tuesday, June 25, 2013 6:38:09 PM UTC+2, Domenic Denicola wrote:
Actually, it's pretty easy to create methods that accept both promises and non-promise values. Just use `Q.promised`:

https://github.com/kriskowal/q/wiki/API-Reference#qpromisedfunc

Thus you could do

```js
var writeFile = Q.promised(qfs.writeFile);

writeFile(path, HTTP.read(url));
```

I just re-read this and last time I glossed over it thinking you were just referring to wrapping the individual arguments as Q(arg) (I was in a hurry). Now I realize you're talking about something I didn't know existed, thanks!

Q.promised(fn) handles all arguments, which is really cool!
 

As to why q-fs doesn't do this by default, that's a question I'll leave for Kris :).

I'll use the Q.promised() versions for now and keep my fingers crossed for the future. It would be great if the file functions would take streams as well, so that you don't need to buffer potentially gigabytes of data in memory.

Wout.
Reply all
Reply to author
Forward
0 new messages