Athari / YaLinqo

Yet Another LINQ to Objects for PHP [Simplified BSD]
https://athari.github.io/YaLinqo
BSD 2-Clause "Simplified" License
439 stars 39 forks source link

Can I employ the 'use' language construct when using a string predicate? #21

Closed BrandonLegault closed 6 years ago

BrandonLegault commented 7 years ago

Let's say I have something like this:

$foo = ['hello' => true];
$bar = ['hello' => 'candy canes'];

I can echo 'candy canes' like this:

foreach (Enumerable::from($foo)
            ->where('$v ==> $v')
            ->select(function ($v, $k) use ($bar) {return $bar[$k];}) as $baz) {
    echo $baz;
}

Is it possible to do something like this though?

foreach (Enumerable::from($foo)
            ->where('$v ==> $v')
            ->select('($v, $k) use ($bar) ==> $bar[$k]') as $baz) {
    echo $baz;
}

Obviously it throws an exception, I'm just wondering if it's possible.

Athari commented 7 years ago

When you pass a string, it's impossible to get the context in which the string is created with local variables and everything else — it's just a plain string. In order to provide this information, you'll have to pass the value and the name of the variable you need explicitly, so instead of

'($v, $k) use ($bar) ==> $bar[$k]'

you'll have to write something like

[ '($v, $k) ==> $bar[$k]', [ 'bar' => $bar ] ]
// or, with default variable names like cN
[ '($v, $k) ==> $c1[$k]', [ $bar ] ]
// vs
function ($v, $k) use ($bar) { return $bar[$k]; }

Doesn't look like a huge improvement, if you ask me. Furthermore, string lambdas are already a questionable feature, so going further that path doesn't sound like a good idea. It shouldn't be that difficult to implement though, just another case for Utils::createLambda.

There're several RFCs proposing proper arrow functions in PHP, but all of them were declined, unfortunately. One time devs said that it reduces readability due to lack of function keyword (WTF), another time because they couldn't implement type hints or something and decided to not implement it at all instead (WTF x2)... Wasn't following it recently, but I hope there's still a chance it'll be done. I mean, Java of all languages, one of the slowest languages to evolve, has arrow functions.

P. S. If you use default argument names like $v and $k, you don't need to provide the list of arguments in string lambdas, so '($v, $k) ==> $k' can be written as just '$k'. Several functions like this are pre-cached, so it also improves performance.

BrandonLegault commented 7 years ago

Thanks for the quick reply. I only started using YaLinqo yesterday so excuse my ignorance, but are these implemented currently?

[ '($v, $k) ==> $bar[$k]', [ 'bar' => $bar ] ] // or, with default variable names like cN [ '($v, $k) ==> $c1[$k]', [ $bar ] ]

I agree that expanding the string lambdas is probably not a good idea because there's a lot of room for error. It's really too bad that PHP doesn't want to implement the arrow functions; I'm a C# developer and their LINQ/Lambda system is the best I've ever seen (and it's extremely easy to read... wtf?).

I wasn't sure if I could just use '$k' or not, good to know.

Athari commented 7 years ago

are these implemented currently?

No.

I wasn't sure if I could just use '$k' or not, good to know.

Default argument names of string lambdas are provided in the documentation. $v and $k are the most common, but in some functions there're others.

Athari commented 6 years ago

Arrow functions aren't happening anytime soon soon, but with create_function being deprecated, the future of string lambdas is dark. Improvements to that feature are pointless at this point.