On Tue, May 3, 2016 at 1:28 PM, Fleshgrinder <p...@fleshgrinder.com> wrote:

> On 5/3/2016 8:57 PM, Sara Golemon wrote:
> > Ooops, missed a negation when I typed it out.
> >
> > "Pretending that poorly designed libraries DON'T exist is naîve."
> >
>
> I am not pretending that they do not exist, quite the contrary, I
> explicitly stated that they exist and that I fear that this syntactic
> sugar yields more of them in the future.
>
> On 5/3/2016 8:57 PM, Sara Golemon wrote:
> > As I've said already.  Yes, intermediate variables do address this
> > style of coding.  Yes, this proposal is syntactic sugar.
> >
> > Intermediate variables also add cognitive overhead of their own in
> > cataloging all the various intermediates used in a large function.  By
> > removing the explicit intermediate variables and replacing them with
> > unnamed temporaries, the code becomes easier to read because there's
> > less unnecessary assignments cluttering up the space.
> >
>
> Still waiting for a real life example that illustrates exactly that. All
> examples and code I have seen so far is either extremely constructed
> (the request-application-response thingy that is now part of the RFC) or
> can be trivially rewritten to be super expressive and readable (the
> original from the RFC and most in this thread).
>

I have to disagree, I haven't seen an example of rewriting the original
example from the RFC in a more expressive AND readable way. Yes, you can
use lots of intermediate variables, but this makes the code HARDER to read
QUICKLY which is entirely the point of a syntatic sugar addition like this.
Syntactic sugar makes a language sweeter, and more palatable. Like cane
sugar makes your cookies taste good, but doesn't make them more nutritious.


>
>   $request = getGlobals()
>    |> parseRequest($$)
>    |> buildPsr7Request($$);
>
> Ask, don't tell!


>   final class RequestBuilder {
>
>     public static function fromGlobals() {
>       return new static($_GLOBALS);
>     }
>
>     public function buildPsr7Request() {
>       $parsed_request = $this->parseRequest();
>       return new Psr7Request($parsed_request);
>     }
>
>   }
>
>   $request = RequestBuilder::fromGlobals()->buildPsr7Request();
>

This breaks dependency injection, and makes testing harder.  You now depend
on an array of data which is accessed internally, and can only minimally
control it's contents in a testing environment.


>
>   $response = loadConfig()
>    |> buildDic($$)
>    |> getApp($$)
>    |> getRouter($app)
>    |> getDispatcher($$, $request)
>    |> dispatchBusinessLogic($$, $request, new Response())
>    |> renderResponse($$)
>    |> buildPsr7Response($$)
>    |> emit($$);
>
> Ask, don't tell!
>
>   final class ResponseBuilder {
>
>     public static function fromGlobals() {
>       return new static($_GLOBALS);
>     }
>
>     public function build() {
>       $this->loadConfig();
>       $this->buildDic();
>       $this->buildApp();
>       $this->buildRouter();
>       $this->buildDispatcher();
>       $this->dispatchBusinessLogic();
>       $this->parseResponse();
>
>       return $this->response;
>     }
>
>   }
>
>   $response = ResponseBuilder::fromGlobals()->build();
>

Again, how do I dependency inject a config during testing to make sure I
build the dic correctly? I'm assuming you're using a bunch of temporary
properties? Also you just made adding a step significantly harder, what if
from building the app, I need to build another layer build for the router,
for |> I add ONE line of code, for yours I edit the build function in the
right location, and change the build router function to load from a
different property, and build another boilerplate function to build this
new thing, and add another property to hold this new thing... WHOA that's a
lot more steps, and a MUCH higher risk of a mistake!


>
> The third is exactly the same ...
>
> Now my favorite:
>
>   $ret =
>     array_merge(
>       $ret,
>       getFileArg(
>         array_map(
>           function ($x) use ($arg) { return $arg . '/' . $x; },
>           array_filter(
>             scandir($arg),
>             function ($x) { return $x !== '.' && $x !== '..'); }
>           )
>         )
>       )
>     );
>
> I already rewrote it in another message but once more with the most
> relevant parts of my original message:
>
> array_filter with O(n)
>
> array_map with O(n)
>
> array_merge with O(∑ array_i, i != 1) and in our case O(n) where n
> equals the total count of elements in $files/$$.
>
> In my universe `getFileArg` (note the absence of a plural form) would
> operate on a single path and not on an array of paths:
>
>   foreach (new DirectoryIterator($arg) as $path) {
>     if ($path->isDot() === false) {
>       $ret[] = getFileArg($arg . DIRECTORY_SEPARATOR . $path);
>     }
>   }
>

Again, you're solution is to use OOP, but the pipe operator's purpose is to
make procedural code cleaner. Not one of your solutions maintained a
procedural interface, and therefore is not an argument against the |>
operator. The purpose of this operator is syntactic sugar, which "is syntax
within a programming language that is designed to make things easier to
read or to express. It makes the language "sweeter" for human use: things
can be expressed more clearly, more concisely, or in an alternative style *that
some may prefer*."[1] (emphasis mine). Its not designed to solve a problem
of how can I do this thing, but how can I write this thing such that my
team might be able to understand it better.

Yes, you can rewrite these examples in an entirely different way, but now
you're not comparing apples to even other fruit (procedural vs OO is not
the same). The point of this is to take a very common pattern (nesting many
procedural calls) and make it easier to read and manage later.


> Ocramius mentioned that the pipe operator would be super useful in async
> libraries and stuff but I am lacking real world examples here that
> illustrate how this new operator would make those experimental stuff
> benefit from it. Especially benefit besides scalar objects.
>
> --
> Richard "Fleshgrinder" Fussenegger
>

I'm personally +1 on this proposal. The examples I've seen where using lots
of intermediate variables are bad in my book, they create unnecessary
variables in scope, lead to more easily mistyping an intermediate name (as
we saw in a previous reply, showing how using intermediate variables was
better!), and generally make the code not line up to see what's happening.
If I look down the left hand side of the |> examples, I can very easily see
what's happening in order.

[1] https://en.wikipedia.org/wiki/Syntactic_sugar

Reply via email to