|
|
Created:
5 years, 9 months ago by gbracha Modified:
5 years, 8 months ago CC:
reviews_dartlang.org Visibility:
Public. |
DescriptionChanges for TC52 3rd edition
R=eernst@google.com
Committed: https://code.google.com/p/dart/source/detail?r=44726
Patch Set 1 #
Total comments: 79
Patch Set 2 : #Patch Set 3 : #Patch Set 4 : #
Total comments: 1
Messages
Total messages: 23 (3 generated)
gbracha@google.com changed reviewers: + lrn@google.com, paulberry@google.com
This is my current draft for TC52. It may still be somewhat incoherent. I aim to sanity check it tomorrow, but if you have the time, you might take a look. I'll send you the PDF to make things easier.
gbracha@google.com changed reviewers: + eernst@google.com
Adding Erik in case he's well again.
https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:40: A conforming implementation is permitted to provide additional APIs, but not additional syntax, except for experimental features in support of null-aware cascades and tear-offs that are likely to be introduced in the next revision of this specification. Clever :) https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3536: %When a stream is canceled, the implementation must wait for the cancelation future returned by \cd{cancell()} to complete before proceeding. Uncomment? Also maybe: "stream is canceled" -> "stream subscription associated with a \code{yield*} or \code{await for} loop is canceled" https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3795: $((x) => x == \NULL ? \NULL : x.im(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k}))(o)$. x.im -> x.m https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3795: $((x) => x == \NULL ? \NULL : x.im(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k}))(o)$. Does this correctly give static warnings if o.m does not have the correct type, because "x" here is dynamic so x.m(...) would not give warnings if looking only at the rewritten version. Could it be written as: $((T x) => x == .....)(o)$ where $T$ is the static type of $o$ ? https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3903: With the introduction of null-aware conditional assignable expressions (\ref{assignableExpressions}), it would make sense to extend cascades with a null-aware conditional form as well. One might define {\em e?..suffix} to be equivalent to the expression \code{(t)\{t?.{\em suffix}; \RETURN{} t;\}($e$)}. Makes sense. We have cascades so you can write x..foo..bar; instead of x.foo;x.bar;. Would be sad to have to go back to x?.foo;x?.bar; because of lack of x?..foo?..bar https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4102: Otherwise, let $f$ be the result of looking up setter $m$ in $o$ with respect to the current library $L$. If $o$ is an instance of \cd{Type} but $e$ is not a constant type literal, then if $f$ is a method that forwards to a static setter, setter lookup fails. If setter lookup succeeds then $i$ evaluates to the closurization of setter $f$ on object $o$ (\ref{ordinaryMemberClosurization}). So we technically go through the previous two lookups for the the name "m=", even if we know syntactically that they can't succeed? How about splitting on that at the top: if m is not a setter name then - method lookup - getter lookup else if m is a setter name then - setter lookup ? I think I'd find that less confusing. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4108: \item If $m$ is a setter name, \code{im.isSetter} evaluates to \code{\TRUE{}}; otherwise \code{im.isMethod} evaluates to \code{\TRUE{}} I still think this is dangerously wrong, and must not be released in its current form. A noSuchMethod implementation seeing "im.isMethod" will assume that it is a method call and may emulate the call with zero arguments, which is wrong. It would actually want to return a function to correctly emulate the extraction. Similarly, seeing "isSetter" as true but with zero positional parameters is breaking the invariant on Invocation. The documentation of Invocation.isSetter says: * Whether the invocation was a setter call. * * If so, [arguments] has exactly one positonal argument, * and [namedArguments] is empty. The invocation object created here is simply invalid, and should not be created or be passed to any existing code. I'd actually prefer to not go through the object's noSuchMethod at all, and just throw a NoSuchMethodError directly until we can find a way to make it interceptable without being wrong. The current approach should *not* be launched, it's just too broken. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4109: \item \code{im.memberName} evaluates to \code{'m'}. This looks like it evaluates to a string, but it should evaluate to a symbol. Either: evaluates to the symbol \code{m}. or evaluates to \code{\#m}. ? https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4110: \item \code{im.positionalArguments} evaluates to the value of \code{\CONST{} []}. Are we requiring "const []" in other places too? Otherwise I think it might be overspecifying since it is detectable whether the value really is const [] or some othe empty fixed-length array, and you don't need it to be that specific object. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4116: \item \code{im'.memberName} evaluates to \code{noSuchMethod}. Symbol #noSuchMethod ? https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4190: \item If $m$ is a setter name, \code{im.isSetter} evaluates to \code{\TRUE{}}; otherwise \code{im.isMethod} evaluates to \code{\TRUE{}} Same comment as above: Just throw a NoSuchMethodError directly instead of sending incorrect/broken information to noSuchMethod. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4293: Except that iff \code{identical($T_1, T_2$)} then \cd{\NEW{} $T_1\#m$ == \NEW{} $T_2\#m$}. The identical(T_1, T_2) looks odd when you are comparing types, since they are not being used as values in the T_1#m / T_2#m syntax. How about: For any type T, new T#m == new T#m (that is, creating a closurization of the same constructor twice gives functions that are equal to each other). https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4481: $((a, i) => ((x) => x == \NULL? a[i] = e_3: x)(a[i]))(e_1, e_2)$ where $x$, $a$ and $i$ are distinct variables that are not used in $e_3$. Evaluation of a compound assignment of the form $e_1?.v$ $\code{??=} e_2$ is equivalent to the evaluation of the expression \code{((x) $=>$ x == \NULL? \NULL: $x.v ??= e_2$)($e_1$)} where $x$ is a variable that is not used in $e_2$. Need to address super.x ??= y too? https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4904: primary (selector* $|$ ( `\#' ( (identifier `='?) $|$ operator))) Could the #-syntax be part of selector instead? It's probably ok, and it does prevent the (arguably abusive) use: o#b() Just want to be sure we are sure you never want to immediately do something to an extracted function (like calling it or accessing a member of it). https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4988: `{\escapegrammar ?.}' identifier Different indentation? https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:5003: One could try and address this with special case rules, but this is simply a matter of digging oneself deeper into a hole. Removing the restrictions on the use of types as objects is the proper way to resolve this issue. Objection, editorializing!
I've only had a chance to think carefully about the changes related to null-aware operators. I'll try to review the rest later today if time allows. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3704: where $e_f$ is an expression. If $e_f$ is an identifier $id$, then $id$ must necessarily denote a local function, a library function, a library or static getter or a variable as described above, or $i$ is not considered a function expression invocation. If $e_f$ is a property extraction expression (\ref{propertyExtraction}), then $i$ is is not a function expression invocation and is instead recognized as an ordinary method invocation (\ref{ordinaryInvocation}). We need to clarify that the last sentence applies both to expressions of the form "e.m" and of the form "e?.m". (Currently "property extraction" is defined only using the '.' operator, so by a strict reading, "e?.m(...)" would be parsed as a function expression invocation, which is not what we want). Suggestion: modify the "property extraction" section to allow property extractions to be either conditional or unconditional (in much the same way that the "ordinary method invocation" section is being modified). Then move the evaluation rule for "e?.id" from line 4996 to somewhere in the "property extraction" section. In addition to fixing the parsing of "e?.m(...)", this would have the advantage of clarifying that the warnings defined in the "property extraction" section apply to uses of '?.'. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3795: $((x) => x == \NULL ? \NULL : x.im(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k}))(o)$. On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > Does this correctly give static warnings if o.m does not have the correct type, > because "x" here is dynamic so x.m(...) would not give warnings if looking only > at the rewritten version. > > Could it be written as: > $((T x) => x == .....)(o)$ > where $T$ is the static type of $o$ > ? Unfortunately Lasse's proposed rewrite would introduce an additional type check in checked mode which I think would be confusing, since the user is going to expect that the only difference between "?." and "." is the null check. (It's possible to construct programs that run in checked mode without throwing an exception, but which nonetheless contain an expression whose runtime type is unrelated to its static type). I think the CL is ok as is, since line 3786 says that we're only rewriting o?.m(...) for evaluation purposes, and line 3798 explicitly specifies the static type of o?.m(...). https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3872: \item $T$ is \code{Type}, $e$ is a constant type literal and the class corresponding to $e$ has a static getter named $m$. Considering the commentary you've added at line 4999, I'm assuming your intention is that: class C { static f() { ... } } main () { C?.f(); } should produce a NoSuchMethodError at runtime. Assuming that is true, then we should also change this line to read "\item $T$ is \code{Type}, $e$ is a constant type literal, $i$ is an unconditional ordinary method invocation, and the class corresponding to $e$ has a static getter named $m$." That way the code above will produce a static warning. Note: a similar change is probably needed to ensure that "C?.x" produces a warning, where x is a static getter/setter in the class C. I'm not sure where that change needs to go--it probably depends whether you accept my suggestions about what to do with the "property extraction" section :) https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3986: Property extraction takes several syntactic forms: $e.m$ (\ref{getterAccessAndMethodExtraction}), $\SUPER.m$ (\ref{superGetterAccessAndMethodClosurization}), $e\#m$ (\ref{generalClosurization}), $\NEW{}$ $T\#m$ (\ref{namedConstructorExtraction}), $\NEW{}$ $T\#$ (\ref{anonymousConstructorExtraction}) and $\SUPER\#m$ (\ref{generalSuperPropertyExtraction}), where $e$ is an expression, $m$ is an identifier optionally followed by an equal sign and $T$ is a type. As I mentioned on line 3704, I think the syntactic forms "e?.m" and "super?.m" also need to be covered, so that warnings defined in this section will apply to expressions of these forms. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4480: Evaluation of a compound assignment of the form $v$ $\code{??=} e$ is equivalent to the evaluation of the expression $((x) => x == \NULL? v=e : x)(v)$ where $x$ is a variable that is not used in $e$. Evaluation of a compound assignment of the form $C.v$ $\code{??=} e$, where $C$ is a type literal, is equivalent to the evaluation of the expression $((x) => x == \NULL? C.v=e: x)(C.v)$ where $x$ is a variable that is not used in $e$. Evaluation of a compound assignment of the form $e_1.v$ $\code{??=} e_2$ is equivalent to the evaluation of the expression $((x) =>((y) => y == \NULL? x.v = e_2: y)(x.v))(e_1)$ where $x$ and $y$ are distinct variables that are not used in $e_2$. Evaluation of a compound assignment of the form $e_1[e_2]$ $\code{??=} e_3$ is equivalent to the evaluation of the expression Nit: the pdf output of this paragraph contains some confusing spaces. For example, "$v$ $\code{??=} e$" comes out looking like "v ?? =e" when the intention is probably "v ??= e". Similarly, "$((x) => x == \NULL? v=e : x)(v)$" comes out looking like "((x) => x == null?v = e : x)(v)", whereas when coding one almost always puts spaces around the '?' operator. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4485: The static type of a compound assignment of the form $v$ $\code{??=} e$ or the form $C.v$ $\code{??=} e$ is the static type of $e$. The static type of a compound assignment of the form $e_1.v$ $\code{??=} e_2$ is the static type of $e_2$. The static type of a compound assignment of the form $e_1[e_2]$ $\code{??=} e_3$ is the static type of $e_3$. I don't think this is what we want. Consider the code: f(num x) { (x ??= 1).modPow(2, 1000); } (Note that "modPow" is defined on the class "int" but not the class "num".) As currently defined, this would produce no warnings, since the static type of "x ??= 1" is the static type of "1", which is "int". However, at runtime, if a non-null value is passed to f(), then "x ??= 1" will evaluate to x, which is not guaranteed to be an int. I think we want to define the static type of "v ??= e" to be the least upper bound of the static types of "v" and "e", similar to what we do for "v ?? e". https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4490: A compound assignment of the form $e_1?.v$ $op = e_2$ is equivalent to \code{((x) $=>$ x?.v = x.v $op$ $e_2$)($e_1$)} where $x$ is a variable that is not used in $e_2$. Nit: there are some spacing errors in this paragraph too. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:7508: Unary postfix & ., e++, e--, e1[e2], e1() , () & None & 15 \\ Add "?." to the table. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:7531: \hline Add "??" to the table (left-associative).
Should we allow null-aware method extraction too? x?#foo
On 2015/03/26 15:16:46, Lasse Reichstein Nielsen wrote: > Should we allow null-aware method extraction too? x?#foo Yes, eventually. Experimentation with that is implicitly allowed by the the clause at the beginning of the spec. I plan to add an explicit note about that today.
Ok, here's my review of the changes related to generalized tear-offs. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:2353: \CONST{} type `\#' (`{\escapegrammar .}' identifier)?; What's the justification for having tear-offs of both the form "new type#" and "const type#"? I don't see any semantic difference between the two syntaxes. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4130: Let $T$ be the static type of $e$. It is a static type warning if $T$ does not have an accessible instance method or getter named $m$ unless either: It seems inconsistent that on line 4102 we allow e#m to refer to a setter named m (if there is no function or getter named m), but here we don't allow for it. I think we need to say "It is a static type warning if $T$ does not have an accessible instance method, getter, or setter named m unless either..." So that code like the following will be warning-free: class C { void set s(int value) { ... } } f(C c) => c#s=; https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4132: \item $T$ or a superinterface of $T$ is annotated with an annotation denoting a constant identical to the constant proxy defined in \cd{dart:core}. Or Nit: when this text appears elsewhere in the spec, "proxy" is notated as "@proxy". https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4133: \item $T$ is \cd{Type}, $e$ is a constant type literal and the class corresponding to $e$ declares an accessible static method or getter named $m$. Similarly, "or setter" should be added here. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4141: \end{itemize} Consider adding some non-normative explanatory text to clarify that in the case where $T$ has an accessible instance member that is a getter or a setter, the static type of $i$ is the type of the getter or setter function. (I missed this subtlety on the first several readings, and assumed that you'd simply forgotten to cover these cases.) https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4147: Evaluation of a property extraction $i$ of the form \NEW{} $T\#m$ or \CONST{} $T\#m$ proceeds as follows: This is inconsistent with line 2352, where the constructs that are added to the grammar contain '.', e.g. "new T#.m" and "const T#.m". https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4155: The static type of $i$ is the type of the constructor function, if $T$ denotes a class in the surrounding scope with an accessible constructor $f$ named $m$. Otherwise the static type of $i$ is \DYNAMIC{}. "$f$" can be removed, since nothing refers to it. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4166: \commentary{Again, note that if $T$ is malformed or malbounded, existing rules ensure that a static warning occurs. This also means that $x\#$ where $x$ is not a type will always give a static warning.} I think you mean "This also means that \NEW{} $x\#$ or \CONST{} $x\#$ where $x$ is not a type will always give a static warning."
https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:2353: \CONST{} type `\#' (`{\escapegrammar .}' identifier)?; Ack, yes, forgot to comment on that. If there is no difference between the two, I'd prefer to not have the const version. It looks like the "const" means something, which it doesn't. If "const Foo#bar" was a compile-time constant expression, it would make sense, but I don't see any changes to the constant section. Also, there is no reason to not make "new Foo#bar" a compile-time constant, and in that case the const version should again be dropped. Which also reminds me: MyClass.staticMethod is a compile time constant, should MyClass#staticMethod (or getter/setter) also be constant?
sra@google.com changed reviewers: + sra@google.com
https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4102: Otherwise, let $f$ be the result of looking up setter $m$ in $o$ with respect to the current library $L$. If $o$ is an instance of \cd{Type} but $e$ is not a constant type literal, then if $f$ is a method that forwards to a static setter, setter lookup fails. If setter lookup succeeds then $i$ evaluates to the closurization of setter $f$ on object $o$ (\ref{ordinaryMemberClosurization}). On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > So we technically go through the previous two lookups for the the name "m=", > even if we know syntactically that they can't succeed? > How about splitting on that at the top: > if m is not a setter name then > - method lookup > - getter lookup > else if m is a setter name then > - setter lookup > ? > I think I'd find that less confusing. It seems that this would be simpler if the closurization site made explicit whether a tear-off getter, setter or method was required. e#foo - a field access or tear off method e#get foo - Closurizer the getter. Always returns a function taking zero arguments. Closurizes the implicit getter of a field or the closurizing getter of a method. e#set foo - Closurizes the setter. Always returns a function taking exactly one argument. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4108: \item If $m$ is a setter name, \code{im.isSetter} evaluates to \code{\TRUE{}}; otherwise \code{im.isMethod} evaluates to \code{\TRUE{}} On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > I still think this is dangerously wrong, and must not be released in its current > form. > > A noSuchMethod implementation seeing "im.isMethod" will assume that it is a > method call and may emulate the call with zero arguments, which is wrong. > It would actually want to return a function to correctly emulate the extraction. > > Similarly, seeing "isSetter" as true but with zero positional parameters is > breaking the invariant on Invocation. The documentation of Invocation.isSetter > says: > * Whether the invocation was a setter call. > * > * If so, [arguments] has exactly one positonal argument, > * and [namedArguments] is empty. > The invocation object created here is simply invalid, and should not be created > or be passed to any existing code. > > > I'd actually prefer to not go through the object's noSuchMethod at all, and just > throw a NoSuchMethodError directly until we can find a way to make it > interceptable without being wrong. The current approach should *not* be > launched, it's just too broken. I think this would also be fixed by e#foo / e#get foo / e#set foo.
https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4108: \item If $m$ is a setter name, \code{im.isSetter} evaluates to \code{\TRUE{}}; otherwise \code{im.isMethod} evaluates to \code{\TRUE{}} I don't see how that would change anything. There is no reasonable way to send an Invocation to a noSuchMethod method corresponding to extracting a setter, whether it's written e#foo= or e#set foo.
lgtm https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:40: A conforming implementation is permitted to provide additional APIs, but not additional syntax, except for experimental features in support of null-aware cascades and tear-offs that are likely to be introduced in the next revision of this specification. I guess 'property extraction' covers more than intended, but 'tear-offs' might require a definition since it is a new term in the specification. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:2353: \CONST{} type `\#' (`{\escapegrammar .}' identifier)?; Did you have to add the periods here to make the grammar parseable? I don't see them in earlier documentation about the tear-offs (e.g., https://github.com/gbracha/generalizedTearOffs/blob/master/proposal.md). https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3903: With the introduction of null-aware conditional assignable expressions (\ref{assignableExpressions}), it would make sense to extend cascades with a null-aware conditional form as well. One might define {\em e?..suffix} to be equivalent to the expression \code{(t)\{t?.{\em suffix}; \RETURN{} t;\}($e$)}. Having x?..foo?..bar it's natural to consider x?..foo..bar and x..foo?..bar. Only the "?-everywhere" and "?-nowhere" variants seem to make sense, because either the ? is "unused", or the cascade section with no ? will unconditionally fail. So maybe the syntax should enforce that only everywhere/nowhere in possible. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4110: \item \code{im.positionalArguments} evaluates to the value of \code{\CONST{} []}. Why not \code{\CONST{} <Object>[]}, such that List<dynamic> instances are not created unless this is unavoidable? A similar argument would call for \code{\CONST <Object>\{\}} below. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4118: \item \code{im'.namedArguments} evaluates to the value of \code{\CONST{} \{\}}. Could again be <Object>[$im$] and \CONST <Object>\{\}. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4193: \item \code{im.namedArguments} evaluates to the value of \code{\CONST{} \{\}}. Again we could have <Object>[] and <Object>{}. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4200: \item \code{$im'$.namedArguments} evaluates to the value of \code{\CONST{} \{\}}. <Object>{}. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4243: %\item The static type of the property extraction is the static type of function $T.m$, where $T$ is the static type of $e$, if $T.m$ is defined. Otherwise the static type of $e.m$ is \DYNAMIC{}. Why is this commented out? https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4418: Evaluation of an assignment $a$ of the form $e_1?.v$ \code{=} $e_2$ is equivalent to the evaluation of the expression $((x) => x == \NULL? \NULL: x.v = e_2)(e_1)$. The static type of $a$ is the static type of $e_2$. It might be an error-prone choice to let $e_2$ be evaluated _zero_ times when the value of $e_1$ is null. Would it make sense to say that, compared to the corresponding null-agnostic constructs, null-aware constructs do not change the number of times subexpressions are evaluated, they just prevent lookups on null? https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4480: Evaluation of a compound assignment of the form $v$ $\code{??=} e$ is equivalent to the evaluation of the expression $((x) => x == \NULL? v=e : x)(v)$ where $x$ is a variable that is not used in $e$. Evaluation of a compound assignment of the form $C.v$ $\code{??=} e$, where $C$ is a type literal, is equivalent to the evaluation of the expression $((x) => x == \NULL? C.v=e: x)(C.v)$ where $x$ is a variable that is not used in $e$. Evaluation of a compound assignment of the form $e_1.v$ $\code{??=} e_2$ is equivalent to the evaluation of the expression $((x) =>((y) => y == \NULL? x.v = e_2: y)(x.v))(e_1)$ where $x$ and $y$ are distinct variables that are not used in $e_2$. Evaluation of a compound assignment of the form $e_1[e_2]$ $\code{??=} e_3$ is equivalent to the evaluation of the expression If null-awareness should not change the number of times subexpressions are evaluated then $e$ should be evaluated also if v == null. A general pattern for this could be to pass all subexpressions to the function expression rather than just some of them. Alternatively, the principle could be that as few as possible of the given subexpressions should be evaluated for all null-aware constructs, in which case nothing should be changed above. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4480: Evaluation of a compound assignment of the form $v$ $\code{??=} e$ is equivalent to the evaluation of the expression $((x) => x == \NULL? v=e : x)(v)$ where $x$ is a variable that is not used in $e$. Evaluation of a compound assignment of the form $C.v$ $\code{??=} e$, where $C$ is a type literal, is equivalent to the evaluation of the expression $((x) => x == \NULL? C.v=e: x)(C.v)$ where $x$ is a variable that is not used in $e$. Evaluation of a compound assignment of the form $e_1.v$ $\code{??=} e_2$ is equivalent to the evaluation of the expression $((x) =>((y) => y == \NULL? x.v = e_2: y)(x.v))(e_1)$ where $x$ and $y$ are distinct variables that are not used in $e_2$. Evaluation of a compound assignment of the form $e_1[e_2]$ $\code{??=} e_3$ is equivalent to the evaluation of the expression Typo?: $((x) ..)(..)$ vs. \code{((x) $=>$ ..)(..)}. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4481: $((a, i) => ((x) => x == \NULL? a[i] = e_3: x)(a[i]))(e_1, e_2)$ where $x$, $a$ and $i$ are distinct variables that are not used in $e_3$. Evaluation of a compound assignment of the form $e_1?.v$ $\code{??=} e_2$ is equivalent to the evaluation of the expression \code{((x) $=>$ x == \NULL? \NULL: $x.v ??= e_2$)($e_1$)} where $x$ is a variable that is not used in $e_2$. How about \code{$e_1$ == null}?
I've responded to most comments. I'll do another read through to ensure basic sanity after all these edits. This will go out tonight due to ECMA requirements. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:2353: \CONST{} type `\#' (`{\escapegrammar .}' identifier)?; On 2015/03/26 18:55:58, Paul Berry wrote: > What's the justification for having tear-offs of both the form "new type#" and > "const type#"? I don't see any semantic difference between the two syntaxes. You mean we haven't stated that a const T# is a constant constructor? https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3536: %When a stream is canceled, the implementation must wait for the cancelation future returned by \cd{cancell()} to complete before proceeding. On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > Uncomment? > Also maybe: "stream is canceled" -> "stream subscription associated with a > \code{yield*} or \code{await for} loop is canceled" The VM team has concerns with this. If it's absence is a bug, it has been there since the initial version. I'm leaving as is until we are clear on that point. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3704: where $e_f$ is an expression. If $e_f$ is an identifier $id$, then $id$ must necessarily denote a local function, a library function, a library or static getter or a variable as described above, or $i$ is not considered a function expression invocation. If $e_f$ is a property extraction expression (\ref{propertyExtraction}), then $i$ is is not a function expression invocation and is instead recognized as an ordinary method invocation (\ref{ordinaryInvocation}). On 2015/03/26 15:07:21, Paul Berry wrote: > We need to clarify that the last sentence applies both to expressions of the > form "e.m" and of the form "e?.m". (Currently "property extraction" is defined > only using the '.' operator, so by a strict reading, "e?.m(...)" would be parsed > as a function expression invocation, which is not what we want). > > Suggestion: modify the "property extraction" section to allow property > extractions to be either conditional or unconditional (in much the same way that > the "ordinary method invocation" section is being modified). Then move the > evaluation rule for "e?.id" from line 4996 to somewhere in the "property > extraction" section. In addition to fixing the parsing of "e?.m(...)", this > would have the advantage of clarifying that the warnings defined in the > "property extraction" section apply to uses of '?.'. Yes, I think that is a good idea. Done. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3795: $((x) => x == \NULL ? \NULL : x.im(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k}))(o)$. On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > x.im -> x.m Done. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3795: $((x) => x == \NULL ? \NULL : x.im(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k}))(o)$. On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > Does this correctly give static warnings if o.m does not have the correct type, > because "x" here is dynamic so x.m(...) would not give warnings if looking only > at the rewritten version. > > Could it be written as: > $((T x) => x == .....)(o)$ > where $T$ is the static type of $o$ > ? No, because checked mode would behave differently. Need to deal with warnings separately. I have adjusted the text in 16.18 and 16.17.1 accordingly. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3872: \item $T$ is \code{Type}, $e$ is a constant type literal and the class corresponding to $e$ has a static getter named $m$. On 2015/03/26 15:07:21, Paul Berry wrote: > Considering the commentary you've added at line 4999, I'm assuming your > intention is that: > > class C { > static f() { ... } > } > main () { > C?.f(); > } > > should produce a NoSuchMethodError at runtime. > > Assuming that is true, then we should also change this line to read "\item $T$ > is \code{Type}, $e$ is a constant type literal, $i$ is an unconditional ordinary > method invocation, and the class corresponding to $e$ has a static getter named > $m$." > > That way the code above will produce a static warning. > > Note: a similar change is probably needed to ensure that "C?.x" produces a > warning, where x is a static getter/setter in the class C. I'm not sure where > that change needs to go--it probably depends whether you accept my suggestions > about what to do with the "property extraction" section :) The intent was that it would produce a static warning by virtue of the translation, but of course that is flawed because the translation is only used for dynamic evaluation. I think the new wording at the beginning of 16.18 and 16.17.1 covers things. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:3986: Property extraction takes several syntactic forms: $e.m$ (\ref{getterAccessAndMethodExtraction}), $\SUPER.m$ (\ref{superGetterAccessAndMethodClosurization}), $e\#m$ (\ref{generalClosurization}), $\NEW{}$ $T\#m$ (\ref{namedConstructorExtraction}), $\NEW{}$ $T\#$ (\ref{anonymousConstructorExtraction}) and $\SUPER\#m$ (\ref{generalSuperPropertyExtraction}), where $e$ is an expression, $m$ is an identifier optionally followed by an equal sign and $T$ is a type. On 2015/03/26 15:07:21, Paul Berry wrote: > As I mentioned on line 3704, I think the syntactic forms "e?.m" and "super?.m" > also need to be covered, so that warnings defined in this section will apply to > expressions of these forms. super?.m makes no sense; I've altered the grammar to ban that. e?.m is now covered. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4102: Otherwise, let $f$ be the result of looking up setter $m$ in $o$ with respect to the current library $L$. If $o$ is an instance of \cd{Type} but $e$ is not a constant type literal, then if $f$ is a method that forwards to a static setter, setter lookup fails. If setter lookup succeeds then $i$ evaluates to the closurization of setter $f$ on object $o$ (\ref{ordinaryMemberClosurization}). On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > So we technically go through the previous two lookups for the the name "m=", > even if we know syntactically that they can't succeed? > How about splitting on that at the top: > if m is not a setter name then > - method lookup > - getter lookup > else if m is a setter name then > - setter lookup > ? > I think I'd find that less confusing. Yes, I think splitting it makes a lot of sense, for this and other reasons. Done. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4108: \item If $m$ is a setter name, \code{im.isSetter} evaluates to \code{\TRUE{}}; otherwise \code{im.isMethod} evaluates to \code{\TRUE{}} On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > I still think this is dangerously wrong, and must not be released in its current > form. > > A noSuchMethod implementation seeing "im.isMethod" will assume that it is a > method call and may emulate the call with zero arguments, which is wrong. > It would actually want to return a function to correctly emulate the extraction. Good point. Indeed, existing tear-offs using the e.m syntax already have this problem, though no one has noticed so far. Long term, I think we need to extend noSuchMethod with an #isTearOff flag. I would not change the e.m tear-off behavior, but e#m would then set the flag. Presumably, no working code would notice the difference (I'll neglect any crazies who catch NoSuchMethodError). > > Similarly, seeing "isSetter" as true but with zero positional parameters is > breaking the invariant on Invocation. Yes, but if I split the cases I could have it pass a dummy argument. But the point above remains. The documentation of Invocation.isSetter > says: > * Whether the invocation was a setter call. > * > * If so, [arguments] has exactly one positonal argument, > * and [namedArguments] is empty. > The invocation object created here is simply invalid, and should not be created > or be passed to any existing code. > > > I'd actually prefer to not go through the object's noSuchMethod at all, and just > throw a NoSuchMethodError directly until we can find a way to make it > interceptable without being wrong. The current approach should *not* be > launched, it's just too broken. Well, we launched the same broken semantics years ago :-) But I agree. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4109: \item \code{im.memberName} evaluates to \code{'m'}. On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > This looks like it evaluates to a string, but it should evaluate to a symbol. > Either: > evaluates to the symbol \code{m}. > or > evaluates to \code{\#m}. > ? A bug that has been lying dormant for a while. Fixed in all locations. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4110: \item \code{im.positionalArguments} evaluates to the value of \code{\CONST{} []}. On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > Are we requiring "const []" in other places too? Otherwise I think it might be > overspecifying since it is detectable whether the value really is const [] or > some othe empty fixed-length array, and you don't need it to be that specific > object. We have been doing this in similar situations with method lookup (e.g., const {}). https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4116: \item \code{im'.memberName} evaluates to \code{noSuchMethod}. On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > Symbol #noSuchMethod ? Done everywhere in response to previous comment. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4190: \item If $m$ is a setter name, \code{im.isSetter} evaluates to \code{\TRUE{}}; otherwise \code{im.isMethod} evaluates to \code{\TRUE{}} On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > Same comment as above: Just throw a NoSuchMethodError directly instead of > sending incorrect/broken information to noSuchMethod. Done. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4293: Except that iff \code{identical($T_1, T_2$)} then \cd{\NEW{} $T_1\#m$ == \NEW{} $T_2\#m$}. On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > The identical(T_1, T_2) looks odd when you are comparing types, since they are > not being used as values in the T_1#m / T_2#m syntax. How about: > For any type T, new T#m == new T#m (that is, creating a closurization of the > same constructor twice gives functions that are equal to each other). > Then I have to exclude parameterized types somehow. Leaving as is. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4480: Evaluation of a compound assignment of the form $v$ $\code{??=} e$ is equivalent to the evaluation of the expression $((x) => x == \NULL? v=e : x)(v)$ where $x$ is a variable that is not used in $e$. Evaluation of a compound assignment of the form $C.v$ $\code{??=} e$, where $C$ is a type literal, is equivalent to the evaluation of the expression $((x) => x == \NULL? C.v=e: x)(C.v)$ where $x$ is a variable that is not used in $e$. Evaluation of a compound assignment of the form $e_1.v$ $\code{??=} e_2$ is equivalent to the evaluation of the expression $((x) =>((y) => y == \NULL? x.v = e_2: y)(x.v))(e_1)$ where $x$ and $y$ are distinct variables that are not used in $e_2$. Evaluation of a compound assignment of the form $e_1[e_2]$ $\code{??=} e_3$ is equivalent to the evaluation of the expression On 2015/03/26 15:07:21, Paul Berry wrote: > Nit: the pdf output of this paragraph contains some confusing spaces. For > example, "$v$ $\code{??=} e$" comes out looking like "v ?? =e" when the > intention is probably "v ??= e". Similarly, "$((x) => x == \NULL? v=e : > x)(v)$" comes out looking like "((x) => x == null?v = e : x)(v)", whereas when > coding one almost always puts spaces around the '?' operator. Yes, I am aware of that. I made some changes, but I still don't like how it comes out. But I can fix typography later. Today I should focus on semantics. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4481: $((a, i) => ((x) => x == \NULL? a[i] = e_3: x)(a[i]))(e_1, e_2)$ where $x$, $a$ and $i$ are distinct variables that are not used in $e_3$. Evaluation of a compound assignment of the form $e_1?.v$ $\code{??=} e_2$ is equivalent to the evaluation of the expression \code{((x) $=>$ x == \NULL? \NULL: $x.v ??= e_2$)($e_1$)} where $x$ is a variable that is not used in $e_2$. On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > Need to address super.x ??= y too? Hmm. Actually, I think we don't really cover super.v = e or super[i] = e. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4481: $((a, i) => ((x) => x == \NULL? a[i] = e_3: x)(a[i]))(e_1, e_2)$ where $x$, $a$ and $i$ are distinct variables that are not used in $e_3$. Evaluation of a compound assignment of the form $e_1?.v$ $\code{??=} e_2$ is equivalent to the evaluation of the expression \code{((x) $=>$ x == \NULL? \NULL: $x.v ??= e_2$)($e_1$)} where $x$ is a variable that is not used in $e_2$. On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > Need to address super.x ??= y too? Done. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4481: $((a, i) => ((x) => x == \NULL? a[i] = e_3: x)(a[i]))(e_1, e_2)$ where $x$, $a$ and $i$ are distinct variables that are not used in $e_3$. Evaluation of a compound assignment of the form $e_1?.v$ $\code{??=} e_2$ is equivalent to the evaluation of the expression \code{((x) $=>$ x == \NULL? \NULL: $x.v ??= e_2$)($e_1$)} where $x$ is a variable that is not used in $e_2$. On 2015/03/26 22:38:50, eernst wrote: > How about \code{$e_1$ == null}? How about it :-) ? Sorry not clear what you mean. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4485: The static type of a compound assignment of the form $v$ $\code{??=} e$ or the form $C.v$ $\code{??=} e$ is the static type of $e$. The static type of a compound assignment of the form $e_1.v$ $\code{??=} e_2$ is the static type of $e_2$. The static type of a compound assignment of the form $e_1[e_2]$ $\code{??=} e_3$ is the static type of $e_3$. On 2015/03/26 15:07:21, Paul Berry wrote: > I don't think this is what we want. Consider the code: > > f(num x) { > (x ??= 1).modPow(2, 1000); > } > > (Note that "modPow" is defined on the class "int" but not the class "num".) > > As currently defined, this would produce no warnings, since the static type of > "x ??= 1" is the static type of "1", which is "int". However, at runtime, if a > non-null value is passed to f(), then "x ??= 1" will evaluate to x, which is not > guaranteed to be an int. > > I think we want to define the static type of "v ??= e" to be the least upper > bound of the static types of "v" and "e", similar to what we do for "v ?? e". Right. Likewise for all variants (v , C.v, e1.v, e1[e2]). https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4904: primary (selector* $|$ ( `\#' ( (identifier `='?) $|$ operator))) On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > Could the #-syntax be part of selector instead? > > It's probably ok, and it does prevent the (arguably abusive) use: > o#b() > Just want to be sure we are sure you never want to immediately do something to > an extracted function (like calling it or accessing a member of it). I'm not inclined to outlaw the abuse. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4988: `{\escapegrammar ?.}' identifier On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > Different indentation? Acknowledged. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:5003: One could try and address this with special case rules, but this is simply a matter of digging oneself deeper into a hole. Removing the restrictions on the use of types as objects is the proper way to resolve this issue. On 2015/03/26 10:38:48, Lasse Reichstein Nielsen wrote: > Objection, editorializing! I am the editor, after all. I wondered if anyone would notice. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:7508: Unary postfix & ., e++, e--, e1[e2], e1() , () & None & 15 \\ On 2015/03/26 15:07:21, Paul Berry wrote: > Add "?." to the table. Done. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:7531: \hline On 2015/03/26 15:07:21, Paul Berry wrote: > Add "??" to the table (left-associative). Done.
On 2015/03/26 23:21:23, gbracha wrote: > I've responded to most comments. I'll do another read through to ensure basic > sanity after all these edits. This will go out tonight due to ECMA requirements. > > https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex > File docs/language/dartLangSpec.tex (right): > > https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... > docs/language/dartLangSpec.tex:2353: \CONST{} type `\#' (`{\escapegrammar .}' > identifier)?; > On 2015/03/26 18:55:58, Paul Berry wrote: > > What's the justification for having tear-offs of both the form "new type#" and > > "const type#"? I don't see any semantic difference between the two syntaxes. > > You mean we haven't stated that a const T# is a constant constructor? I'm not sure what you mean. "const T#" isn't a constructor at all--it's the closurization of a constructor, hence it's an ordinary function. Perhaps you mean "const T# is only legal if T's anonymous constructor is const"? But if so, I don't see why that confers any benefit--closurization of a constructor is equivalent to ((args...) => new T(args...)), which works regardless of whether the constructor being called is const. Perhaps you mean "const T# is equivalent to ((args...) => const T(args...))", but that doesn't make sense because the arguments passed to a constant constructor invocation must be constant expressions. Perhaps you mean "const T# is a valid constant expression, whereas new T# is not"? But that doesn't make any sense either--closurization doesn't require evaluating the constructor, so if we wanted to we could declare the closurization of all constructors to be valid constant expressions provided that T is not a type parameter (and similarly for the closurization of all static functions and static getters/setters). What am I missing?
The deed is done. I've tried to clarify the situation wrt typechecking. Please feel free to point out whatever remaining flaws.
Message was sent while issue was closed.
Committed patchset #4 (id:60001) manually as r44726 (presubmit successful).
Message was sent while issue was closed.
https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4108: \item If $m$ is a setter name, \code{im.isSetter} evaluates to \code{\TRUE{}}; otherwise \code{im.isMethod} evaluates to \code{\TRUE{}} The existing extraction works because of the correspondence between a function and a function-typed getter - if can try to "get" or "call" a name, and the noSuchMethod can distinguish the two and simulate its choice of field or method. You could even have said that a method introduces a synthetic getter which returns the extracted function, so "o.foo" accesses would always use a getter. It breaks down only for the new extraction of getters and setters because we get a third way to access a name, and Invocation has no way to represent that. An existing noSuchMethod implementation cannot correctly simulate a getter because extracting a getter is a completely new thing (but extracting a function isn't). In this way, o#foo is actually slightly worse than the existing tear-off because it does does not treat function-typed getters and methods the same - the former returns a function that must be called to get the value, the latter just returns the value. That's OK because the language has always been saying that a function typed getter and a function are quite different (one can't override the other). Sadly, even if we add an isTearOff flag to the Invocation, it will still make existing code behave incorrectly if it sees such an invocation because it doesn't check for that flag or implement it. We may want it anyway (it's not *breaking* because no existing program will stop working, but existing libraries may not be compatible with new code). https://codereview.chromium.org/1031323002/diff/60001/docs/language/dartLangS... File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/60001/docs/language/dartLangS... docs/language/dartLangSpec.tex:3535: %When a stream is canceled, the implementation must wait for the cancelation future returned by \cd{cancell()} to complete before proceeding. Still commented out (and two l's in "cancell").
Message was sent while issue was closed.
https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4418: Evaluation of an assignment $a$ of the form $e_1?.v$ \code{=} $e_2$ is equivalent to the evaluation of the expression $((x) => x == \NULL? \NULL: x.v = e_2)(e_1)$. The static type of $a$ is the static type of $e_2$. The ?? operator is definitely short-circuit: (e1 ?? e2) will not evaluate e2 if e1 evaluates to a non-null value. It's like JavaScript (e1 || e2). That makes ??= also short-circuit. For e1?.selector(e2) I would *not* expect e2 to be evaluated if selector isn't called. The '?' guards the entire expression. So again, I think the guarding should affect which expressions are evaluated, and I would be surprised if it didn't. Example: foo?.addFeature(new Feature(id: counter++)) If I'm not adding anything, I don't want to increment my counter. So, the only one I may have doubts about is e1.foo ?= e2. If e1 is null, would I expect it to evaluate e2? I'm split on that. Since assignment returns the value, you can have cases like: x = o?.bar = 42 and in that case you might want x to be 42. On the other hand, it's inconsistent with the other cases, which counts against it, and other null-aware expressions also have a value, so is this different from: x = o?.setBar(42) which sets x to null? I think I lean slightly towards not evaluating the expression, making o?.bar = e and o?.setBar(e) work the same way.
Message was sent while issue was closed.
Considering the rationale for subexpression evaluation for null-aware operators: Probably the most consistent choice would be "avoid subexpression evaluation whenever possible", but it does involve a bewildering richness of situations. https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4418: Evaluation of an assignment $a$ of the form $e_1?.v$ \code{=} $e_2$ is equivalent to the evaluation of the expression $((x) => x == \NULL? \NULL: x.v = e_2)(e_1)$. The static type of $a$ is the static type of $e_2$. On 2015/03/27 07:14:45, Lasse Reichstein Nielsen wrote: > The ?? operator is definitely short-circuit: (e1 ?? e2) will not evaluate e2 if > e1 evaluates to a non-null value. It's like JavaScript (e1 || e2). > That makes ??= also short-circuit. > > For e1?.selector(e2) I would *not* expect e2 to be evaluated if selector isn't > called. The '?' guards the entire expression. So again, I think the guarding > should affect which expressions are evaluated, and I would be surprised if it > didn't. > Example: > foo?.addFeature(new Feature(id: counter++)) > If I'm not adding anything, I don't want to increment my counter. > > So, the only one I may have doubts about is e1.foo ?= e2. > If e1 is null, would I expect it to evaluate e2? I'm split on that. > Since assignment returns the value, you can have cases like: > x = o?.bar = 42 > and in that case you might want x to be 42. > On the other hand, it's inconsistent with the other cases, which counts against > it, and other null-aware expressions also have a value, so is this different > from: > x = o?.setBar(42) > which sets x to null? > > I think I lean slightly towards not evaluating the expression, making o?.bar = e > and o?.setBar(e) work the same way. For (e1 || e2), the rationale for the short-circuit semantics could be "skip the evaluation of subexpressions whose value cannot affect the value of the expression as a whole" plus "evaluation proceeds from left to right". The same rationale doesn't quite work for (e1 ?? e2), but we could have "e2 is a backup for e1, to be used only if necessary". For e1?.selector(e2), we could have "call off the entire action if e1 'is not present'", again not quite the same. Finally, with `v ?= e` we could have "call off the assignment if 'v _is_ already present'". It seems that there is an interesting wealth of rationales around. ;) One overarching principle that we could apply is: "Avoid the evaluation of subexpressions as often as possible", in which case `v ?= e` should not evaluate and return the value of `e` when `v != null`, but it could pass on the value of `v` to the enclosing expression (just like other assignment expressions). https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4481: $((a, i) => ((x) => x == \NULL? a[i] = e_3: x)(a[i]))(e_1, e_2)$ where $x$, $a$ and $i$ are distinct variables that are not used in $e_3$. Evaluation of a compound assignment of the form $e_1?.v$ $\code{??=} e_2$ is equivalent to the evaluation of the expression \code{((x) $=>$ x == \NULL? \NULL: $x.v ??= e_2$)($e_1$)} where $x$ is a variable that is not used in $e_2$. On 2015/03/26 23:21:22, gbracha wrote: > On 2015/03/26 22:38:50, eernst wrote: > > How about \code{$e_1$ == null}? > > How about it :-) ? Sorry not clear what you mean. Actually, thinking about it, no special checking is needed in order to act differently when \code{$e_1$ == \NULL}. The anomaly is that we don't have e_1?[e_2] === ((a, i) => a == \NULL? \NULL : a[i])(e_1, e_2) plus something similar to e_1?[e_2] = e_3 === ((a, i) => a == \NULL || i == \NULL? \NULL : a[i] = e_3)(e_1, e_2) And of course `e_1 ?@ e_2` for @ \in {+,-,*,/,...}. ;)
Message was sent while issue was closed.
https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4418: Evaluation of an assignment $a$ of the form $e_1?.v$ \code{=} $e_2$ is equivalent to the evaluation of the expression $((x) => x == \NULL? \NULL: x.v = e_2)(e_1)$. The static type of $a$ is the static type of $e_2$. We don't actually have "v ?= e", only "o?.p = e" which should call the setter p= if o is not null (or did you mean "v ??= e"?). It is true that there can be different perspectives. Mine is mostly as a "null guard", and everything being guarded should be skipped if the guard is null (or for '??', if it is not null). It's a shorthand for something with "x == null ? ... : ...". The ?? operator exists in C# (and in Groovy as he Elvis operator), and it is short-circuit there. It should be short-circuit in Dart too. It seems that Groovy's safe navigation operator does evaluate arguments before not calling a function, so that's a different behavior. C# is getting safe navigation operators (?.foo, ?.coo(), ?[..]), but I can't find their spec. From the examples I've seen I'd expect the ?.foo(args) to not evaluate args. I'll see if I can find an implementation. Groovy a.?x=print(42) also prints 42 if a is null. At least they are consistent (but the language doesn't seem to have a specification that actually specifies anything).
Message was sent while issue was closed.
(Just for the record, publishing a comment which has been sitting here for weeks because I forgot to "Publish+Mail Comments"). https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.tex File docs/language/dartLangSpec.tex (right): https://codereview.chromium.org/1031323002/diff/1/docs/language/dartLangSpec.... docs/language/dartLangSpec.tex:4418: Evaluation of an assignment $a$ of the form $e_1?.v$ \code{=} $e_2$ is equivalent to the evaluation of the expression $((x) => x == \NULL? \NULL: x.v = e_2)(e_1)$. The static type of $a$ is the static type of $e_2$. On 2015/03/27 15:42:09, Lasse Reichstein Nielsen wrote: > We don't actually have "v ?= e", only "o?.p = e" which should call the setter p= > if o is not null (or did you mean "v ??= e"?). > > It is true that there can be different perspectives. Mine is mostly as a "null > guard", and everything being guarded should be skipped if the guard is null (or > for '??', if it is not null). It's a shorthand for something with "x == null ? > ... : ...". > > The ?? operator exists in C# (and in Groovy as he Elvis operator), and it is > short-circuit there. It should be short-circuit in Dart too. > > It seems that Groovy's safe navigation operator does evaluate arguments before > not calling a function, so that's a different behavior. C# is getting safe > navigation operators (?.foo, ?.coo(), ?[..]), but I can't find their spec. From > the examples I've seen I'd expect the ?.foo(args) to not evaluate args. I'll see > if I can find an implementation. > > Groovy a.?x=print(42) also prints 42 if a is null. > At least they are consistent (but the language doesn't seem to have a > specification that actually specifies anything). Sorry, I meant "v ??= e". I think the most intuitive semantics (having had this in the back of my mind today ;) is based on an "ok, then drop it" rationale: As soon as a null is encountered, no more actions take place. Assigning something to a variable _unless_ it is _non-null_ is an anomaly here. You might expect that only non-null values could be assigned to a formerly null valued variable, but you can't undo the side-effects (e.g., print(42)) when you discover that the returned value is null. So that operation probably doesn't have a rationale. ;-) |