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

Allow object patterns to tear off methods? #2561

Closed
munificent opened this issue Oct 7, 2022 · 5 comments · Fixed by #2779
Closed

Allow object patterns to tear off methods? #2561

munificent opened this issue Oct 7, 2022 · 5 comments · Fixed by #2779
Labels
patterns Issues related to pattern matching.

Comments

@munificent
Copy link
Member

The patterns proposal currently says:

It is a compile-time error if X does not have a getter whose name matches the subpattern's field name.

(Emphasis added.) This implies that you can't refer to a method in an extractor pattern in order to tear it off. I'm not sure if allowing that is particularly useful, but we certainly could support it. Should we?

@munificent munificent added the patterns Issues related to pattern matching. label Oct 7, 2022
@lrhn
Copy link
Member

lrhn commented Oct 7, 2022

I'd generally say no. Just because tear-offs and getter invocations share the same syntax, doesn't mean that they are the same thing. I'd be fine with a specialized tear-off syntax (which also works to tear off getters).

I can see cases where I'd use it anyway:

var (:add, :addError, :close) = streamController; // Assumes inferring the tear-off type.
otherStream.listen(add, addError, _wrapAction(close));

Basically, any time you want to access more than one thing on the same value, you can use destructuring for it.
Needing to extract multiple methods is still going to be rare, so I'd be fine with not supporting it.

The real question is what we can do for dynamic tear-off.
If I write:

var dynamic(:Function add, :Function addError, :Function close) = streamController as dynamic;

is there any reasonable implementation which will not tear off the methods.
We'd have to do a runtime check to distinguish between a method and a getter. Is that reasonable to require from the runtime?
(It's dynamic code, so some overhead is expected anyway. That's not what worries me. It's more whether there's need for new special functionality just to support this.)

@leafpetersen
Copy link
Member

I'm not sure if allowing that is particularly useful, but we certainly could support it. Should we?

I don't have strong opinions here, but I could definitely see some places one might use it, e.g. I know I've seen people write code like this (because A and B don't share the right super-interface):

Object a = ...;
bool result;
if (a is Iterable) {
  result = a.contains(3);
} else if (a is Map) {
 result = a.containsKey(3) {
}
if (result) {
  ...
}

which could become:

switch(a) {
   case Iterable(:var contains):
   case Map(containsKey:var contains):
     if (contains(3)) {
         ....
     }
}

@Levi-Lesches
Copy link

Levi-Lesches commented Oct 14, 2022

It could just be me, but destructuring a tear-off is starting to get a little less than intuitively readable. Wouldn't it be better to encourage something like the following instead?

Object a = // ...
bool Function(int) test = switch(a) {  // the new switch expression
  case Iterable: a.contains;
  case Map: a.containsKey;
};

if (test(3)) { /* */ }

@munificent munificent changed the title Allow extractor patterns to tear off methods Allow object patterns to tear off methods Nov 5, 2022
@munificent munificent changed the title Allow object patterns to tear off methods Allow object patterns to tear off methods? Nov 5, 2022
@eernstg
Copy link
Member

eernstg commented Jan 17, 2023

I think we should allow method tear-offs in objectPatterns because we allow extension getter invocations, and also because @lrhn had some quite reasonable use cases.

(You could actually say that a method tear-off is very similar to a getter invocation, whereas an extension getter invocation is a completely different thing.)

This also means that we don't have to explain why it doesn't fail in the dynamic case if we use a patternField to invoke a supposed getter, and it turns out to be a method tear-off. Perhaps it isn't very hard to implement a dynamic error in that situation, but I just don't see how it would help anyone.

@munificent
Copy link
Member Author

I think we should allow it too. My reasoning is basically:

  1. If a user were to try to write it, it's pretty clear what their intent is since it's symmetric with property access expressions which perform tear-offs.
  2. If we didn't want to make that syntax do a tear-off, I can't think of what other useful behavior it could have.

So we may as well make it do the thing they think it will do.

munificent added a commit that referenced this issue Jan 19, 2023
-   Allow object pattern fields to tear off methods.

-   No exception for non-exhaustive switch statements that don't need
    to be exhaustive.

-   Promoted types and bounds can be always-exhaustive.

-   Fix incorrect static error with cast patterns in assignments.

-   Clarify that patterns are not const contexts.

Fix #2561.
Fix #2698.
Fix #2765.
Fix #2758.
munificent added a commit that referenced this issue Jan 19, 2023
* [patterns] Fix a handful of small-ish patterns issues:

-   Allow object pattern fields to tear off methods.

-   No exception for non-exhaustive switch statements that don't need
    to be exhaustive.

-   Promoted types and bounds can be always-exhaustive.

-   Fix incorrect static error with cast patterns in assignments.

-   Clarify that patterns are not const contexts.

Fix #2561.
Fix #2698.
Fix #2765.
Fix #2758.

* Tweak wording in a few places.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
patterns Issues related to pattern matching.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants