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

Syntax for implementing a single-function interfaces #4711

Open
josh11b opened this issue Dec 18, 2024 · 3 comments
Open

Syntax for implementing a single-function interfaces #4711

josh11b opened this issue Dec 18, 2024 · 3 comments
Labels
leads question A question for the leads team

Comments

@josh11b
Copy link
Contributor

josh11b commented Dec 18, 2024

Summary of issue:

Many of the operator overload interfaces have a single function, and other interfaces are expected to commonly as well. The current impl definition syntax is perhaps cumbersome for this case. Perhaps we should have a convenient shortcut?

In order to allow evolution of interfaces, this should apply any time the interface has one required function. If this convenient syntax is used, it should ignore functions with a default or final definition in the interface.

@josh11b josh11b added the leads question A question for the leads team label Dec 18, 2024
@josh11b
Copy link
Contributor Author

josh11b commented Dec 18, 2024

One option that was suggested in a recent conversation was:

class C {
  impl as Core.AddWith(D) where .Result = E {
    fn Op[self: Self](other: D) -> E {
      return DoAdd(self, other);
    }
  }
}

could be shortened to:

class C {
  impl as Core.AddWith(D) fn[self: Self](other: D) -> E {
    return DoAdd(self, other);
  }
}

A few things to note:

  • This is a pure subset of the tokens, skipping the where clause, the function name, and one set of curly braces {...}.
  • As a result, the body of the function ends up indented less.
  • This would only be allowed in cases where the non-function associated constants could be deduced from the signature of the function (in this case Result can be deduced to be the return type of the function which is specified as E).
  • We could potentially infer the interface parameters, as well, so we could skip the (D) after Core.AddWith. This is in line with other cases where we want to infer parameters, like CTAD in C++.

@danakj
Copy link
Contributor

danakj commented Dec 20, 2024

Not sure I am a fan of a shorthand for this, but some thoughts on why for me:

  • Losing the where requires the developer to become a compiler (they have to go do some type deduction/connection logic) to figure out what the associated Result type will be.
  • Using a shorthand for single functions would cause a bunch of unrelated source changes when adding/removing a function to/from an interface.

@chandlerc
Copy link
Contributor

chandlerc commented Dec 20, 2024

Not sure I am a fan of a shorthand for this, but some thoughts on why for me:

  • Losing the where requires the developer to become a compiler (they have to go do some type deduction/connection logic) to figure out what the associated Result type will be.
  • Using a shorthand for single functions would cause a bunch of unrelated source changes when adding/removing a function to/from an interface.

Maybe not obvious from the original write up, but the idea is that this is a short hand for the full syntax:

class C {
  impl as Core.AddWith(D) where .ResultType = E {
    fn [self: Self](other: D) -> E {
      return DoAdd(self, other);
    }
  }
}

That is, interfaces opt into this being available by having an anonymous function and all associated constants being deduced from the signature of that function in an impl. But it is just available, and an impl can always choose to use the normal syntax instead for clarity or as you say for access to more powerful features of where.

And the expectation is that the only changes that would require updating the source would be the same ones that require updating the source today: adding a function or associated constant that must be defined / specified in the impl. If defaults are available, the syntax wouldn't change.

But it would require a structural change as well as the addition of the newly required function definition or associated constant value. So it's more making the required source changes a bit more invasive than introducing source changes where we wouldn't have had them previously.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
leads question A question for the leads team
Projects
None yet
Development

No branches or pull requests

3 participants