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

ENH Add generic types #11108

Merged
merged 1 commit into from
Jan 17, 2024

Conversation

GuySartorelli
Copy link
Member

@GuySartorelli GuySartorelli commented Jan 10, 2024

Description

Adds generic types (mostly return types - we don't need generic param typing for now since we're not really using static analysis).

There are also a few general corrections to PHPDocs that I noticed along the way (e.g. adding |null when the method is returning a null value.

There are some cases where either the return type or the whole PHPDoc was duplicated from the parent class - in those cases I've simply removed the duplication.

Caveats

  1. DataObject::get() and DataObject::get_one() give weird results in some specific scenarios.
    • If using DataObject:get(MyClass::class), it won't know about the MyClass class and just give you a DataList<DataObject> - which is correct, but imprecise. Same with get_one() with the same syntax.
    • If using MyClass::get(AnotherClass::class), it won't know about the AnotherClass and will give you a DataList<MyClass> - which is NOT correct. I think this is okay since doing that is a bad code smell anyway - people should just not do that. Probably in a future release we should explicitly disallow that syntax. Same with get_one() with the same syntax.
    • We could use a conditional return type here which would be useful for static analysis, but that's not supported in VSCode using intellephense so we shouldn't do that.
  2. Because ArrayList will wrap an associative array with ArrayData in its iterator (but not in First(), Last(), etc), the typing for the iterator is wrong if the arraylist was created with associative arrays. Ideally people should be wrapping their associative arrays in ArrayData anyway because of the existing inconsistency with what ArrayList returns.
  3. Because ArrayList can accept values of mixed types (you could have a combination of ArrayData, DataObject, and some custom class for example), the return values might not always be reported correctly, especially if adding objects to the list after instantiation. This is acceptable since that sort of usage is less common - and they'd already have to use @var or similar in their IDE before this PR.
  4. When passing a service name that isn't a direct FQCN to the injector (e.g. Injector::inst()->get(LoggerInterface::class . '.error');), there is no way for an IDE to determine the correct class name. In the future we may want to use conditional return types to try to resolve this sort of thing, but as of writing those aren't as widely supported in IDEs as non-conditional generic return types are.
  5. For the extension generics to really be useful, subclasses will need to use the appropriate @extends annotation. I've raised a separate card to add a CI rule for this so we can at least be consistent with it in supported modules.
  6. SapphireTest::objFromFixture() can technically take a table name as the first argument.... but that's probably never done in practice. I'm 99% sure in that case most IDEs would correctly still recognise that it's returning DataObject anyway so should be fine.

Manual testing steps

Check that things work as expected in your IDE.

Issues

Pull request checklist

  • The target branch is correct
  • All commits are relevant to the purpose of the PR (e.g. no debug statements, unrelated refactoring, or arbitrary linting)
    • Small amounts of additional linting are usually okay, but if it makes it hard to concentrate on the relevant changes, ask for the unrelated changes to be reverted, and submitted as a separate PR.
  • The commit messages follow our commit message guidelines
  • The PR follows our contribution guidelines
  • Code changes follow our coding conventions
  • Tests aren't necessary for this change (we may add static analysis later, separately)
  • Any relevant User Help/Developer documentation is updated; for impactful changes, information is added to the changelog for the intended release
  • CI is green

@GuySartorelli GuySartorelli marked this pull request as draft January 10, 2024 04:27
Copy link
Member

@emteknetnz emteknetnz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot to peer review here so all of the peer review will take multiple peer review sessions to get through. I got about halfway through and got up to (but haven't reviewed) EagerLoadedList

src/Core/Injector/Injector.php Show resolved Hide resolved
src/ORM/ArrayList.php Show resolved Hide resolved
src/Core/Extension.php Show resolved Hide resolved
src/ORM/DataList.php Show resolved Hide resolved
src/ORM/DataList.php Show resolved Hide resolved
src/ORM/DataList.php Show resolved Hide resolved
src/ORM/DataList.php Show resolved Hide resolved
src/ORM/DataList.php Show resolved Hide resolved
src/ORM/DataObject.php Show resolved Hide resolved
src/ORM/ArrayList.php Show resolved Hide resolved
src/ORM/ArrayList.php Show resolved Hide resolved
src/ORM/ArrayList.php Show resolved Hide resolved
src/ORM/ListDecorator.php Show resolved Hide resolved
src/ORM/PaginatedList.php Outdated Show resolved Hide resolved
src/Security/InheritedPermissionsExtension.php Outdated Show resolved Hide resolved
* @return ArrayIterator
*/
public function getIterator(): Traversable
{
Deprecation::notice('5.2.0', 'Will be removed without equivalent functionality');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't be deprecating things in the PR, it's very unrelated. Why are we deprecating this here?

Copy link
Member Author

@GuySartorelli GuySartorelli Jan 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not unrelated. I thought I had added a comment to the PR about this but it looks like I forgot to.

This is being deprecated because:

  • It's not actually needed anymore - the <% control %> template block was removed in CMS 3, and that was the only reason this method is here at all.
  • having the getIterator() here causes problems with identifying the correct type for T being iterated through from getIterator() of subclasses in some IDEs. This was brought up in the original POC in this issue. One solution we considered was adding generic typing to ViewableData but that really is nonsensical outside of the context of lists, and most ViewableData isn't a list.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Add it to the 5.2.0 changelog that it's being deprecated I suppose then.

src/Forms/GridField/GridFieldConfig.php Outdated Show resolved Hide resolved
src/Forms/GridField/GridFieldConfig.php Outdated Show resolved Hide resolved
src/ORM/Filterable.php Outdated Show resolved Hide resolved
There are also a few general corrections to PHPDocs that I noticed along
the way (e.g. adding `|null` when the method is returning a null value.

There are some cases where either the return type or the whole PHPDoc
was duplicated from the parent class - in those cases I've simply
removed the duplication.
@emteknetnz emteknetnz merged commit 357ed7a into silverstripe:5 Jan 17, 2024
15 checks passed
@emteknetnz emteknetnz deleted the pulls/5/add-generics branch January 17, 2024 04:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants