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

Add specs for ++/2 and --/2 #440

Merged
merged 5 commits into from
Aug 29, 2022

Conversation

erszcz
Copy link
Collaborator

@erszcz erszcz commented Aug 24, 2022

Hopefully fixes #437.

Comment on lines 44 to 49
-spec erlang:'++'(list(T1), list(T2)) -> list(T1 | T2);
(list(T1), nonempty_improper_list(T2, T3)) -> nonempty_improper_list(T1 | T2, T3);
([], T) -> T;
(nonempty_list(T1), T2) -> nonempty_improper_list(T1, T2).
Copy link
Collaborator

Choose a reason for hiding this comment

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

According to docs, the clauses in a spec are not allowed to overlap. It's not like a case expression where the first matching clause is chosen.

I don't know if we can write such spec though. Perhaps we should go for this one.

Would you care to add some examples (test cases) to show that this fancy spec is useful?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Would you care to add some examples (test cases) to show that this fancy spec is useful?

Hmm, I tried coming up with some, but apparently this spec is not taken into account at all. There are hardcoded rules for handling ++ and --. So for the sake of #437 the only important thing is to have any spec defined. I'll work on some known problems tests for this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah I thought there are special code for binops. Perhaps the spec ia needed only when called as a funcrion ie like erlang:'++'(X, Y)...?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ok, this seems to be a bigger topic previously being discussed in #163 (closed today by Pierre). I think in this PR we should focus on unblocking #437 and maybe providing known_problems for some list operators, but in general not let it linger for too long.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ok, I have added the tests following the examples and the sketched out spec. Indeed, the function forms seem to already be checked against the spec, but not the operator forms.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it's useful to have some richer semantics for some operators

So far it seems we're seeing incomplete implementations instead of richer semantics ;p As in the case of ++ whose type checking implementation is less accurate than the spec I sketched above. Anyway, I think that we can have custom implementations for "some operators" where it makes sense yet default to treating the operators and erlang:* invocations as equivalent.

According to some paper [...]

Yeah, I remember reading that, too. That's a convincing point, indeed. If they overlap it's just not clear (not possible to tell deterministically) which spec to choose.

Ultimately, it's possible to rewrite the spec not to have overlapping domains. It's going to have more clauses, so will be slightly less readable, but it should still match the new tests.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ultimately, it's possible to rewrite the spec not to have overlapping domains.

Ok, I take it back. It's not possible without negation types. T2 in the third clause overlaps the 2nd param of the first and second clauses...

-spec erlang:'++'([T1, ...], [T2])                           -> [T1 | T2, ...];
                 ([T1, ...], nonempty_improper_list(T2, T3)) -> nonempty_improper_list(T1 | T2, T3);
                 ([T1, ...], T2)                             -> nonempty_improper_list(T1, T2);
                 ([], T)                                     -> T.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The thing I wanted to achieve with the spec was the type of a proper [a,b,c] ++ [d,e,f] to be a proper list. Due to the implementation of the ++ operator and improper lists it turns out we cannot escape the _ ++ _ :: term() :/

Copy link
Collaborator

Choose a reason for hiding this comment

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

I know. I believe Josef would just say that ++ should be used for proper lists only. Anything else is a type error. (But I'm not sure it's correct given you actually use it for other stuff even if we don't like it.)

Copy link
Collaborator

Choose a reason for hiding this comment

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

We can go for the spec you came up with. We can always change it later if it poses any problems.

@japhib
Copy link

japhib commented Aug 24, 2022

Confirmed locally that this fixes #437

@erszcz erszcz force-pushed the add-more-list-operator-specs branch from d989e42 to bf2a4db Compare August 27, 2022 12:24
@erszcz erszcz force-pushed the add-more-list-operator-specs branch from db64a25 to 0aa9da4 Compare August 29, 2022 17:46
@erszcz erszcz merged commit a2a0369 into josefs:master Aug 29, 2022
@erszcz erszcz deleted the add-more-list-operator-specs branch August 29, 2022 17:48
This was referenced Sep 24, 2022
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.

Call to undefined function :erlang.'++'/2 in OTP 22
3 participants