-
Notifications
You must be signed in to change notification settings - Fork 214
Rough Ideas: Promoting final fields. #3358
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
Comments
Perhaps you could use a different word to indicate "same or better"? The stable getters as proposed in #1518 do indeed have the property that if you evaluate such a getter twice on the same receiver then you will receive exactly the same result (they are It is true that 'idempotent' is often used to indicate that you get the same result and there are no side effects. Stable getters do not make any such commitment, so you could have three buckets (idempotent getters, stable getters, other getters), but none of them would have this "same or better" behavior. Also, I consider the ability to reason about the code as crucial, which means that I wouldn't know how to characterize "better" for the general case. If you are running an algorithm that must terminate within 500ms then a new max time of 600ms is different, and it might be better, but I'd prefer to just note that it is not the same, and the algorithm will have to include som user-written code to determine whether it's better or worse, and what to do about it. By the way, I like your characterization of the current situation as "unstable final fields". ;-) It is indeed true that we have a keyword |
:) Done.
I see I didn't mention it properly. An idempotent getter allow code that is subset of code allowed by a reliable getter. A reliable getter allow code that is subset of code allowed by an unreliable getter. An unreliable getter allow code that is currently allowed. So I'd see any approach/concept as 'better' if it can promote getters and ensure type soundness while breaking as little code as possible. |
Also, this is just a thread I've used to share ideas because I didn't want to hijack #3307(where this conversation begin). No idea why people are disliking it(maybe it's easy or maybe it's the only thing they can do. I hope they'll write and enlighten me). I've changed stable to reliable not because stable doesn't fit the description but because I don't want anyone to confuse 'stable' with eernstg's 'stable'. I'd still go with 'stable' in practice i.e 'reliable' is used for mere explanation. It's the term 'impure' that is assumed when 'pure' is omitted because it's more general i.e it covers cases that are pure. If eernstg's getters allow side effects then they are 'impure idempotent' else they are 'pure idempotent'(one can call them just 'pure' as well). To me, 'stable' means something can't get worse but it can defintely get better. A getter returning stable values mean one can promote them and every subsequent value will be same or better for promotion(which means it won't invalidate the previous promotions but can allow more promotions). |
If ideas expressed in this thread are sound, then this thread could serve as an inspiration for a more concrete proposal that uses the right keywords at right places, and then people can vote as they should. I'm closing this because I lack the motivation to do that. |
Uh oh!
There was an error while loading. Please reload this page.
Below are some rough ideas based on my current understanding of the situation(I just skimmed through some discussions related to the topic. In case I've missed something obvious, I'll be happy to get educated about it.)
There are currently three type of getters:
A better value
b
is a value that either implements previous valuep
orp
isnull
.Example, idempotent final field/getter:
Example, reliable final getter:
Example, unreliable final getter:
More examples,
g1
returning1
(on first call),1
(on second call),1
(on third call) and so on, is an idempotent getter.g2
returningnull
,null
,1
,1
,2
,3
,0
... is a reliable getter.g3
returningnull
,1
,2
,null
... is an unreliable getter.g4
returningnull
,1.0
,1
... is an unreliable getter.g5
returningnull
,1
,"a"
... is an unreliable getter.I believe that final fields should always be idempotent because final variables are idempotent(for reads). Overriding a final field with a getter is correct as long as getter is idempotent.
Approach 1: Idempotent final fields
This approach propose that final fields are idempotent by default. This means that users are allowed to override or implement a final field with a getter as long as it's idempotent. Using a getter that is either reliable or unreliable is an error.
Give users the modifier
idempotent
that they can use on a getter that they believe is idempotent but compiler cannot prove that. This will be a promise that users are going to make just like they make in case oflate
fields.Idempotent final fields are restrictive and they might no be as useful as I think they're especially since methods used to prove idempotency aren't good and this results in unneccessary friction. Below is a slightly less-correct but better approach.
Approach 2: Reliable final fields
This approach propose that final fields are reliable by default. This means that users are allowed to override or implement a final field with a getter as long as it's reliable. An idempotent getter is also a reliable getter so those are allowed as well. Using a getter that is unreliable is an error.
The easiest method to determine whether a getter is reliable is to make sure that it's returning one type of object(no type union). I believe this will address most of the cases.
Give users the modifier
reliable
/stable
that they can use on a getter that they believe is reliable but compiler cannot prove that.Reliable final fields are subject to promotion.
Approach 3: Unreliable final fields
This is the current situation.
The situation can be improved using an optimistic promotion at package level iff every getter in hierarchy(that is known to package) is either idempotent or reliable. Then compiler can pull it off using cache at sites where a final field is promoted. Going through each package, if not every getter is idempotent(i.e some are reliable) in hierarchy(that is known to package), then add logic that update the cached value before each read iff new value is better. If some authors aren't satisfied, give them a lint
avoid_reliable_getters
and an anontation@pragma('idempotent')
that they can use on getters that they believe are idempotent and compiler can then optimize them.If someone need a truely unreliable field, they can just change
final
tovar
.The text was updated successfully, but these errors were encountered: