Skip to content
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

Return null when passed a non-function argument #20

Merged
merged 1 commit into from
Jan 17, 2017
Merged

Return null when passed a non-function argument #20

merged 1 commit into from
Jan 17, 2017

Conversation

lucasfcosta
Copy link
Member

This PR aims to solve the issue described at chaijs/chai#893.

I just added a simple instanceof check to the main function in this module in order to detect when something that is not an instance of a function is passed. When that happens we return null.

Also, this should be enough to cover all cases since the @@hasInstance symbol needs to be implemented on the "father" functions in order for it to recognize other instances as their children, so if anyone implemented @@hasInstance on the Function constructor they really expect whatever that symbol returns to be the final verdict whether something should be considered a function or not and therefore we shall not worry about those cases.

I also added tests for that and updated the docs.

I will also submit a PR to the main repo later.

var match = toString.call(aFunc).match(functionNameMatch);
if (match) {
name = match[1];
var isFunction = aFunc instanceof Function;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather typeof aFunc == 'function'. Function#toString expects an object to have some internal methods only functions have, typeof is the most accurate way to check for them.

Current solution will throw on edge cases like { __proto__: function() {} }.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, even typeof == 'function' does not guarantee Function#toString won't throw. typeof == 'function' checks for [[Call]], but Function#toString requires [[ECMAScriptCode]]. let proxy = new Proxy(() => {}, {}) sets [[Call]], but not [[ECMAScriptCode]], so proxied functions does not work with toString.

if (match) {
name = match[1];
var isFunction = aFunc instanceof Function;
if (isFunction) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should early return for non-functions? Like if (typeof aFunc != 'function') return null. Otherwise nesting is rather deep.

@lucasfcosta
Copy link
Member Author

I have just updated this.

@shvaikalesh
Copy link

shvaikalesh commented Jan 11, 2017

Thanks for going forward on the instanceOf issue, @lucasfcosta.

I have a feeling that get-func-name should return undefined instead of null.

get-func-name essentially returns name property. When property is missing, internal [[Get]] returns undefined. Maybe we should too? null is used (in DOM API, and in Object.getPrototypeOf, for example) to highlight an absence of Object type.

@lucasfcosta
Copy link
Member Author

@shvaikalesh hmmm, I'm not sure about that change.

Thanks for your feedback, I'm not strongly against it, but I feel like using undefined may give the impression that this went unhandled. Returning null is like saying "Hey, we've done something but there's no result", while returning undefined feels like "maybe we did something, maybe we just didn't notice this".

@meeber
Copy link

meeber commented Jan 11, 2017

LGTM. I also prefer null over undefined due to the ambiguity of undefined in the language. I think it's okay for us to deviate in our function from the behavior of the engine when returning a missing property.

@shvaikalesh
Copy link

OK then, I have no strong opinion on this. LGTM.

@@ -22,6 +23,10 @@ var toString = Function.prototype.toString;
var functionNameMatch = /\s*function(?:\s|\s*\/\*[^(?:*\/)]+\*\/\s*)*([^\s\(\/]+)/;
function getFuncName(aFunc) {
var name = '';
if (typeof aFunc !== 'function') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just nitpicking, but we could avoid unnecessary initializations of name here:

var name;
if (typeof aFunc !== 'function') {
  return null;
}

name = '';

or

if (typeof aFunc !== 'function') {
  return null;
}

var name = '';

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any byte counts.
Thanks!

Copy link

@meeber meeber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RIP

Err... I mean, LGTM!

Copy link
Member

@vieiralucas vieiralucas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@lucasfcosta
Copy link
Member Author

Thanks for your approval, friends :)

@lucasfcosta lucasfcosta merged commit 17268c0 into chaijs:master Jan 17, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants