[Feature Request] Traits cannot express "returns a reference to a field of self"
Nobody has claimed this yet.
- Dominant language
- Mojo
- Stars
- 29.8k
- Forks
- 3.2k
- PR merge metrics
- No merged PRs in 30d
Description
Review Mojo's priorities
- I have read the roadmap and priorities and I believe this request falls within the priorities.
What is your request?
Allow a trait method to require "returns a reference into self", and allow an implementation to satisfy that requirement by returning a reference to one of its own fields.
Concretely, I'd like this pair to compile:
trait Container:
def get(mut self) -> ref[self] List[Int]:
...
struct Boxes(Container):
var items: List[Int]
def __init__(out self):
self.items = [1, 2, 3]
def get(mut self) -> ref[self.items] List[Int]:
return ref self.items
This does not yet work, but seems quite straightforward.
What is your motivation for this change?
Returning a reference to a field works fine on a plain struct, but becomes inexpressible the moment the method is required by a trait. The implementation has to fall back to returning by value, copying a collection that the caller only wanted to borrow.
So, the following compiles and returns 1.
struct Boxes:
var items: List[Int]
def __init__(out self):
self.items = [1, 2, 3]
def get(mut self) -> ref[self.items] List[Int]:
return ref self.items
def main():
var b = Boxes()
ref got = b.get()
print(got[0])
But as soon as we want to add more structure using a trait, we run into issues:
Try #1: Trait requires ref[self], impl provides ref[self.items]
trait Container:
def get(mut self) -> ref[self] List[Int]:
...
struct Boxes:
var items: List[Int]
def __init__(out self):
self.items = [1, 2, 3]
def get(mut self) -> ref[self.items] List[Int]:
return ref self.items
def main():
var b = Boxes()
ref got = b.get()
print(got[0])
Same struct as above, now with struct Boxes(Container) and the trait from field 1:
error: cannot return 'self's origin, because it might expand to a RegisterPassable type
def get(mut self) -> ref[self] List[Int]:
~~~~ ~~~~^~~~~
error: 'Boxes' does not implement all requirements for 'Container'
note: no 'get' candidates have type 'def(mut self: Boxes) thin -> ref[*[0,0]] List[Int]'
note: candidate declared here with type 'def(mut self: Boxes) thin -> ref[*[0,0].items] List[Int]'
Try #2: Trait and impl both use ref[self]
trait Container:
def get(mut self) -> ref[self] List[Int]:
...
struct Boxes:
var items: List[Int]
def __init__(out self):
self.items = [1, 2, 3]
def get(mut self) -> ref[self] List[Int]:
return ref self.items
def main():
var b = Boxes()
ref got = b.get()
print(got[0])
But this does not work as well:
error: cannot return 'self's origin, because it might expand to a RegisterPassable type
def get(mut self) -> ref[self] List[Int]:
~~~~ ~~~~^~~~~
error: cannot return reference with incompatible origin: 'origin_of(self.items)' vs 'origin_of(self)'
return ref self.items
So there is no way through. The trait cannot name the implementer's fields, because it
does not know them; and it cannot name self either, since that spelling is rejected
on the trait declaration itself — note that this first error appears in both cases 2
and 3, independently of what the implementation does.
The only workaround I found is to give up the reference entirely:
def get(mut self) -> List[Int]:
return self.items.copy()
Correct, but it copies the collection on every call. For a trait that exists precisely
to expose internal storage, that undercuts the point of having borrows.
Any other details?
All above was tested on Mojo 1.0.0 (ed45d567), Linux x86_64.
Related but distinct: modular/modular#6810 (binding a type parametrized with an origin in a
trait's associated alias).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the two trait and implementation examples from the issue on Mojo 1.0.0 (ed45d567), including the reported origin errors. Done means a trait can express a reference into self, an implementation can return a reference to its field, and the examples compile without copying the collection.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100