| ▲ | sandreas 8 days ago |
| While I appreciate the effort and like the approach in general, in this use case I really would prefer extensions / extension functions (like in Kotlin[1]) or an IEnumerable / iterator approach (like in C#). $arr = [
new Widget(tags: ['a', 'b', 'c']),
new Widget(tags: ['c', 'd', 'e']),
new Widget(tags: ['x', 'y', 'a']),
];
$result = $arr
|> fn($x) => array_column($x, 'tags') // Gets an array of arrays
|> fn($x) => array_merge(...$x) // Flatten into one big array
|> array_unique(...) // Remove duplicates
|> array_values(...) // Reindex the array.
;
feels much more complex than writing $result = $arr->column('tags')->flatten()->unique()->values()
having array extension methods for column, flatten, unique and values.1: https://kotlinlang.org/docs/extensions.html#extension-functi... |
|
| ▲ | hn8726 7 days ago | parent | next [-] |
| Kotlin also has extensions function `let` (and a couple of variants) which let you chain arbitrary methods: ```
val arr = ...
val result = arr
.let { column(it, "tags")
.let { merge(it) }
.let { unique(it) }
.let { values(it) }
``` You add function references for single-argument functions too: ```
arr.let(::unique) // or (List<>::unique), depends on the function
``` all without adding a special language construct. |
|
| ▲ | troupo 8 days ago | parent | prev | next [-] |
| The advantage is that pipes don't care about the type of the return value. Let's say you add a reduce in the middle of that chain. With extension methods that would be the last one you call in the chain. With pipes you'd just pipe the result into the next function |
| |
| ▲ | sandreas 7 days ago | parent [-] | | Yeah, I agree. That's an advantage of pipes - although much harder to read and write than chained methods in my opinion. The use-case in the article could still be solved easier with extension methods in my opinion :-) | | |
| ▲ | troupo 7 days ago | parent [-] | | Yeah, the examples should also show that you can use arbitrary functions, not just library functions. E.g. your own business logic, validation etc. |
|
|
|
| ▲ | cess11 8 days ago | parent | prev | next [-] |
| PHP has traits, just invent that API, put it in a trait and add it to your data classes. |
| |
| ▲ | sandreas 7 days ago | parent | next [-] | | Well, while traits might be a workaround for certain use cases, simple arrays with scalar data types could not be extended via traits. While I know that there are Collection classes in Symfony, Laravel, etc., I'm not a huge fan of wrapping a PHP array with a class to get method chaining, even with generators. $sum = [1, 2, 3]->filter(fn($x) => $x%2!= 0)->concat([5,7])->sum();
cannot be solved with traits. Additionally, I think traits should be used very carefully and they do not have this many use cases that aren't a code smell to me. | |
| ▲ | stefanfisk 7 days ago | parent | prev [-] | | How would that work if a library supplies a function that takes a string and returns an array? I can’t make it use my array class. | | |
| ▲ | cess11 7 days ago | parent [-] | | Could you give a realistic example? The PHP pipes as described in the articles about it will require a bunch of wrapping anyway so you could just do that. There are several alternatives, from a function or method that just converts from raw array to class, to abstractions involving stuff like __invoke, __call, dispatchers and such. Also the expectation to not have to put facades on libraries is a bit suspicious, in my experience it is very common. I find it unlikely you actually want to use raw arrays instead of leveraging type guards in your code. | | |
| ▲ | stefanfisk 7 days ago | parent [-] | | If I use Laravel’s Str in an app where both myself and a third party library want to add a chainable method, how do I make the API make sense? We can’t both subclass Str. The only option I see is Macroable and that’s a rabbit hole I’d rather avoid. | | |
| ▲ | cess11 7 days ago | parent [-] | | The Laravel developers expect you to use Stringable::macro if you want to extend their 'fluent' API, and if you're working in an organisation that builds with the Laravel toolchain that's probably what's least surprising to the other members. I'm still not clear over what you want to do or why the third party library expects there to be a hacked in 'fluent' method on the Stringable. Personally I'm not a fan of the Str/Stringable API:s, I find it weird and confusing to mix methods for file paths, strings, encryption and so on. Actually, I'm more of a Symfony person for reasons like this. |
|
|
|
|
|
| ▲ | Contortion 7 days ago | parent | prev [-] |
| Basically what Collections do in Laravel. |
| |
| ▲ | sandreas 7 days ago | parent [-] | | Exactly... similar in Symfony. While converting arrays to collection-object is a suitable option that does work, it would feel much more "native", if there were extension methods for Iterable / Traversable. | | |
| ▲ | Contortion 3 days ago | parent [-] | | Agreed. Like in JS and Java, it would be a lot nicer if the language itself had the chainable methods. |
|
|