4 ms·
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 a
by sandreas 1y 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-functions https://kotlinlang.org/docs/extensions.html#extension-functi...
- troupo 1y agoThe 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 1y agoYeah, 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 1y agoYeah, the examples should also show that you can use arbitrary functions, not just library functions. E.g. your own business logic, validation etc.
- cess11 1y agoPHP has traits, just invent that API, put it in a trait and add it to your data classes.
- stefanfisk 1y agoHow 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 1y agoCould 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 1y agoIf 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 1y agoThe 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 1y agoBasically what Collections do in Laravel.
- sandreas 1y agoExactly... 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 1y agoAgreed. Like in JS and Java, it would be a lot nicer if the language itself had the chainable methods.
- hn8726 1y agoKotlin 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.