Open gavinking opened 11 years ago
This seems cool to me. Loops will be a little more restrictive, though.
Loops will be a little more restrictive, though.
Out of curiosity: why?
Loop-invariant inference is a big challenge in the analysis community, so we don't want to do that. We can have types be refined within the body of the loop, but by the end of the body of the loop that type needs to be a subtype of the type coming into the loop.
When I finally get round to implementing this - and I'm looking forward to it, for 1.1 - what I probably need to do is get rid of the new sub-Scope
every time the type of something changes and instead maintain a map inside ExpressionVisitor
that keeps the "current" type (a stack of current types, I suppose) for each value, and copy that type on the MemberOrTypeExpression
so the backend can get it from there.
would make this simpler if I could just do if(!is ComponentName obj) - though I recognize that I'm doing it somewhat wrong anyway:
@lahwran yes, this is part of #74, as mentioned in this comment https://github.com/ceylon/ceylon-spec/issues/74#issuecomment-11896085.
I wonder if the following fits in this feature, and if it is even possible.... Instead of:
class FlowBased()
{
variable String? notDefinedYet = null;
shared void doStuff()
{
notDefinedYet = "Now it is defined";
doMoreStuff();
}
void doMoreStuff()
{
if (exists ndy = notDefinedYet)
{
print(ndy + "!");
}
}
}
we could write:
class FlowBased()
{
variable String? notDefinedYet = null;
shared void doStuff()
{
notDefinedYet = "Now it is defined";
doMoreStuff();
}
void doMoreStuff()
{
print(notDefinedYet + "!");
}
}
Ie. the compiler will find out that doMoreStuff()
is always called after notDefinedYet
is defined, so there is no need to check it in this function.
Of course, if a path is added that risks to call doMoreStuff()
without setting notDefinedYet
first, the code would no longer compile...
The use case I frequently encounter (in Java) is in GUI applications where some data cannot be available at component creation time, so it is set later, then displayed. But we are sure it is displayed only after it is set, so the check for nullity is a bit redundant.
I am not sure the case is worth the effort of implementing it (if possible at all), but I had to ask... :-)
@PhiLhoSoft No, compilers don't generally try to do stuff which involves tracing paths through multiple functions. That bumps up against circularities and nontermination etc, etc.
The relevant term is "typestate". It's surprisingly difficult, though there is research on it from an analysis perspective and from a language-design perspective. The Wikipedia article seems to be a decent start with the key links I could think of.
On Tue, Oct 21, 2014 at 9:56 AM, Gavin King notifications@github.com wrote:
@PhiLhoSoft https://github.com/PhiLhoSoft No, compilers don't generally try to do stuff which involves tracing paths through multiple functions. That bumps up against circularities and nontermination etc, etc.
— Reply to this email directly or view it on GitHub https://github.com/ceylon/ceylon-spec/issues/536#issuecomment-59930748.
A nice feature that it looks like Groovy now has is, if I'm understanding correctly, is the following:
Currently we don't let you use type inference with "forward" specified values. So it would be very easy to make it mean flow-based typing.
Another example:
(This feature would fit nicely with the proposal to do type narrowing in
else
blocks.)