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

add AbstractCollection abstract class #270

Merged
merged 4 commits into from
Nov 28, 2022
Merged

add AbstractCollection abstract class #270

merged 4 commits into from
Nov 28, 2022

Conversation

drupol
Copy link
Collaborator

@drupol drupol commented Nov 3, 2022

This PR has been created while discussing with @AlexandruGG

This is an alternate way to provide an abstract collection class:

  • without depending on it
  • without altering what's already existing
  • without repeating code all over the place.

Minimal Working Example:

class AAA extends AbstractCollection
{
}

$c = AAA::unfold(static fn (int $a = 0, int $b = 1): array => [$b, $a + $b]);
print_r($c->limit(10)->all());

This PR:

  • Provide an alternate way to have an abstract class in the library
  • Provide ...
  • It breaks backward compatibility
  • Is covered by unit tests
  • Has static analysis tests (psalm, phpstan)
  • Has documentation
  • Is an experimental thing

Related to #268

@drupol
Copy link
Collaborator Author

drupol commented Nov 3, 2022

@BusterNeece What do you think of this option ?

@BusterNeece
Copy link

@drupol I don't mind it, but I think you may have combined two of the methodologies I was talking about in a way that isn't particularly necessary.

Right now, this PR has both an AbstractCollection and wraps an internal collection that's tracked separately. Only one of those things needs to happen, not necessarily both.

Since I'd imagine the static analysis tool will have a fit over the current setup, what I'd propose would be something else:

  • Revert the main Collection class to how it was, with no abstraction; this would be the main class to use if you aren't modifying anything, and it can stay final
  • Make a new, extensible CollectionDecorator class that isn't final, that has this same "wrappedCollection" variable syntax. Almost exactly the way the current abstract is implemented.

This is how Doctrine does it, and it works extremely well for both ensuring the main classes are final, while giving developers an easy branching-off-of point for their own implementations: https://github.com/doctrine/orm/blob/2.13.x/lib/Doctrine/ORM/Decorator/EntityManagerDecorator.php

It also forces that anyone implementing their own won't reference your Collection class directly in their code, but rather will use the CollectionInterface instead.

@BusterNeece
Copy link

@drupol Also, upon further investigation, I'm not sure that the wrappable class should return instances of the interface, but rather something like static. Otherwise, once you do a single operation in your extended class, the returned item is hinted as being a different type than the original. I believe as long as the abstract class extends the interface, this is still considered a subset of the interface's return type.

@drupol
Copy link
Collaborator Author

drupol commented Nov 3, 2022

@drupol Also, upon further investigation, I'm not sure that the wrappable class should return instances of the interface, but rather something like static. Otherwise, once you do a single operation in your extended class, the returned item is hinted as being a different type than the original. I believe as long as the abstract class extends the interface, this is still considered a subset of the interface's return type.

Definitely, but AFAIK returning static is not yet doable in PHP :(

@BusterNeece
Copy link

@drupol static as a return type hint was introduced with PHP 8.

@drupol
Copy link
Collaborator Author

drupol commented Nov 3, 2022

Right, then it would be only available for PHP 8 :)

I'll do the change later in the evening I think.

@drupol
Copy link
Collaborator Author

drupol commented Nov 3, 2022

I updated the PR, now the Minimal Working Example is:

class AAA extends CollectionDecorator
{
}

$decorated = Collection::unfold(static fn (int $a = 0, int $b = 1): array => [$b, $a + $b]);

$c = (new AAA($decorated))->limit(10);

print_r($c->all());

@BusterNeece
Copy link

@drupol For immutability's sake, you should probably return new static($this->wrapped->doThing()) all of those operations, right? So it matches the expected pattern of the current class.

@drupol
Copy link
Collaborator Author

drupol commented Nov 3, 2022

Oooh you're right, going to make the changes.

@BusterNeece
Copy link

@drupol Come to think of it, that would prevent anyone from injecting their own constructors into the extended class...may be worthwhile to make a newInstance function that does the return new static($thing), so you can replace it with whatever other stuff you want to pass in the constructor. Just a thought.

@drupol drupol force-pushed the add-abstract-class-v2 branch from ada6b53 to 7139244 Compare November 4, 2022 09:22
@AlexandruGG
Copy link
Collaborator

I like this approach better than the one in #268!

That being said, I'm still not sure this is actually needed, for the following reason: if anyone wants to add new, useful operations to Collection, then these would be best placed directly in the library and the main class, rather than a custom one. That way everyone benefits from it.

If the argument is that "well, this is a very specific business logic operation and doesn't fit into the library itself", then I would say that it shouldn't be in Collection at all (including an extension of it).

Also this feels like peak irony: https://github.com/loophp/collection/pull/270/files#diff-d82dd67de25323d8122521b137f07152b743665fe3e8b718f99136cc90c88fa3R24. Feels wrong to introduce something new as "deprecated" and tell people not to use it.

@drupol
Copy link
Collaborator Author

drupol commented Nov 4, 2022

I like this approach too, but there's a couple of things to discuss:

  1. How to deal with static constructors? I removed them from the Collection class
  2. Should we add a constructor?
  3. What should be the visibility of the default Collection constructor?
  4. Fix the hundreds of new static analysis issues

@drupol drupol force-pushed the add-abstract-class-v2 branch 17 times, most recently from 86d388c to 0806109 Compare November 7, 2022 07:21
@drupol drupol force-pushed the add-abstract-class-v2 branch 2 times, most recently from 2ea1fff to aa73323 Compare November 16, 2022 21:12
@github-actions github-actions bot added the stale label Nov 22, 2022
@drupol drupol removed the stale label Nov 25, 2022
@loophp loophp deleted a comment from github-actions bot Nov 25, 2022
@drupol drupol force-pushed the add-abstract-class-v2 branch 9 times, most recently from 6898863 to 3bbe432 Compare November 27, 2022 19:39
@drupol
Copy link
Collaborator Author

drupol commented Nov 27, 2022

@AlexandruGG I think it's definitely ready. WDYT?

@drupol drupol force-pushed the add-abstract-class-v2 branch from 3bbe432 to f1cbbd3 Compare November 27, 2022 19:45
@drupol drupol marked this pull request as ready for review November 27, 2022 20:16
@drupol drupol changed the base branch from master to 2.7 November 27, 2022 20:21
@drupol drupol changed the base branch from 2.7 to master November 27, 2022 20:21
@drupol drupol added enhancement New feature or request new feature labels Nov 27, 2022
Copy link
Collaborator

@AlexandruGG AlexandruGG left a comment

Choose a reason for hiding this comment

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

Nice work!

@drupol drupol merged commit 77633d8 into master Nov 28, 2022
@drupol drupol deleted the add-abstract-class-v2 branch November 28, 2022 16:41
@BusterNeece
Copy link

@drupol Thanks for your persistence in working on this. Glad to see this kind of extensibility in the library :)

@drupol
Copy link
Collaborator Author

drupol commented Nov 28, 2022

Thanks you guys ! :) Hope this is going to help some people !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants