Git Product home page Git Product logo

Comments (6)

AlexandruGG avatar AlexandruGG commented on September 15, 2024

Hey @raphaelvoisin,

Thank you for raising this, I will do my best to answer your questions below.

Your questions

1. first() and last() behaviour

For the most part, collection methods return a new collection - this not only promotes a more consistent API but also favours applying multiple operations in succession. The methods that return scalars or keys/values from the collection are documented in the Methods Background section of the docs.

Ideally we would not use first() or last() unless as a last operation performed, and if you really want to extract the value you just do $collection->first()->current(). However, the focus with loophp/collection is on iteration, so not extracting items would be best, similar to how you'd not want to get the value out of a monad.

This being said, I wouldn't be too bothered if we changed the behaviour of these methods in particular, just that it would have to be for a new major version only.

2. head() and tail() behaviour

These methods have consecrated definitions that stem from the list data type in functional programming. Head gives you the first element, tail gives you everything except the first element. See wikipedia.

Indeed tail() has nothing to do with last() and is not meant to be the mirror of head().

3. Missing autocompletion

I'm not sure if this is possible without anything else added, and you should not rely on simply calling ->current() without then checking the type or using an assertion because the method can return null (Psalm and PHPStan will also warn you about this). This is similar to the native PHP function current, which can return false.

You have a few options:
a) use a native PHP assertion: assert($firstElement !== null);
b) use an assertion library like webmozarts/assert: Assert::notNull($firstElement);
c) use an if statement: if ($firstElement !== null) {}

Using a) and c) should give you IDE autocompletion; using b) will not, but I personally prefer it because it works with static analysis and I don't care as much about the autocompletion.

4. contains() vs has()

Indeed these operations have different purposes - you can think of them like this:

  • contains -> check if a given value exists in the collection; plain and simple, nothing more
  • has -> check if the collection has one or more values based on some logic which can use the collection items' keys and/or values; this method takes callbacks with the purpose of specifying that logic

These methods both take variadic (any number of) parameters; combining them into a single one might be possible, but it would make the code messy and break the Single Responsibility Principle to some extent.

On illuminate/collections, it looks like it also uses has - not as an alias of contains, but with a different purpose of checking if a key exists.

My thoughts

I hope the above provides some clarity. Just wanted to add that loophp/collection offers many operations and possibilities, some of which might not be immediately obvious regarding their usefulness. As with learning any new API, it takes a bit of time to get comfortable with them. I can safely say I've probably used less than half of all of them in production code myself, however I do keep finding new opportunities to simplify my code and make it more "declarative" and "functional" by using them.

You've probably already seen the Methods API Docs, but in addition to those examples the unit tests and the static analysis tests can be an additional source of inspiration or clarification.

Lastly, feel free to open PRs for anywhere you feel the documentation is unclear or doesn't provide sufficient info!

from collection.

raphaelvoisin avatar raphaelvoisin commented on September 15, 2024

@AlexandruGG Thank you for your reply :)

1. first() and last() behaviour

Ideally we would not use first() or last() unless as a last operation performed, and if you really want to extract the value you just do $collection->first()->current().

Of course, but processing the first / last element on a list is a use-case so common that I would have kept something simple for them... maybe a personal opinion

2. head() and tail() behaviour

These methods have consecrated definitions that stem from the list data type in functional programming. Head gives you the first element, tail gives you everything except the first element. See wikipedia.

I see your point. BTW, do you know where this definition comes from ? Do you have examples of a similar API, in PHP or other language ?

3. Missing autocompletion

Thank you for explanation, it confirms that I didn't miss something obvious, and I'll continue with a simple if, because I do care about autocompletion 😃

4. contains() vs has()

These methods both take variadic (any number of) parameters; combining them into a single one might be possible, but it would make the code messy and break the Single Responsibility Principle to some extent.

I think it's a question of taste here, but I see your point. I personnaly like to be able to use different parameter types as soon as static analysis is able to check everything, but I understand your choice.

My thoughts

I hope the above provides some clarity. Just wanted to add that loophp/collection offers many operations and possibilities, some of which might not be immediately obvious regarding their usefulness. As with learning any new API, it takes a bit of time to get comfortable with them.

I understand, I wanted to open the debate first to understand some choices. But an intuitive API is quite important too, it's part of the success of a library.
After your explanation, I would say that ->first / ->last is probably what still disturbed me the most. (not being able to get the first/last element easily with autocompletion is a handicap to me 😄), but I understand the rest :)

from collection.

drupol avatar drupol commented on September 15, 2024

Of course, but processing the first / last element on a list is a use-case so common that I would have kept something simple for them... maybe a personal opinion

I agree. When I started building this library, one of the goal was the following: "methods within the library should only returns a CollectionInterface, never something else".
Then, and thanks to @AlexandruGG , I changed my mind and we decided which set of methods could possibly return another type of value.
This means that we can still improve that, nothing is definitely frozen. I also think that this is the right moment to do it, so we can have it ready for the next major release (7.0).

I see your point. BTW, do you know where this definition comes from ? Do you have examples of a similar API, in PHP or other language ?

I started writing this library first for learning purposes because I learned functional programming. These terms comes straight from Haskell.

Many other operations comes from it like foldLeft, foldLeft1, scanRight, scanRight1,...

Thank you for explanation, it confirms that I didn't miss something obvious, and I'll continue with a simple if, because I do care about autocompletion smiley

Sadly yes. I wish I could get rid of them and have a typed collection library working properly. The static analysis tools that we are using are making great effort to get better each days, and with time, these efforts will also benefits this library. Recently PSalm 5 introduced many changes for typing a pipe operator, I guess in the long run this will have a huge impact on this library. We just have to wait a bit.

I think it's a question of taste here, but I see your point. I personnaly like to be able to use different parameter types as soon as static analysis is able to check everything, but I understand your choice.

I never recommend to people I work with to mix arguments types. It's harder to type for static analyzers tools and usually it makes your code even more messy. Unlike other languages we cannot do methods overloading in PHP, so I had to make a choice. You might or might not like it, this is what it is. We can surely improve things, but I had to start somewhere! :)

I understand, I wanted to open the debate first to understand some choices. But an intuitive API is quite important too, it's part of the success of a library.

I think these kind of discussions are a great value. It shows basically the point of view of the newcomers VS the point of view of the maintainers. This is the starting point of doing changes, if necessary. We are definitely open to the discussion as you can most probably feel from these back'n'forth posts. If you really would like to make your point, I also invite you to propose a PR with your changes so we can inline-review your proposal and even discuss further.

Regarding the success of the library, I didn't do it for that precisely. I wrote this library first to learn and share the discoveries I made by learning Haskell and the "lazy" principles. I'm glad that people are using it today, but I never planned to build this library to make it successful.

After your explanation, I would say that ->first / ->last is probably what still disturbed me the most. (not being able to get the first/last element easily with autocompletion is a handicap to me smile), but I understand the rest :)

How about proposing a PR about it and discuss it further? I have the feeling that this is something recurrent that could be easily fixed for the next major release. WDYT?

from collection.

AlexandruGG avatar AlexandruGG commented on September 15, 2024

@drupol thanks for adding to this discussion :).

@raphaelvoisin just to add to what's been said above:

I see your point. BTW, do you know where this definition comes from ? Do you have examples of a similar API, in PHP or other language ?

You will find them across languages that are functional or have incorporated functional elements. See in:

After your explanation, I would say that ->first / ->last is probably what still disturbed me the most. (not being able to get the first/last element easily with autocompletion is a handicap to me 😄), but I understand the rest :)

As Pol mentioned we could change this, but we should keep some consistency. For example, it might be weird if we change head() to not return a Collection, while tail() returns a Collection. At the same time, we cannot change the latter.

Perhaps a solution would be to not make head() be a simple alias for first() anymore, and only make first()/last() return an item from the collection.

If you'd like to contribute this change, have a look into the code and see if you can open a draft PR, we'd be happy to help further from there :)

from collection.

github-actions avatar github-actions commented on September 15, 2024

Since this issue has not had any activity within the last 5 days, I have marked it as stale.
I will close it if no further activity occurs within the next 5 days.

from collection.

AlexandruGG avatar AlexandruGG commented on September 15, 2024

Hey @raphaelvoisin, I hope this was fine to close but let us know if you think it should be kept open.

from collection.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.