Skip to content
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

Uniform tear-off syntax #691

Closed
tatumizer opened this issue Nov 18, 2019 · 14 comments
Closed

Uniform tear-off syntax #691

tatumizer opened this issue Nov 18, 2019 · 14 comments
Labels
feature Proposed language feature that solves one or more problems

Comments

@tatumizer
Copy link

(based on discussion in #376)
Proposing new syntax for tear-offs to cover several use cases. General form: obj.(thing-to-tear-off)
Examples:
a.(+) // operator tear-off
a.(unary-)
a.(get x) // getter tear-off
a.(set x) // setter tear-off
Foo.(new) // default constructor tear-off
Foo.(new named) // named constructor tear-off

@tatumizer tatumizer added the feature Proposed language feature that solves one or more problems label Nov 18, 2019
@eernstg
Copy link
Member

eernstg commented Dec 6, 2019

Cf. this discussion on dart-misc:

It would also be useful to consider tear-offs of instance methods independently of the receiver. That is, a method with k positional arguments is torn off as a function with k + 1 positional arguments, and the first argument is the receiver.

Getters and setters could be handled as described above, we'd just change a from an expression denoting an instance to a type literal: Class.(thing-to-tear-off-with-receiver-argument).

@rrousselGit
Copy link

rrousselGit commented Dec 6, 2019

I don't see myself ever using a.(get x) when I can write () => a.x.

They take the same number of characters, but the closure approach is easier to refactor.

What about:

#a
#+a
#-a
#a.x
#=a.x
#Foo
#Foo.named

?

@rrousselGit
Copy link

The character doesn't really matter.
We can change it to something else, like ~ or ::

@natebosch
Copy link
Member

It would also be useful to consider tear-offs of instance methods independently of the receiver.

Does this have the semantics of picking a concrete implementation statically? Or will it have the semantics of wrapping with a closure and the concrete implementation is still picked at runtime?

I don't think the former would work:

class Foo {
  int get _private => 1;

  int get public => 2;

  void doStuff() {
    print(_private + public);
  }
}

// Some other library.
class Bar implements Foo {
  @override
  void doStuff() {}

  @override
  int get public => 3;

  // No override of _private possible
}

void main() {
  void Function(Foo) tornOff = Foo::doStuff;
  tornOff(Foo()); // OK
  tornOff(Bar()); // throws? What would the error be?
}

I think the latter would be fine. Effectively Foo::doStuff is syntactic sugar for (Foo f, <other args>) => f.doStuff(<other args>);

@eernstg
Copy link
Member

eernstg commented Dec 9, 2019

Does this have the semantics of picking a concrete implementation statically?

No, the idea is simply that with abstract class C { S foo(T); } a tear-off like myC.foo yields something that works like (T t) => myC.foo(t), and C.foo yields (C self, T t) => self.foo(t). So that's what you call 'the latter'.

@kasperpeulen
Copy link

What about a default first parameter name called it

=> a + it // operator tear-off
=> a - it
=> a.x // getter tear-off
=> a.x = it // setter tear-off
=> Foo(it) // default constructor tear-off
=> Foo.named(it) // named constructor tear-off

@kasperpeulen
Copy link

Right, my point is that I don`t think we really need new tear-off syntax, if we have #265.

@eernstg
Copy link
Member

eernstg commented Dec 10, 2019

There is one thing that a tear-off is capable of doing that we can't emulate with a manual rewrite, namely the special behavior for equality tests (operator ==): Two tear-offs of the same method will test equal iff they were torn off the same receiver (o1.foo == o2.foo iff identical(o1, o2)). This property could be carried over to the new kind of tear-off (where we tear an instance method off of a class, yielding a function that adds an extra positional argument accepting the receiver): They could be equal iff they tear off the same method of the same statically known receiver type. A similar property could be defined for getters and setters and constructors.

@RedHatter
Copy link

Isn't this the same functionality of this proposal that was aproved back in 2015?

@eernstg
Copy link
Member

eernstg commented Jun 6, 2020

It is similar, but the generalized tear-offs as described in said proposal are not supported in Dart today (not in the specification, not in the implementation).

@fzyzcjy
Copy link

fzyzcjy commented May 14, 2021

Any updates after a year? This question may be related: https://stackoverflow.com/questions/67534998/getter-setter-method-passed-as-a-pseudo-function-pointer-in-dart?noredirect=1#comment119380290_67534998

@fzyzcjy
Copy link

fzyzcjy commented Jan 24, 2022

@tatumizer Hi is it implemented? (I see it closed) thanks

@fzyzcjy
Copy link

fzyzcjy commented Jan 24, 2022

@tatumizer All right :(

@micimize
Copy link

micimize commented Jan 24, 2022

@tatumizer can you clarify/expand on that some? For instance, do you mean:
1. A uniform tear-off approach will never be implemented but each kind of tear-off may be taken turn (e.g. now we have Foo.new, we may eventually have some equivalent to Foo.(set bar)).
2. Tear-offs for operators, getters, and/or setters will never be implemented.

If the latter, could we have some insight into the discussion that led to that decision?

Edit: misread and thought tatumizer was a contributor 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems
Projects
None yet
Development

No branches or pull requests

8 participants