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

Adding common interface implemented by Map and Vector that is mutable and iterable #7586

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

acrylic-origami
Copy link

@acrylic-origami acrylic-origami commented Jan 7, 2017

MutableMap and MutableVector both already implement KeyedContainer and IndexAccess. The former extends KeyedTraversable, while the latter gives these classes basic mutability through set[All] and removeKey.

Currently, the only way to admit both Map and Vector to an immutable wrapper with mutable descendants is to upper-bound the collection generic type by ConstIndexAccess and refine to a mutable IndexAccess in the descendants. For example:

<?hh // strict
class ImmutableWrapper<Tk, +Tv, +TCollection as \ConstIndexAccess<Tk, Tv>> {
	public function __construct(private TCollection $collection) {}
	public function get_collection(): TCollection {
		return $this->collection;
	}
}
class MutableWrapper<Tk, Tv, +TCollection as \IndexAccess<Tk, Tv>> extends ImmutableWrapper<Tk, Tv, TCollection> {
	public function mutate(Tk $k, Tv $v): void {
		$this->get_collection()->set($k, $v); // for example
	}
}

However, without iterability, working with the IndexAccess family is cumbersome, and attempts to add iterability get messy. Keeping track of keys in a separate iterable collection, for example, leads quickly to generic hell, especially when the mutability of this collection is considered.

Of the Traversable descendants, I'm proposing KeyedContainer because it and Indexish are the only common ancestors of Map and Vector to define an indexing method — in this case, the square bracket syntax. Indexish is also a good candidate, but I figure that in the future, some core Hack classes might extend KeyedContainer but not Indexish, judging from Typing[4005] (the illegal-use-of-square-bracket-indexing error).

I should mention the associated issue, #7573 .

…d IndexAccess for mutable, key-iterable collections (Map and Vector at the moment).
@facebook-github-bot
Copy link
Contributor

Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla - and if you have received this in error or have any questions, please drop us a line at [email protected]. Thanks!

If you are contributing on behalf of someone else (eg your employer): the individual CLA is not sufficient - use https://developers.facebook.com/opensource/cla?type=company instead. Contact [email protected] if you have any questions.

@facebook-github-bot
Copy link
Contributor

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks!

@hhvm-bot
Copy link
Contributor

hhvm-bot commented Jan 9, 2017

@acrylic-origami updated the pull request - view changes

@hhvm-bot
Copy link
Contributor

hhvm-bot commented Jan 9, 2017

@mofarrell has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@dlreeves
Copy link
Contributor

dlreeves commented Jan 9, 2017

KeyedContainer was introduced to be a union of Hack Collections and PHP arrays. This requires adding special support in the runtime to have arrays behave as instances of KeyedContainer. Do you imagine arrays also being instances of MutableKeyContainer?

@acrylic-origami
Copy link
Author

acrylic-origami commented Jan 10, 2017

@dlreeves That's a good point. I don't include them because they don't implement IndexAccess. Functionally, they definitely fit the concept behind MutableKeyedContainer. However, there are no interfaces for square-bracket syntax for mutation.

MutableKeyedContainer would actually be in the right place to be that interface, if it ditched the extension of IndexAccess and allowed setting via square brackets behind the scenes.

For now, I figured Map and Vector was a good start for MutableKeyedContainer.

@fredemmott
Copy link
Contributor

@sgolemon was thinking of this a long while back - any comments, and still have a copy of the diagram?

@dlreeves
Copy link
Contributor

If it doesn't support arrays then I wonder if a mutable version of Indexish would be better. At one point we allowed Indexish to be modified with [] in the type checker, but removed it since the immutable collections also implemented this interface.

@acrylic-origami
Copy link
Author

@dlreeves Are you proposing reviving this historic mutable Indexish implementation? I'm not sure I follow your rationale that Indexish is more appropriate because of arrays, when arrays implement Indexish as well. Could you elaborate?

Also, did this mutable Indexish include a mechanism to remove elements? That's the one functional thing IndexAccess would implement over a mutable Indexish as it stands.

@dlreeves
Copy link
Contributor

@acrylic-origami - Ok took a look at the type hierarchy again. Would having IndexAccess extend Indexish solve this particularly issue for you? That way you have the mutable methods available via IndexAccess, but can access values using square-brackets. You still wouldn't be able to write using square-brackets though.

@acrylic-origami
Copy link
Author

@dlreeves Well, Indexish can't be usefully extended by custom interfaces, but IndexAccess definitely can. So, I suggested they stay separate and are combined by a common descendant to avoid misleading upcasts of custom IndexAccesses to KeyedContainer. That way, the only and more correct option would be to upcast to ConstIndexAccess to achieve that functionality.

@mofarrell mofarrell added the hack label Jan 25, 2017
@mofarrell
Copy link
Contributor

mofarrell commented May 12, 2017

https://pbs.twimg.com/media/C_pNhu3XgAAibNw.jpg
^ Collections diagram

At the moment, functions with nullable Disposable arguments can't pass
the typechecker (unless the argument isn't referenced at all), since
`is_null` trips Typing[4188].
@facebook-github-bot
Copy link
Contributor

@acrylic-origami has updated the pull request. Re-import the pull request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants