-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fs: Accept a function as an options container. #1998
Conversation
TL;DRLGTM my opinionWe should consider what API is really useful. If function call is not satisfied the required condition, we need to raise an alert like For example, if an user wants to use So, I think this current API is correct. ideal solutionWhen I was in the similar situation, I research the usage and consider what is correct and really useful API, then I sent the PR #1412 . Of course, I could revert the PR #635 . The PR has my decision:
If some users really want to use callback function in realisticOf course, the above opinion and solution is ideal. I don't think this is pretty good idea. |
@yosuke-furukawa, What do you think about a falsy second argument? |
I think that if some people are misusing |
(responding to @yosuke-furukawa, I am not against the changes in this PR) |
I'm -1 on adding proper errbacks support here. |
If we got any issues about a falsy second argument, we should fix that. But currently, we have not got the report. So we don't need to fix
Yes, I agree. I guess a few developers are just misunderstanding the |
Don't think that is a good idea to passing function as second argument. It would be good to update docs for fs.createWriteStream and fs.createReadStream and show deprecation message if somebody passing function to arguments. |
Ah, @bnoordhuis for the #1981. And do not get the idea wrong, I am +0 for both this PR and #1982 myself. I also think that the main issue in on the modules side misusing the API in an undocumented way. But the fact here is that the behaviour was broken in a minor release, and this is close to breaking TL;DR: I am not the one to advocate for these kind of «fixes» and it would be perfectly fine by me if both of the PRs are rejected. I'm just trying to make it easier to come up with a solution. |
@ChALkeR |
Ok, as no one (including myself) seems to actually support the idea of handling this (wrong API usage by modules) on the io.js side, I closed these PRs (both #1982 and #1998). |
The docs state that I'm +1 on this, not because of buggy modules, but for consistency. |
@seishun Yes, we can do this, but this callback will do nothing further as the most of fs method do. So, one possible way to wrap up passed function around with |
Functions are not objects, and using them as option bags could be confusing like hell. fs.readFileSync('/etc/passwd', function hey_i_am_an_option_object(err, data) {
console.log(data)
}) This kind of thing is explicitly forbidden in other places, so we should forbid it in If you do want to use a function as an option bag, just create an object out of it using |
Yes they are.
Confusing to whom? No one is forcing you to write code like this.
|
Imo, for consistency, in an ideal case, functions should not be treated as option bags.
The only reason that would justify that would be backwards compatibility with a noticable amount of valid code. But to the moment I found only two modules, and in both cases it was an error on the module side (that code didn't do anything sensible). One of those modules is already fixed, the second one has an open PR to fix that. |
That statement only means that Function prototype chain ends with Object, which is irrelevant here. And as far as The issue here is that it is impossible to distinguish a function used as a callback and a function used as an option bag. This is why mixing them up is a bad idea. |
I don't see the problem, it just needs a special case for two arguments: if the second argument is a function, assume
No, it doesn't. "Object type" has nothing to do with prototype chains.
It's only an issue when there is ambiguity. I've addressed this in my response to @ChALkeR. |
@seishun Please share a valid usecase for the «feature» of using functions as option bags when calling some io.js API method. From what I have seen, 100% of such cases were bugs in users code. |
I'll quote myself, I don't see why anyone would want to do this, but neither why it shouldn't be allowed. Either way, if it's disallowed, then the docs must be fixed. Writing "an object that isn't a function" in every function that accepts an options object would be wordy and seem like an arbitrary restriction. |
I can not imagine it to myself how to use functions as option bags, it shouldn't be allowed at all. If somebody wants to use functions as callback it may be possible to add this feature. |
If we do whatever you're suggesting we do, we'll end up with: var options1 = { flag: 'r' };
var options2 = function(){};
options2.flag = 'w+';
fs.writeFileSync('/etc/passwd', options1); // this works
fs.writeFile('/etc/passwd', options1); // this works
fs.writeFileSync('/etc/passwd', options2); // this works
fs.writeFile('/etc/passwd', options2); // this doesn't since user "obviously" meant to pass options Do you see the issue with it?
Hmm... I stand corrected, there is an "object type" in es5 spec. But the spec uses different language than io.js does. What es5 spec calls "object type", io.js calls "non-primitive type". And "objects" are simply defined as "every non-primitive, And this kind of a language is so commonly used, so adding "hey functions aren't considered objects" disclaimer is hardly worth it. And one would unlikely use function as an options object deliberately anyway (hey, all cases we found are bugs).
I wonder what do you think |
Yes.
And I think it's a problem that io.js is perpetuating a misconception.
That was a bug. Since it couldn't be fixed without potentially breaking code, there is now a discussion to deprecate these methods altogether. As a temporary solution, the docs for
It returns a string determined by the type, with a special case for objects, as defined here. It's not the same as returning the type. The way it treats |
OK, I will write some notices in our API doc. |
Is there anyone who tries in the real code to pass a function as an options object? 'cause all two cases we found so far are people trying to pass a callback to a function that doesn't accept any. And it doesn't warrant a notice. |
I guess not so many (maybe zero). But it is not zero percent that users misunderstand that Especially, So I will send a PR to add a notice in |
I used to be of the opinion that any js type that could have properties set on it should be allowed as an options "object". Why restrict the user? You can set properties on functions and strings in js, so why should we tell people not to? Doing so is just a feature of the language, if you don't like it, use another language! I've come around to agreeing with @rlidwka: its confusing, usually a bug, and in the case of the node APIs, which have a lot of optional intermediate arguments that we have to disambiguate based on type (edit: and functions that behave differently based on type, like This, for example, is just plain weird:
Clearly a bug, I'd say, and yet listen is done on an ephemeral port :-( /cc @chrisdickinson, because I mentioned docs |
We already closed this PR, we should not discuss on the closed PR. |
Hi. Sorry, I've been traveling and unable to check the tracker as often as needed. Passing a function to fs.createXStream should not throw a TypeError in this version of io.js. If we want to make it do that in the future, that's a different proposition. for the time being folks having working code written against the idea that these methods take callbacks. That code takes precedence over our desire to "teach" them our API — we should not have broken it in the first place. Most of the arguments here deal with the inconsistency of supporting a function as a property bag. The issue is that that is how they were dealt with before, and we're restoring that behavior before going through a deprecation path (or adding an API for err-backs). With that in mind, I'd like to re-open this PR.
|
@chrisdickinson Reopened. |
We should follow the old version, and plan to add a deprecation notice for false-y options in v3 (to be removed in v4 if the change doesn't break everything).
|
We should raise this issue to |
The regression has been around for a month now, perhaps it should be for quick resolution. I'm still in the pot of allowing it with a deprecation message, because upstream users use these modules and shouldn't be responsible for small bugs like this - it was not in a semver-major release and upstream users shouldn't have to worry about this in semver-minor releases. |
Make that two months. I would be ok doing it with a deprecation message, if anyone feels strongly about this. :s Re-open after updated if so. |
This is alternate to #1982
This should fix a breaking change in commit 353e26e, that was included in a minor version of io.js and broke at least two modules (that were misusing
fs.createWriteStream
method, but still).Those two modules were passing a function to
fs.createWriteStream
, and that was never supported (it was always ignored). In 2.3.0 a more strict options validation was introduced, it started throwing anError
, and at least those two modules were broken.This patch uses a simple way to get around that, treating a
function
as a valid options container.Apart from
function
s, 353e26e changed the behaviour on falsy variables (null
and0
started causing anError
), and that is not addressed in this PR. I could fix that, replacing theoptions === undefined
with a!options
check (that would involve changing the expectations of several tests). What do you think?@yosuke-furukawa, @chrisdickinson
Fixes: #1981