<div dir="ltr">I would just like to express some of my concerns regarding pipe operator ( |> syntax ).<div><br></div><div>I am not opposing it, and it may be just my aesthetic concerns, but what made me like Java syntax so much is that Java code most of the time looks like word.anotherWord. I am not sure how to explain this correctly, but this always gives off the impression of a homogenous code style: no ** operators from python, no object referencing-dereferencing etc I am kind of afraid that a pipe operator in such environment could feel alien to users.</div><div><br></div><div>From what I managed to find in the net, maybe code style convention that Elixir provides could partially fix that: it recommends to add whitespace before and after pipe like so:<font color="#000000"> <span class="gmail-n" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">other_function</span><span class="gmail-p" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">(</span><span class="gmail-p" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">)</span><span class="gmail-w" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)"> </span><span class="gmail-o" style="background-color:transparent;font-family:inherit;font-size:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235);font-weight:bold">|></span><span class="gmail-w" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)"> </span><span class="gmail-n" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">new_function</span><span class="gmail-p" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">(</span><span class="gmail-p" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">)</span><span class="gmail-w" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)"> </span><span class="gmail-o" style="background-color:transparent;font-family:inherit;font-size:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235);font-weight:bold">|></span><span class="gmail-w" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)"> </span><span class="gmail-n" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">baz</span><span class="gmail-p" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">(</span><span class="gmail-p" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">)</span><span class="gmail-w" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)"> </span><span class="gmail-o" style="background-color:transparent;font-family:inherit;font-size:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235);font-weight:bold">|></span><span class="gmail-w" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)"> </span><span class="gmail-n" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">bar</span><span class="gmail-p" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">(</span><span class="gmail-p" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">)</span><span class="gmail-w" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)"> </span><span class="gmail-o" style="background-color:transparent;font-family:inherit;font-size:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235);font-weight:bold">|></span><span class="gmail-w" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)"> </span><span class="gmail-n" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">foo</span><span class="gmail-p" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">(</span><span class="gmail-p" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">). This code is readable and, imo, will not catch reader eyes so much when they are reading the code.</span></font></div><div><font color="#000000"><span class="gmail-p" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)"><br></span></font></div><div><font color="#000000"><span class="gmail-p" style="background-color:transparent;font-family:inherit;font-size:inherit;font-weight:inherit;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229,231,235)">Regarding traits, I am not an expert in functional programming, but what catches my eye right away is that, as I understand, this approach is incompatible with var keyword.</span></font></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sun, Apr 28, 2024 at 2:06 PM Johannes Spangenberg <<a href="mailto:johannes.spangenberg@hotmail.de">johannes.spangenberg@hotmail.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><u></u>

  
  <div>
    <p>Here are a few notes from my side, although I am just a fellow
      subscriber to the mailing list and not an API designer of the Java
      project:</p>
    <blockquote type="cite">
      <div dir="ltr">
        <div>2. Documentation accessibility is a strange point for me to
          be fair. Every IDE nowadays is capable of fetching the right
          documentation, as well as explicitly mentioning where the
          method comes from, as it is done in C#, kotlin, swift and many
          other languages. I don't think anyone has ever heard
          complaints about poor documentation of LinQ. Unless someone is
          writing in notepad, this is poorly applicable.</div>
      </div>
    </blockquote>
    <p>I am regularly annoyed by this issue whenever I read source code
      at GitHub which uses Kotlin, C++, JavaScript, or on-demand imports
      in Java. I my view, it is less about finding the documentation,
      and more about finding the definition of the method. People are
      not always in their feature-rich IDE when reading source code.</p>
    <p>
      </p><blockquote type="cite">Regarding ambiguity, the common practice
        (which also is applied in my design) is to prioritize members
        over extensions, there is no ambiguity if behaviour is well
        defined.This "potentially" could sometimes result in source
        incompatibility with some third-party libraries, but as soon as
        this is not conflicting with anything from stdlib, that's not
        really our concern. Also, I think it's kind of exotic scenario,
        and may crash only with utilities from stdlib classes, which
        cuts off virtually all production code from the risk group.</blockquote>
    <p></p>
    <p>Regarding the related risk of collisions, I recently was affected
      by the following Gradle bug, which is caused by a collision
      between the stdlib of Java and Kotlin (made possible by extension
      methods):</p>
    <blockquote>
      <p><a href="https://github.com/gradle/gradle/issues/27699" target="_blank">https://github.com/gradle/gradle/issues/27699</a></p>
    </blockquote>
    <blockquote type="cite">
      <div dir="ltr">
        <div>3. Not overridable. Should they be? I don't think there is
          a way to achieve some kind of "polymorphic" extensions, and I
          don't think there should be: extension methods should provide
          polymorphic target handling, floow LSP etc., not the other way
          around.</div>
      </div>
    </blockquote>
    <p>Rust uses a single concept (Traits) which effectively supports
      both. Traits also provide a nice solution for the issues behind
      Unions. However, while I would like to see something similar to
      Traits in Java, I would actually cut the
      extension-method-semantic. (i.e. I would make the methods
      available only after the object was assigned to the type of the
      Trait.)<br>
    </p>
    <p>For people who don't know Rust, you can think of Traits as
      interfaces, which can also declare implementations for already
      existing classes. Here is an attempt to map it to some made-up
      Java syntax:</p>
    <blockquote>
      <pre>/* usage */
MyFilesTrait files1 = Path.of("src")
MyFilesTrait files2 = List.of(Path.of("src-1"), Path.of("src-2"))

/* trait definition */
interface MyFilesTrait {

    Stream<Path> asPathStream();

    for-class Path {
        @Override
        Stream<Path> asPathStream() {
            return Stream.of(this);
        }
    }

    for-class File {
        @Override
        Stream<Path> asPathStream() {
            return Stream.of(this.toPath());
        }
    }

    for-class Collection<? extends MyFilesTrait> {
        @Override
        Stream<Path> asPathStream() {
            return this.stream().flatMap(item -> item.asPathStream())
        }
    }
}
</pre>
    </blockquote>
    <p>If you would seal the interface, you would effectively have an
      union.<br>
    </p>
    <blockquote type="cite">
      <div dir="ltr">
        <div>Its common issue users just aren't aware of the existence
          of certain utility classes and end up with nonoptimal code.</div>
      </div>
    </blockquote>
    <p>This seems mostly related to the auto-completion of the IDE. I
      don't think the extension functions would be necessary for that,
      but I agree that extension methods would guide IDEs and kind of
      force them to implement the discovery during auto-completion.<br>
    </p>
    <blockquote type="cite">
      <div dir="ltr">
        <div>Code without extension methods is always much more verbose,
          if the API is supposed to be fluent developer could end up
          with deep nested invocations.<br>
        </div>
      </div>
    </blockquote>
    <p>
      </p><blockquote type="cite">
        <div>as for "the illusion of belonging" it could be addressed by
          introducing some special operator instead of dot to highlight
          the difference, e.g. something like:</div>
        <div><span style="font-family:monospace">x¬f3("p3")¬f2("p2",
            "p22")¬f1("p1")</span></div>
      </blockquote>
    <p></p>
    <p>In the JavaScript community, there were some discussions about
      introducing a "pipe operator" some years ago, but it seems to be
      stalled right now.<br>
    </p>
    <blockquote>
      <p><a href="https://github.com/tc39/proposal-pipeline-operator" target="_blank">https://github.com/tc39/proposal-pipeline-operator</a><br>
      </p>
    </blockquote>
    <blockquote type="cite">
      <div dir="ltr">JS also has its own unique way of extending APIs.
        The only modern widely-used language that does not have
        extension methods is Python, but that only applies to built-ins,
        custom classes could be extended as well.<br>
      </div>
    </blockquote>
    <p>If you are referring to the possibility to assign new properties
      to prototypes (JS) or classes (Python), than I think it is
      considered bad practice in parts of both communities.</p>
    <p>From my point of view, extension functions as implemented by
      Kotlin are not really a good fit for Java. Java and Kotlin have
      greatly different design philosophies. While Kotlin focuses more
      on convenience (or ease of use), Java has a much bigger focus and
      language simplicity. The complex method resolution required for
      this style of extension functions doesn't seem to fit well for
      Java in my opinion. Other solutions like the pipeline operator
      seem like a better fit to me. While they also increase the
      complexity by introducing a new operator, it keeps the method
      resolution quite simple and doesn't hide the complexity as done by
      extension methods. As a result, it also doesn't suffer from the
      accessibility issues of extension methods. </p>
    <p>Best Regards,<br>
      Johannes<br>
    </p>
  </div>

</blockquote></div>