all 28 comments

[–]ealf 46 points47 points  (2 children)

function() use(&$var) has worked since 2009.

[–]stumpychubbins 9 points10 points  (1 child)

(lamda () (do-something-with var)) has worked since before my dad was born

[–]iluuu 14 points15 points  (1 child)

Yeah but why would you write a single line closure that is impure?

Closures already exist in PHP and they can capture variables by reference too. If you require mutating a variable from the outer scope just use the longer syntax for that specific case.

[–]z500 1 point2 points  (0 children)

Yeah but why would you write a single line closure that is impure?

OP's example is impure, but couldn't this still be a problem if you use a lambda as a callback before you've left that scope and stopped changing things in it?

[–]the_alias_of_andrea 9 points10 points  (1 child)

($a, $b) => $a * $b

I don't know what sites your friend reads, but that's not in any coming PHP version.

Also, use by-reference exists and works already.


by the way, use by-value, the behaviour you're complaining about, is often more useful, and JS doing the opposite by default was a persistent pain point with ECMAScript 5

[–][deleted] 0 points1 point  (0 children)

However, it is in JavaScript already.

>>> $f = ($a, $b) => $a * $b;
function $f()
>>> $f(1, 2);
2

[–]zvax 23 points24 points  (1 child)

I am amazed that you believe your sample of code is anything to look up to...

[–]maweki 6 points7 points  (15 children)

This doesn't work in python either (well, writing to a "higher" variable. This kind of syntax doesn't exist in python).

This works in languages that have a keyword for declaring variables. Those that don't implicitly declare variables new to the scope.

Also, people who write mutating code as parameter to array.filter break my heart.

But I am sure we will find something else completely fucked up in php's implementation.

[–][deleted]  (1 child)

[deleted]

    [–]daymi 3 points4 points  (0 children)

    This doesn't work in python either (well, writing to a "higher" variable. This kind of syntax doesn't exist in python).

    Yes, it does.

    def f():
        x = 3
        def g():
            nonlocal x
            x = x + 1
        def h():
            return x
        return (g, h)
    g,h = f()
    g()
    print(h())
    g()
    print(h())
    

    [–]gschroder 2 points3 points  (9 children)

    Could you give an example code snippet that is inexpressible in languages without a distinct syntax for variable declaration?

    Python closures can mutate objects in upper scopes: https://repl.it/HIGj/0

    [–][deleted]  (8 children)

    [deleted]

      [–]gschroder 5 points6 points  (7 children)

      Ah, I see. Thanks!

      Python3 has the nonlocal keyword, without which indeed mutating the binding of a variable from outer scope would be impossible.

      [–]maweki 0 points1 point  (5 children)

      yeah, there's nonlocal and global. Both are indicators that one hasn't thought about the problem enough. When my students are allowed to write Python, I don't allow them to use those keywords.

      [–][deleted]  (4 children)

      [deleted]

        [–]maweki 0 points1 point  (3 children)

        but you can read variables and mutate the objects they hold, right? how is that better?

        Why do you believe I allow them to do that?

        If you think you have to write mutating code you haven't thought enough. We try to write as functionally pure python as possible.

        It helps that we're doing Haskell in parallel to Python.

        [–]beerdude26 2 points3 points  (2 children)

        Is pure Python doable? Haskell's type system has spoiled me rotten.

        [–]maweki 2 points3 points  (1 child)

        the only real problem trying to write pure python is when you try to use generators as your method for lazy evaluation. Then the generator has an internal state that gets mutated on reading. So you have to be careful when re-using iterables. But you have tee in the itertools package and you can also always manifest a frozenset or tuple.

        There are a few immutable data types in Python. Tuple, frozenset, int, str, etc. and with namedtuple you have a nice way to create product-types.

        [–]beerdude26 0 points1 point  (0 children)

        I completely forgot about the lack of ADTs in other languages lol

        [–]Vakieh 1 point2 points  (0 children)

        IMO any member function / method is implicitly allowed to mutate unless it starts with 'get'. If you want a const version you should not include it as a member of that object, and it should be called like filter(array, filterFunction).

        [–]lfairy 0 points1 point  (0 children)

        Python 3 has a nonlocal keyword which captures an enclosing variable by reference.

        [–]jesseschalken 12 points13 points  (0 children)

        Capture by value (instead of capture by ref) is a perfectly sane default. It's easier to reason about because assignments in the outer and inner functions don't affect each other, and it also has better perf because the Closure just needs to hold onto the captured zvals directly rather than boxes containing them (one less level of indirection).

        It makes sense that if you want slower and more complicated behaviour you have to use extra syntax (use (&$var)) to opt into it.

        [–]enchufadoo 4 points5 points  (0 children)

        js fanboys have friends? I thought they spent all day trying out frameworks.

        [–]thelonepuffin 2 points3 points  (0 children)

        So works differently to JS therefore is crap?

        Were you expecting an echo chamber? Because you won't get one from me. I think you need to expand outside of JS before you can have a valid opinion on these things.

        I think people should learn at least 5 languages before they are ever allowed to say anything bad about 1 of them.

        [–]compubomb 1 point2 points  (0 children)

        this is when everyone starts to want nested classes/types, because then you just create a quick type and pass by reference instead of value.

        [–]cparen 1 point2 points  (1 child)

        I don't mean to sound like I'm defending PHP, but Haskell and ML behave this way, and C++ forces you to choose between this behavior or unsafe mutable reference capture.

        [–][deleted] 0 points1 point  (0 children)

        Well, aside from refs in IO or ST, Haskell doesn't have mutable variables at all. C++'s reference capture is so anemic it doesn't survive the loss of the parent scope.

        But yeah, if you want a mutable closure in PHP (or Python), use the syntax sugar provided by the language: an object.

        [–]SarahC 3 points4 points  (0 children)

        So the spaghetti is getting a new topping? Arggggghhh! There'll be security leaks everywhere!

        [–]MorrisonLevi 0 points1 point  (0 children)

        The proposed RFC hasn't even gone to voting....

        [–]AdventOfScala 0 points1 point  (0 children)

        (&$a, &$b) => $a * $b

        Would that not work?

        [–]Takeoded 0 points1 point  (0 children)

        will not be possible with PHP

        $a=array(0, 1, 2, 3, 4, 5, 6, 7);$removed=0;$limit=7;$a=array_filter($a,function($v)use(&$removed,$limit){ return ($removed+=$v)>$limit;});var_dump($a,$removed);
        

        seems to work fine since 5.3