-
Notifications
You must be signed in to change notification settings - Fork 35
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
Conversation
priv/prelude/erlang.specs.erl
Outdated
-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). |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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()
:/
There was a problem hiding this comment.
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.)
There was a problem hiding this comment.
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.
Confirmed locally that this fixes #437 |
d989e42
to
bf2a4db
Compare
db64a25
to
0aa9da4
Compare
Hopefully fixes #437.