-
Notifications
You must be signed in to change notification settings - Fork 205
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
Method-to-function conversion #4150
Comments
There would be no feature ambiguity since function types don't have static namespaces. I'm worried that using the same syntax for different things can lead to confusion. Why stop at one level? This is a more indirect approach to a feature that would turn |
#8 looks much more general and more readable IMO: var xs2 = [1, 2, 3].map(#.toString()); There are no limitations there on what kind of expression you can use. |
@lrhn wrote:
Good points! For @tatumizer wrote:
True, with the ability to denote the actual argument in the expression we do have much more expressive power. var xs1 = [1, 2, 3].map(.toString()); // Based on the context type schema `_ Function(int)`.
var xs2 = [1, 2, 3].map(#.toString()); // A concise function literal based on a proposal in #8. The primary difficulty is that there is no firm syntactic basis for delimiting the function literal as a whole. (I said already in the original posting of issue #8 that 'The main issue with this approach is that it is ambiguous', so there's nothing new about that). For example: foo(bar(baz(#.toString()))) // Could mean
foo(bar(baz(((x) => x).toString()))) // or
foo(bar(baz((x) => x.toString()))) // or
foo(bar((x) => baz(x.toString()))) // or
foo((x) => bar(baz(x.toString()))) // or
(x) => foo(bar(baz(x.toString()))) We'd also need to have disambiguation rules for the case where there is more than one occurrence of I don't think we can allow this kind of decision to be based on the static types of the expressions involved (because we don't even know the structure of those expressions, and different structures may have subexpressions with completely different static types). In other words, we must decide on the structure based on the syntax alone. I think this implies that the proposal that uses Method-to-function conversion is much simpler in this respect: It includes the selector chain after Also, all the heated debates about |
@eernstg wrote:
I don't understand that. The whole idea of the original proposal is to base the decision on the static type of the expression:
Without this logic, you won't be able to distinguish between |
Exactly, this proposal is syntactically unambiguous, and it uses the context type. No problem. The
where 'this kind of decision' means 'delineating the function literal syntactically'. |
The ambiguity you pointed to arises only in the context of nested calls like Your proposal is entirely based on the assumption that the expression starts with the dot (that's how shortcuts are currently defined). For function literals, this is too restrictive. You can't even write (Another point: while designing the feature, we'd better avoid referring to meaningless names like bar and baz; normally, the method name tells us whether the method expects a closure as a parameter (onError, onClick, etc). Otherwise, the comparison is unfair: in OP, you use |
I prefer the other proposals, because
|
I'm biased of course, but I'd agree that #3786 should be accepted as well, which does this directly with |
Discussions in #357 strongly suggest that we will support a primary expression of the form
'.' <identifier>
(e.g.,.foo
). The semantics of such terms will most likely be determined by the context type.This issue is a proposal that we should generalize the semantics of this syntax to cover an additional case: If
.foo
is used in a context where an expression of typeR Function(T)
is expected then it is implicitly transformed into(T x) => x.foo
. Similar conversions are applied when a chain of selectors are present, e.g.,.foo(1)?.whereType<int>()[4]
would become(T x) => x.foo(1)?.whereType<int>()[4]
. For example:This feature will only enable a small amount of abbreviation, but it is likely to be convenient to have in a large number of invocations of
map
andforEach
on collections, as well as many other situations involving callback arguments, and this would justify having the feature even though it doesn't do a lot each time it is used.Proposal
Syntax
The grammar is adjusted as follows:
Several other proposals are expected to introduce this new kind of expression. If and when we get any of those proposed features then this grammar change is not needed.
Static analysis
Assume that
e
is an expression of the form.id s1 .. sk
whereid
is an identifier andsj
is derived from<selector>
, forj
in1 .. k
, ande
is not a subexpression of an expression of the form.id s1 .. sk .. sn
wheresj
is derived from<selector>
forj
in1 .. n
(that is,e
already contains all the selectors).If the context type of
e
is of the formR Function(T)
for some typesR
andT
thene
is implicitly transformed into((T x) => x.e s1 .. sk)
, wherex
is a fresh name.If the resulting function literal is or contains a compile-time error then it should be reported in terms of a failure to perform the method-to-function conversion, plus information about the error that arises after the conversion. For example,
.foo
may be an error in the context ofR Function(T)
becauseT
isn't an interface type that declares a member namedfoo
, and there is no extension method namedfoo
which is applicable to a receiver of typeT
; orx.foo
is an expression that has no errors whenx
has typeT
, but that type is not a subtype ofR
, and hence the function literal as a whole isn't assignable toR Function(T)
.The text was updated successfully, but these errors were encountered: