type inference for actual members
See original GitHub issueCurrently we force you to write an explicit type for all shared
attributes and methods, including actual
members.
The reason for this is that in our phased typechecking lifecycle, types must be assigned to shared
members before we start performing any right-to-left type inference based on expressions.
However, it’s always been in the back of my mind that there is an alternative way to get an inferred type, which is to look up the refinement hierarchy in RefinementVisitor
and assign the type of the thing it refines. There’s two complicating factors, however:
- a member can refine more than one other member, and
- a member it refines can itself have an inferred type.
Yesterday I realized that the following strategy is workable: to assign to a member the intersection of the types of the realizations of all members it refines which have explicit types.
I implemented that strategy in https://github.com/ceylon/ceylon/commit/e8e137aa3ba2204e40284491e79d0f046f6cf407, and it seems to have worked out rather well though I still need some proper tests.
For example, the following code works:
void test() {
I&J ij = Bottom().thing;
}
class Bottom() satisfies Mid1&Mid2<J> {
shared actual value thing = object satisfies I&J{};
}
interface I {} interface J {}
interface Top {
shared formal Object thing;
}
interface Mid1 satisfies Top {
shared actual formal I thing;
}
interface Mid2<T>
satisfies Top
given T satisfies Object {
shared actual formal T thing;
}
I think this is a pretty reasonable change to the language, and it doesn’t impact the backends, nor the IDEs. Thought?
Issue Analytics
- State:
- Created 7 years ago
- Comments:13 (13 by maintainers)
Top GitHub Comments
@gavinking well, as I said, I think
value
should only mean “infer from the rhs”, and never something else. It’s very regular, easy to understand, and expectable. Besides, I like that the language enforces explicitness here. I think it makes it easier for readers to understand the code. With or without and IDE, not having to navigate to another file to understand some code is a great thing.By the way, I understand that types can sometimes be long to write out, but I don’t think that that’s enough justification for this feature.
My knee-jerk reaction is that
value
used to mean “infer the declaration type from the expression type”, but now anactual value
would mean “infer it from the supertyp(s)”. That feels a little odd, I suppose because it’s the combination that changes the semantics.