PHP 8.5 adds pipe operator

(thephp.foundation)

189 points | by lemper 7 hours ago ago

122 comments

  • xorcist a few seconds ago

    "Essentially the same thing" as a shell pipe, except each function run sequentially in full, keeping output in a variable. So nothing like a shell pipe.

    For short constructions '$out = sort(fn($in)' is really easier to read. For longer you can break them up in multiple lines.

      $_ = fn_a($in)
      $_ = fb_b($_)
      $out = fn_c($_)
    
    Is it really "cognitive overhead" to have the temporary variable explicit? Being explicit can be a virtue.

    I am skeptical to these types of sugar. Often what you really want is an iterator. The ability to hide that need carries clear risk.

  • bapak 6 hours ago

    Meanwhile the JS world has been waiting for 10 years for this proposal, which is still in stage 2 https://github.com/tc39/proposal-pipeline-operator/issues/23...

    • avaq 3 hours ago

      Not only have we been waiting for 10 years, the most likely candidate to go forward is not at all what we wanted when the proposal was created:

      We wanted a pipe operator that would pair well with unary functions (like those created by partial function application, which could get its own syntax), but that got rejected on the premise that it would lead to a programming style that utilizes too many closures[0], and which could divide the ecosystem[1].

      Yet somehow PHP was not limited by these hypotheticals, and simply gave people the feature they wanted, in exactly the form it makes most sense in.

      [0]: https://github.com/tc39/proposal-pipeline-operator/issues/22... [1]: https://github.com/tc39/proposal-pipeline-operator/issues/23...

      • lexicality 2 hours ago

        Am I correct in my understanding that you're saying that the developers of the most widely used JS engine saying "hey we can't see a way to implement this without tanking performance" is a silly hypothetical that should be ignored?

        • jeroenhd 43 minutes ago

          With JS' async/await system basically running on creating temporary closures, I don't think things will change all that much to be honest.

          Furthermore, I don't see why engines should police what is or isn't acceptable performance. Using functional interfaces (map/forEach/etc.) is slower than using for loops in most cases, but that didn't stop them from implementing those interfaces either.

          I don't think there's that much of a performance impact when comparing

              const x = fun1(abc);
              const y = fun2(x);
              const z = fun3(y);
              fun4(z);
          
          and

              abc |> fun1 |> fun2 |> fun3 |> fun4
          
          especially when you end up writing code like

              fun1(abc).then( (x) => fun2(x)).then( (y) => fun3(y)).then((z) => fun4(z))
          
          when using existing language features.
        • avaq 2 hours ago

          They can't implement function application without tanking performance? I find that hard to believe. Especially considering that function application is already a commonly used (and, dare I say: essential) feature in the language, eg: `Math.sqrt(2)`.

          All we're asking for is the ability to rewrite that as `2 |> Math.sqrt`.

          What they're afraid of, my understanding goes, is that people hypothetically, may start leaning more on closures, which themselves perform worse than classes.

          However I'm of the opinion that the engine implementors shouldn't really concern themselves to that extent with how people write their code. People can always write slow code, and that's their own responsibility. So I don't know about "silly", but I don't agree with it.

          Unless I misunderstood and somehow doing function application a little different is actually a really hard problem. Who knows.

      • xixixao 2 hours ago

        I guess partially my fault, but even in the article, you can see how the Hack syntax is much nicer to work with than the functional one.

        Another angle is “how much rewriting does a change require”, in this case, what if I want to add another argument to the rhs function call. (I obv. don’t consider currying and point-free style a good solution)

    • wouldbecouldbe 5 hours ago

      It’s really not needed, syntax sugar. With dots you do almost the same. Php doesn’t have chaining. Adding more and more complexity doesn’t make a language better.

      • chilmers an hour ago

        I'm tired of hearing the exact same arguments, "not needed", "just syntax sugar", "too much complexity", about every new syntax feature that gets added to JS. Somehow, once they are in the language, nobody's head explodes, and people are soon using them and they become uncontroversial.

        If people really this new syntax will make it harder to code in JS, show some evidence. Produce a study on solving representative tasks in a version of the language with and without this feature, showing that it has negative effects on code quality and comprehension.

      • purerandomness 12 minutes ago

        If your team prefers not to use this new optional feature, just enable a PHPStan rule in your CI/CD pipeline that prevents code like this getting merged.

      • bapak 5 hours ago

        Nothing is really needed, C89 was good enough.

        Dots are not the same, nobody wants to use chaining like underscore/lodash allowed because it makes dead code elimination impossible.

        • pjmlp 3 hours ago

          K&R C was good enough for UNIX System V, why bother with C89.

          • boobsbr 2 hours ago

            K&R C was the apex, we've just been going downhill since.

      • Martinussen an hour ago

        When you say chaining, do you mean autoboxing primitives? PHP can definitely do things like `foo()->bar()?->baz()`, but you'd have to wrap an array/string yourself instead of the methods being pulled from a `prototype` to use it there.

      • troupo 5 hours ago

        > With dots you do almost the same.

        Keyword: almost. Pipes don't require you to have many different methods on every possible type: https://news.ycombinator.com/item?id=44794656

      • EGreg 5 hours ago

        It’s not really chaining

        More like thenables / promises

        • wouldbecouldbe 5 hours ago

          It looks like chaining, but with possibility of adding custom functions?

          • bapak 5 hours ago

            It's chaining without having to vary the return of each function. In JS you cannot call 3.myMethod(), but you could with 3 |> myMethod

            • cyco130 4 hours ago

              It requires parentheses `(3).myMethod()` but you can by monkey patching the Number prototype. Very bad idea, but you absolutely can.

      • te_chris 4 hours ago

        Dots call functions on objects, pipe passes arguments to functions. Totally missing the point.

    • fergie 2 hours ago

      Good- the [real world examples of pipes in js](https://github.com/tc39/proposal-pipeline-operator?tab=readm...) are deeply underwhelming IMO.

    • defraudbah 2 hours ago

      do not let me start on monads in golang...

      both are going somewhere and super popular though

    • lacasito25 4 hours ago

      in typescript we can do this

      let res res = op1() res = op2(res.op1) res = op3(res.op2)

      type inference works great, and it is very easy to debug and refactor. In my opinion even more than piping results.

      Javascript has enough features.

  • mort96 2 hours ago

    I'm surprised that the example requires lambdas... What's the purpose of the `|> foo(...)' syntax if the function has to take exactly one operand? Why is it necessary to write this?

        $arr
            |> fn($x) => array_column($x, 'tags')
    
    Why doesn't this work?

        $arr
            |> array_column(..., 'tags')
    
    And when that doesn't work, why doesn't this work?

        $arr
            |> array_unique
    • ptx an hour ago

      Apparently "foo(...)" is just the PHP syntax for a function reference, according to the "first-class callable" RFC [1] linked from the article.

      So where in Python you would say e.g.

        callbacks = [f, g]
      
      PHP requires the syntax

        $callbacks = [f(...), g(...)];
      
      As for the purpose of the feature as a whole, although it seems like it could be replaced with function composition as mentioned at the end of the article, and the function composition could be implemented with a utility function instead of dedicated syntax, the advantage of adding these operators is apparently [2] performance (fewer function calls) and facilitating static type-checking.

      [1] https://wiki.php.net/rfc/first_class_callable_syntax

      [2] https://wiki.php.net/rfc/function-composition#why_in_the_eng...

    • tossandthrow 2 hours ago

      It is to interject the chained value at the right position in the function.

      They write that elixir has a slightly fancier version, it is likely around this, they mean (where elixir has first class support for arity > 1 functions)

      • mort96 2 hours ago

        But the example suggests that it can't interject the chained value at the right position; if that was the case, the example would've been written as `|> array_column('tags', ...)`.

        • wink an hour ago

          yeah that sounds weird. defaulting to the first (or only) parameter would have made sense.

  • abrookewood 4 hours ago

    I love the pipe operator - one of the things I dig about Elixir though many languages have it. It's so much easier to reason about:

      $result = $arr
        |> fn($x) => array_column($x, 'tags')
        |> fn($x) => array_merge(...$x)
        |> array_unique(...)
        |> array_values(...)
    
    VS array_values(array_unique(array_merge(...array_column($arr, 'tags'))));
    • qwertox 4 hours ago

      I don't see how this is hard to reason about, assuming this is the resulting code when using variables:

        $tags        = ...array_column($arr, 'tags');
        $merged_tags = array_merge($tags);
        $unique_tags = array_unique($merged_tags);
        $tag_values  = array_values($unique_tags);
      
      It also makes it easier to inspect the values after each step.
      • jeroenhd 2 hours ago

        Correctly naming things is one of the harder challenges in computer programming. Putting effort into naming intermediates that you're going to throw out is a waste. Plus, the more variables you introduce, the more likely you'll accidentally re-use a variable name somewhere down the line.

        With PHP allowing variable initialization in one branch but not the other, and continuing execution by default when an undeclared variable is passed, declaring more variables can lead to an annoying class of bugs that would require significant (breaking) changes to the core language to completely eliminate.

      • agos 2 hours ago

        I don't think inspecting this is easier than adding |> IO.inspect() to a pipe chain

        • harg 2 hours ago

          Or putting `|> dbg()` at the end and let it print the value at every step of the chain

      • lawn an hour ago

        Introducing a new variable every single line adda a bunch of cognitive load compared to the pipe operator.

        It's much easier skim with the pipe operator and it's more robust too (for example reordering is a pain with variables, it's easy to introduce errors).

      • cess11 2 hours ago

        Such variable threading tends to be harder to skim through in production code, the intermediates become noise that's harder to filter out than a repeated symbol like |>.

        Preferably you should also be sure that the functions are compatible with the data type going in and only rarely have to break it to dump data mid-chain. If you expect that kind of erroring it's likely a builder-chain with -> is a better alternative and do logging in the methods.

      • r34 3 hours ago

        Your version includes 4 variables. Pipes don't create those intermediate variables, so they are more memory efficient.

        Readability is mostly matter of habit. One reads easily what he/she is used to read.

        • qwertox 3 hours ago

          It's true that pipes are more readable, and for many cases they will be the better option, but the example of nested functions just doesn't hold.

          That's like saying someone would use this:

             $result = $arr |> fn($x) => array_column($x, 'tags') |> fn($x) => array_merge(...$x) |> array_unique(...) |> array_values(...)
          
          which is harder to reason about than the nested functions.

             array_values( array_unique( array_merge( ...array_column($arr, 'tags') ) ) );
          
          or

             array_values(
               array_unique(
                 array_merge(
                   ...array_column($arr, 'tags')
                 )
               )
             );
          • account42 19 minutes ago

            The pipe syntax is much more readable than nested function calls when you need additional arguments for intermediate functions. With nested functions it becomes hard to see which functions those arguments belong to even if you try to help it with formatting.

          • navalino 3 hours ago

            It is more readable and better option — you have to parse it from the innermost function to the outermost just to understand what it's doing. With the pipe, it's more straightforward: you read it step by step — do this, then that, then the next — just like how you'd naturally read instructions.

        • girvo 3 hours ago

          > so they are more memory efficient

          They can be. It depends on the language, interpreter, compiler, and whether you do anything with those intermediate variables and the optimiser can get rid of them.

          • r34 3 hours ago

            I thought we are talking about PHP8.5:)

    • someothherguyy 3 hours ago

      > It's so much easier to reason about

      Is it though? I don't think so.

      • andrewflnr 3 hours ago

        It tends to work a little better in Elixir, because you very rarely have to include one-off lambdas in your pipeline. The standard library functions are designed to work with the pipeline operator, where the thing you probably want to thread through is usually the first argument.

  • gbalduzzi 5 hours ago

    I like it.

    I really believe the thing PHP needs the most is a rework of string / array functions to make them more consistent and chain able. Now they are at least chainable.

    I'm not a fan of the ... syntax though, especially when mixed in the same chain with the spread operator

    • account42 an hour ago

      The syntax could be improved by allowing you to omit the (...) part entirely for single argument functions and using currying for functions that need additional arguments. So you would end up with something like:

        $result = $arr
            |> select_column('tags')         // Gets an array of arrays
            |> fn($x) => array_merge(...$x)  // Flatten into one big array
            |> array_unique                  // Remove duplicates
            |> array_value                   // Reindex the array.
    • colecut 4 hours ago

      PHP string / array functions are consistent.

      string functions use (haystack, needle) and array functions use (needle, haystack)

      because that's the way the underlying C libraries also worked

      • Einenlum 4 hours ago

        They're not though.

        array_filter takes (arr, callback)

        https://www.php.net/manual/en/function.array-filter.php

        array_map takes (callback, arr)

        https://www.php.net/manual/en/function.array-map.php

        • exasperaited 4 hours ago

          This is "english-sentence-order-consistent", as it goes.

          Array filter is "filter this array with this function".

          Array map is "map this function over this array".

          But I agree any replacement function should be consistent with Haskell.

          • eurleif 3 hours ago

            One can construct English sentences in the opposite order. There is no singular "English sentence order".

            "Filter for this function in this array"

            "Map over this array with this function"

            • exasperaited 3 hours ago

              Right, but these are both more unwieldy.

              One filters something with something else, in the real world. Filter water with a mesh etc.

              And (in maths, at least) one maps something onto something else. (And less commonly one maps an area onto paper etc.)

              Just because you can make your two sentences does not make them natural word order.

              • quietbritishjim 2 hours ago

                > And (in maths, at least) one maps something onto something else.

                Yes, but that's the opposite of what you said earlier. You might map x onto 2*x, for example. Or, if you're talking about a collection, you might map the integers 0..10 on to double their value. Data first, then the way you're manipulating it. I'm a mathematician and this is what makes sense to me.

                I would only say "map this function..." if the function itself is being manipulated somehow (mapped onto some other value).

              • hnlmorg 2 hours ago

                When you consider that PHP is used by hundreds of thousands of non-native English speakers, I don’t really think you can make a legitimate claim that “English sentence order” trumps “consistent argument ordering”.

                There’s enough viral videos online of how even neighbouring European counties order common sentences differently. Even little things like reading the time (half past the previous hour vs half to the next hour) and counting is written differently in different languages.

                So modelling the order of parameters based on English vernacular doesn’t make a whole lot of sense for programming languages used by programmers of all nationalities.

                • exasperaited an hour ago

                  > When you consider that PHP is used by hundreds of thousands of non-native English speakers, I don’t really think you can make a legitimate claim that “English sentence order” trumps “consistent argument ordering”.

                  Well that’s good, because I didn’t.

      • Y-bar 2 hours ago

        > because that's the way the underlying C libraries also worked

        I feel like this is a weak defence of the internally inconsistent behaviour. As someone who has been programming with PHP for over twenty years now, most of them professionally, I still cannot remember the needle/haystack order in these functions, I thank intellisense for keeping me sane here.

        As evident with this pipe operator, or with for example Attributes, PHP does not need to religiously follow the C way of doing things, so why not improve it instead of dismissing it as "it is the way it is because that is the way it was"?

      • account42 an hour ago

        So they are consistent because they are consistently inconsistent??

        There isn't a good reason for PHP to have inherited C's issues here.

    • noduerme 4 hours ago

      Agree, the ... syntax feels confusing when each fn($x) in the example uses $x as the name of its argument.

      My initial instinct would be to write like this:

      `$result = $arr

          |> fn($arr) => array_column($arr, 'tags') // Gets an array of arrays
      
          |> fn($cols) => array_merge(...$cols)`
      
      Which makes me wonder how this handles scope. I'd imagine the interior of some chained function can't reference the input $arr, right? Does it allow pass by reference?
      • Einenlum 4 hours ago

        You can write it this way. The parameter name is arbitrary. And no, to my knowledge you can't access the var from the previous scope

      • cess11 3 hours ago

        You can do

             function ($parameter) use ($data) { ... }
        
        to capture stuff from the local environment.

        Edit: And you can pass by reference:

           > $stuff = [1]
           = [
               1,
             ]
        
           > $fn = function ($par) use (&$stuff) { $stuff[] = $par; }
           = Closure($par) {#3980 …2}
        
           > $fn(2)
           = null
        
           > $stuff
           = [
               1,
               2,
             ]
        
        
        Never done it in practice, though, not sure if there are any footguns besides the obvious hazards in remote mutation.
  • sandreas 5 hours 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 42 minutes ago

      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.

    • cess11 4 hours ago

      PHP has traits, just invent that API, put it in a trait and add it to your data classes.

    • troupo 5 hours ago

      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

  • defraudbah 2 hours ago

    PHP is that weird beast that no one wants to praise and yet it works tremendously well for those who manage to tame it.

    I would likely never touch it as there are too many languages to use and what I know is more than enough to do my job, but I am super excited to see languages like PHP that aren't mainstream in my bubble to keep evolving

    • nolok an hour ago

      I'm not tempting you do to it or anything, but I want to say given your point of view, if one day you need a crude+ app and try to do it using laravel, you might be really surprised by what modern php actually is.

      There was a point were I thought the language and it ecosystem was going down the drain but then they recovered and modern php is 90% what do you want to do and don't worry about the how, it's easy.

      I don't use it much anymore, but every time I do all I see are possibilities.

      • defraudbah 38 minutes ago

        what about deployment? I assume I need to scp files like Python or keep everything in a single giant PHP file? is that an option?

        • nolok 29 minutes ago

          Deployment these days is essentially git pull && composer update

          Of course not if you use vm or serverless or whatever like this, but for a basic here is my crude app, that's what you do.

          Or if you want to go old school sure, just scp that directory, it still works like it did 30 years ago.

  • phplovesong 5 hours ago

    The stdlib is so inconsistent this will be a nightmare.

    Optionally with a better language you know what order params as passed (array_map / array_filter), but in PHP its an coin toss.

    This feels very bolted on and not suited for the stdlib at all.

    PHP devs should instead FIRST focus on full unicode support (no, the mb_real_uppercase wont do), and only then focus on a new namespaced stdlib with better design.

    • foul 3 hours ago

      >The stdlib is so inconsistent this will be a nightmare.

      I think that callables will end with being useless in this context and everyone will pipe closures to put that $x wherever the stdlib imposes.

    • Einenlum 4 hours ago

      This.

      We definitely need a better stdlib with appropriate data structures

      • allan_s an hour ago

        it's a chicken and the egg problem

        I think initiative like this drive a need for a more consistent, and even if slow, PHP has been deprecated/reworking its stdlib so I'm hopeful on this.

  • rogue7 an hour ago

    This looks neat. However since I read about Koka's dot selection [0], I keep thinking that this is an even neater syntax:

    fun showit( s : string )

      s.encode(3).count.println
    
    However, this is of course impossible to implement in most languages as the dot is already meaningful for something else.

    [0] https://koka-lang.github.io/koka/doc/book.html#sec-dot

    • jprafael an hour ago

      That syntax is very clean when it works. I think however the limitation of not being able to pipe arguments into 2nd, 3rd, ..., positions and keyword arguments, or variadic explosion like the syntax showcased in the article makes it less powerful.

      Are there other syntax helpers in that language to overcome this?

      • account42 11 minutes ago

        It still makes sense to have a clean syntax for the simple case. You can use currying (with or without first class language support) to handle more complex cases or just fall back to good old function composition or even loops.

    • throw-the-towel an hour ago

      I think this is called uniform function call syntax.

  • mappu 3 hours ago

    Every single one of those steps buffers into a temporary variable - this isn't efficient like a bash pipe.

    • quietbritishjim 3 hours ago

      Genuine question from a non-PHP user:

      Does PHP support iterator-like objects? Like Python I mean, where mydict.values() produces values on demand, not immediately realised as a list. Or are all steps necessarily guaranteed to be fully realised into a complete list?

      • Timwi 2 hours ago

        The section where the article mentions function composition implies that it doesn't. The article says that compositing the functions before passing them into map would be an optimization. I take that to mean that without the composition, each map fully processes an array passed to it from the previous map, and the first map fully reads the whole file in the example. If it were iterable, the function composition would make no difference compared to a pipeline of multiple maps.

        Meanwhile, I'm confused as to why it sometimes says “map” and sometimes “array_map”. The latter is what I'm familiar with and I know that it operates on a whole array with no lazy evaluation. If “map” isn't just a shorthand and actually creates a lazy-evaluated iterable, then I'm confused as to why the function composition would make any difference.

      • severak_cz 3 hours ago
      • throw_m239339 3 hours ago

        PHP does have generators and iterators yes, although I personally rarely use them directly.

  • zelphirkalt 2 hours ago

    Hm. Looks like PHP actually got a modern feature there, and it is looking decent, not like the usual new PHP feature, that just looks worse than in other languages, where it has been standard. Consider me surprised, that they seem to have done a good job on this one. And they even dodged the bullet with making the right side callables, which avoids the trap of inventing new types of expressions and then not covering all cases.

  • mhh__ 32 minutes ago

    Every language should have this.

    Forget about transforming existing code, it makes new code much more reasonable (the urge to come up with OOPslop is much weaker when functions are trivial) — they're programming languages for a reason.

  • librasteve 5 hours ago

    raku has had feed operators like this since its inception

      # pipeline functional style
      (1..5)
        ==> map { $_ * 2 }
        ==> grep { $_ > 5 }
        ==> say();              # (6 8 10)
    
      # method chain OO style
      (1..5)
        .map( * * 2)
        .grep( * > 5)
        .say;                   # (6 8 10)
    
    uses ==> and <== for leftward

    true it is syntax sugar, but often the pipe feed is quite useful to make chaining very obvious

    https://docs.raku.org/language/operators#infix_==%3E

  • ds_ an hour ago

    One of the many joys of working with Clojure https://clojure.org/guides/threading_macros

  • habibur 4 hours ago

    I tried to emulate something similar with PHP at one point. But the problem with PHP was parameter order. Especially in functions like array_key_exists() the array element is the 2nd parameter, while pipe operator expects the object to work on be the 1st parameter, the array in these cases.

    I believe they have solved this problem by now. Though no idea how.

    • kijin 4 hours ago

      The usual solution is to wrap it with a closure.

          function($x) { return array_key_exists('needle', $x); }
      
      Or using the arrow function syntax:

          fn($x) => array_key_exists('needle', $x)
      
      The same trick also helps when you need to use functions with mandatory extra parameters, functions with pass-by-value parameters, etc.
  • dev_l1x_be 2 hours ago

    Rust is next? Jokes aside, pipe operators in programming languages have a interesting side effect of enabling railway oriented programming that I miss the most when not working in F#.

    • simonask 33 minutes ago

      The way function/trait resolution works in Rust, it's actually already quite idiomatic to code in this style (just using the dot operator). The standard library Iterator is a great example of this. :-)

      I don't think there's any significant push for an even terser syntax at the moment.

  • pknerd 2 hours ago

    Am I the only one who found it ugly?

  • ChocolateGod 4 hours ago

    Why not just make types psuedo-objects?

    $myString.trim().replace("w", "h");

    Which has the advantage of also offering a clean alternative to the fragmented stdlib.

    • account42 3 minutes ago

      Because duplicating the stdlib is probably not a good idea.

    • williamdclt 2 hours ago

      > Why not just make types psuedo-objects?

      With this sort of "just" I could build Paris out of matchsticks

    • reddalo 4 hours ago

      I agree. But in PHP it would probably be like this:

      $myString->trim()->replace("w", "h");

      • troupo 4 hours ago

        Because pipes don't care about the type your function returns. And you don't need hundreds of methods on each type just in case. You just pipe the result of the previous function to the next one.

        And those functions can be business logic, or validation, or... Not just object methods

  • someothherguyy 4 hours ago

    composition would be much nicer than this, maybe soon

  • cpursley 2 hours ago

    Your move, JavaScript.

  • DataDaemon 4 hours ago

    This will be the year of PHP. People are tired of JS.

    • Timwi 2 hours ago

      I am indeed tired of JS; however, I'm not a fan of PHP either. I like the new pipe syntax as a concept, but when added to an already uncomfortable overall programming environment, it can only provide mild relief.

    • rambambram 2 hours ago

      You mean the fourth decade of PHP.

    • beardyw 3 hours ago

      I admire your conviction.

  • BiteCode_dev 2 hours ago

    It's lovely to see how PHP keeps growing. It's far from what it was when I used to code with it in V3. I really thought it would be lost in its bad design, but the core devs kept at it, and it is, indeed, a pretty decent language now.

  • cess11 4 hours ago

    "A major limitation of the pipe operator is that all the callables in the chain must accept only one required parameter.

    For built-in functions, if the function does not accept any parameters, it cannot be used in a chain. For user-land PHP functions, passing a parameter to a function that does not accept any parameters does not cause an error, and it is silently ignored.

    With the pipe operator, the return value of the previous expression or the callable is always passed as the first parameter to the next callable. It is not possible to change the position of the parameter."

    https://php.watch/versions/8.5/pipe-operator

    In the light of these limitations I would not call the Elixir implementation "slightly fancier".

    I'm not so sure I'll be upgrading my local PHP version just for this but it's nice that they are adding it, I'm sure there is a lot of library code that would look much better if rewritten into this style.

  • JaggerJo 4 hours ago

    Thanks F#!

  • ossusermivami 4 hours ago

    i wish python had something liek that to be honest

    • kh_hk 29 minutes ago

      one can dream but i wouldn't keep high hopes. I feel functional patterns are left as second class citizens in python.

  • keyle 5 hours ago

    C'mon Dart! Follow up please. Go is a lost cause...

    • tayo42 5 hours ago

      I feel like a kindergartener writing go. I wish another language got popular in the space go is used for.

      • jillesvangurp 2 hours ago

        Kotlin is shaping up slowly. It's kind of there with a native compiler that is getting better with each release and decent multiplatform libraries. It's a bit weak with support for native libraries and posix stuff. But that's a fixable issue; it just needs more people working on that.

        For example ktor (one of the server frameworks) can actually work with Kotlin native but it's not that well supported. This is not using Graal or any of the JVM stuff at runtime (which of course is also a viable path but a lot more heavyweight). With Kotlin native, the Kotlin compiler compiles directly to native code and uses multiplatform libraries with native implementations. There is no Java standard library and none of the jvm libraries are used.

        The same compiler is also powering IOS native with Compose multiplatform. On IOS libraries are a bit more comprehensive and it's starting to become a proper alternative to things like flutter and react native. It also has pretty decent objectc and swift integration (both ways) that they are currently working on improving.

        In any case, it's pretty easy to write a command line thingy in Kotlin. Use Klikt or similar for command line argument parsing.

        Jetbrains seems to be neglecting this a bit for some reason. It's a bit of a blind spot in my view. Their wasm support has similar issues. Works great in browsers (and supported with compose as well) but it's not a really obvious choice for serverless stuff or edge computing just yet; mainly because of the library support.

        Swift is a bit more obvious but has the issue that Apple seems to think of it as a library for promoting vendor lockin on their OS rather than as a general purpose language. Both have quite a bit of potential to compete with Go for system programming tasks.

  • ioma8 4 hours ago

    The syntax is ugly as hell.

    • JohnKemeny 2 hours ago

      Thank you for your insight.

    • frankzander 3 hours ago

      Amen ... I mean PHP could have been such a good language if the syntax wouldn't be such a show stopper.

  • lordofgibbons 5 hours ago

    Why doesn't PHP remove the horrid $ symbol for variables and the -> symbol for calling methods? I think those alone would do a lot more for its perception and adoption than adding the pipe operator.

    • jeroenhd 2 hours ago

      Same reason C doesn't introduce classes and C++ doesn't remove pointers: it's a) part of the core language and b) extremely inconsequential for any serious developer.

      I actually like the clarity these dollar signs add in a code base. Makes it easier to recognise (dynamic) functions, and makes it harder to accidentally shadow methods.

      Other languages will let you do `const Math = {}` and nuke the entire math library, or write stuff like `int fopen = 0;` to make the fopen method call inaccessible in that scope. With PHP, you don't need to restrict your variable name to "something that hopefully won't conflict with an obscure method".

      The -> is a leftover from an older programming language that I'd rather have replaced by a ., but not at the cost of breaking existing code (which it surely would).

      • asddubs an hour ago

        I do also appreciate that php has an explicit string concat operator rather than overloading +. Though of course it could just use another symbol for that to get rid of -> if we're talking about time travel. As it stands, you can't really do $obj.method(), because method() could be a function returning a string as well, so it's ambiguous

    • nolok 43 minutes ago

      Because back compat' is a very strong feature of the language, same reason "match" was created instead of replacing switch.

      As a result, taking a php 5.2 script and moving it up to 8.5 is super easy, and taking a PHP 4 one is barely harder only longer (since it probably uses the horrors that were register_globals and co).

      Ultimately, I prefer this than a fragmented ecosystem impossible to resolve.

    • phatskat 4 hours ago

      I actually don’t mind them, and I’ve been out of daily PHP work for a few years now. When I see people denote internal variables with _ or elements with $ in JS, it rubs me the wrong way, but in PHP the $ is kind of nice.

      I also prefer the look of ->, it’s _cool_

      • kijin 4 hours ago

        Other languages have all sorts of oversized arrows, like ==> and >>>.

        -> in PHP and C++ looks clean by comparison.

        I'll never forgive them for the brain fart they made of the namespace separator, though.

        • esskay 3 hours ago

          What would the alternative for a namespace separator be? The backslashes work well with PSR-4 to give a logical visual of the expected directory structure.

        • LeonM 3 hours ago

          > I'll never forgive them for the brain fart they made of the namespace separator, though.

          You mean the backslash? What's wrong with that?

    • ahofmann 3 hours ago

      I honestly don't understand this. The syntax is one of the most boring parts of a programming language. It is solved by the IDE (and now LLMs). I don't care about syntax, I care about what I can build. Since the beginning of time people argue about things like tabs vs. spaces, or the dollar sign and I honestly don't understand why that is. It just doesn't matter.

      Just to be clear: consistency does very much matter. The mental load of reading totally different styles of code is awful and a waste of energy.

      • Timwi 2 hours ago

        Readability (and hence, maintainability) is definitely a factor in decisions like this. In the particular case of the pipe operator though, the article does mention something it lets you do that you couldn't do before: in a context where only an expression is allowed (such as match), you can now do things that previously would not have worked because it would have required temporary variables.

    • throw_m239339 2 hours ago

      > Why doesn't PHP remove the horrid $ symbol for variables and the -> symbol for calling methods? I think those alone would do a lot more for its perception and adoption than adding the pipe operator.

      Because it simply can't do that in a retro-compatible way. -> isn't so bad, C/C++ uses that as well. as for $ I guess it came from Perl. The point is already used for string concatenation, where other languages would overload the + operator.