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

Rigorously define equals method on Term and Quad #142

Merged
merged 3 commits into from
Mar 5, 2019
Merged

Conversation

RubenVerborgh
Copy link
Member

Closes #133.

elf-pavlik
elf-pavlik previously approved these changes Jan 21, 2019
Copy link
Member

@elf-pavlik elf-pavlik left a comment

Choose a reason for hiding this comment

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

👍

Copy link
Member

@rubensworks rubensworks left a comment

Choose a reason for hiding this comment

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

Looks good to me. Just two minor comments.

interface-spec.html Outdated Show resolved Hide resolved
interface-spec.html Outdated Show resolved Hide resolved
interface-spec.html Outdated Show resolved Hide resolved
Copy link
Contributor

@blake-regalia blake-regalia left a comment

Choose a reason for hiding this comment

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

See comments

@RubenVerborgh
Copy link
Member Author

RubenVerborgh commented Jan 22, 2019 via email

@blake-regalia
Copy link
Contributor

Yes, but isn't the idea to always return true or false and not throw an error? What if i pass a term to quad constructor such that quad.term.equals === null? We need to test at runtime that .equals is a function for each component of quad; and that this is another consequence of #132 / #133

@RubenVerborgh
Copy link
Member Author

RubenVerborgh commented Jan 22, 2019 via email

@RubenVerborgh
Copy link
Member Author

All of the above comments have been addressed; please re-review as necessary.

Copy link
Member

@bergos bergos left a comment

Choose a reason for hiding this comment

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

+1 for the text, just some small Respec stuff. The comments should be valid for all added id attributes and links.

interface-spec.html Outdated Show resolved Hide resolved
interface-spec.html Outdated Show resolved Hide resolved
interface-spec.html Outdated Show resolved Hide resolved
@blake-regalia
Copy link
Contributor

blake-regalia commented Jan 22, 2019

There is still an outstanding edge case that is not covered by the algorithm which I brought up in my last comment; namely that .equals needs to be tested for or the constructor explicitly needs to convert terms or disallow writing to component properties otherwise what happens when:

factory.quad({
	termType: 'NamedNode',
	value: 'http://ex.org/s',
}, {
	termType: 'NamedNode',
	value: 'http://ex.org/p',
}, {
	termType: 'NamedNode',
	value: 'http://ex.org/o',
}, {
	termType: 'NamedNode',
	value: 'http://ex.org/g',
}).equals(other);

might throw: Uncaught TypeError: {...}.equals is not a function

@RubenVerborgh
Copy link
Member Author

@blake-regalia We are assuming now that they are valid Terms; I can state that assumption somewhere explicitly, but I'd prefer to keep it. Too complex and expensive otherwise.

Also see #137.

@RubenVerborgh
Copy link
Member Author

@bergos' comments processed, pending @blake-regalia response.

@blake-regalia
Copy link
Contributor

We are assuming now that they are valid Terms;
Too complex and expensive otherwise.

@RubenVerborgh By your own logic, iff we are assuming they are valid Terms then we don't need to test for null or undefined! Where is the consistency in that?

@RubenVerborgh
Copy link
Member Author

Null pointer exceptions are a common source of errors, I expect several magnitudes more common than malformed Term exceptions.

@blake-regalia
Copy link
Contributor

Null pointer exceptions are a common source of errors

Agreed - and I still think it would be nice to let devs know that the variable they passed to equals is actually null ;) because who does that intentionally?

I expect several magnitudes more common than malformed Term exceptions.

Well we are not just going for a majority of cases, it needs to be well-defined, consistent and fully-covered.

@RubenVerborgh
Copy link
Member Author

Alright, not disagreeing, but I don't have more bandwidth to follow up on this. Re-assigning to @bergos and @blake-regalia, feel free to conclude in the way you think is most appropriate.

@elf-pavlik
Copy link
Member

I think this relates to #104 (Nuance "plain objects (JSON) cannot be used) since @blake-regalia just used such 'plain objects' to make his case.

@vhf
Copy link
Member

vhf commented Jan 24, 2019

I added a commit for the first part of the later comments: making .equals parameter optional and nullable.

Removed commit `.equals parameters are optional and nullable`
diff --git a/interface-spec.html b/interface-spec.html
index f0f7b01..5f4cc36 100644
--- a/interface-spec.html
+++ b/interface-spec.html
@@ -129,7 +129,7 @@
     interface Term {
       attribute string termType;
       attribute string value;
-      boolean equals(Term other);
+      boolean equals(optional Term? other);
     };
     </pre>
 
@@ -168,7 +168,7 @@
     interface NamedNode : Term {
       attribute string termType;
       attribute string value;
-      boolean equals(Term other);
+      boolean equals(optional Term? other);
     };
     </pre>
 
@@ -193,7 +193,7 @@
     interface BlankNode : Term {
       attribute string termType;
       attribute string value;
-      boolean equals(Term other);
+      boolean equals(optional Term? other);
     };
     </pre>
 
@@ -222,7 +222,7 @@
       attribute string value;
       attribute string language;
       attribute NamedNode datatype;
-      boolean equals(Term other);
+      boolean equals(optional Term? other);
     };
     </pre>
 
@@ -263,7 +263,7 @@
     interface Variable : Term {
       attribute string termType;
       attribute string value;
-      boolean equals(Term other);
+      boolean equals(optional Term? other);
     };
     </pre>
 
@@ -289,7 +289,7 @@
     interface DefaultGraph : Term {
       attribute string termType;
       attribute string value;
-      boolean equals(Term other);
+      boolean equals(optional Term? other);
     };
     </pre>
 
@@ -333,7 +333,7 @@
       attribute Term predicate;
       attribute Term object;
       attribute Term graph;
-      boolean equals(Quad other);
+      boolean equals(optional Quad? other);
     };
     </pre>
 

(Removed the commit, see it above)


As for the other part I'm not sure to understand your suggestion @blake-regalia , let's start here:

In that case, I assume then it would be OK for implementations to throw

Why this assumption? This PR so far doesn't let you throw when you implement .equals, and it specifies that other can be undefined or null, and how to handle the case when it's undefined, null, or a Term/Quad.

Edited: the .equals algo doesn't define what to do when the argument isn't null | undefined | Term but I agree with:

We shouldn't overthink. .quad expects Term instances. If passed something else, behavior is undefined.
#145 (comment) by @RubenVerborgh

(The spec defines the behaviour of .equals(optional Term? other), the behaviour of .equals(anythingElse other) would be undefined behaviour)

@blake-regalia If I understand correctly you suggest explicitly mentioning that this behaviour is undefined?

@elf-pavlik elf-pavlik dismissed their stale review January 24, 2019 15:06

still discussing on gitter

Copy link
Member

@bergos bergos left a comment

Choose a reason for hiding this comment

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

For me it's ok, but boolean equals(optional Quad? other); would be even better, as it's the exactly what's in the description.

@bergos
Copy link
Member

bergos commented Jan 24, 2019

@blake-regalia can you make a proposal what to change so the PR gets your approval?

@elf-pavlik
Copy link
Member

On the chat I suggested to reconsider if we really have to define standard (blessed) equal method or we better just leave for libraries to decide how to compare equality and implement it as utility functions: https://gitter.im/rdfjs/Representation-Task-Force?at=5c49de898ce4bb25b802ca8a

@bergos: i will never need a a custom equals, but if some people want a function then they can do it. for me it's just about: const result = functionReturnsTerm(); if (result) { if(quad.predicate.equals(result)) {}} vs. if (quad.predicate.equals(functionReturnsTerm())) {}

@elf-pavlik: vs if (equals(quad.predicate, functionReturnsTerm())) {} where one can choose the right equals() for the job
do we really need that one 'blessed' equals() ?

It also would allow some factories to use 'plain objects' discussed in #104

@elf-pavlik
Copy link
Member

elf-pavlik commented Jan 27, 2019

As I understand the problem @blake-regalia and @ericprud would like to have possibility to throw if .equals() receives null or undefined while this PR mandates to return false in those cases.

I don't think having MAY or SHOULD helps here since this PR attempts to ensure that equals() will reliably return false for null and undefined.

If we don't define .equals() it would leave it up to implementations to have it as customization and libraries which want to only rely on the spec would need to use a function to compare equality in a way that meets that specific library needs.

@RubenVerborgh
Copy link
Member Author

Closing this concrete proposal until we reach an agreement here: #151

@RubenVerborgh
Copy link
Member Author

Reopening based on resolution of #151.

@RubenVerborgh RubenVerborgh reopened this Mar 4, 2019
@blake-regalia blake-regalia requested a review from vhf March 4, 2019 21:46
@elf-pavlik
Copy link
Member

@RubenVerborgh with current approvals I think you can just go ahead and merge it.

@blake-regalia
Copy link
Contributor

I added @vhf for review as he had a good suggestion about the signatures.

Copy link
Contributor

@blake-regalia blake-regalia left a comment

Choose a reason for hiding this comment

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

While we're here, as per @vhf 's suggestion, it might be best to update the signatures as well, i.e., optional Term? other and optional Quad? other. @RubenVerborgh does that sound good to you? If so, let's try and add the commits to this PR.

@RubenVerborgh
Copy link
Member Author

No objection to that.

@elf-pavlik
Copy link
Member

@blake-regalia should we just apply patch @vhf posted in his comment above? #142 (comment) and do manual merge?

@blake-regalia
Copy link
Contributor

Okay, made the commits -- let's wait for @vhf to review and then we can merge.

@elf-pavlik elf-pavlik merged commit 5a5a91d into master Mar 5, 2019
@elf-pavlik elf-pavlik deleted the fix/equals branch March 5, 2019 15:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants