<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    Hi Brian,<br>
    <br>
    First the intuition and then the rationale.<br>
    <br>
    Intuition: the extension does not include the period '.' learned
    from years of working with existing systems, both shell and
    programming languages with file apis.<br>
    <br>
    Second: In trying to make Path.getExtension() handle all of the use
    cases possible, it makes some of them more difficult.  In
    particular, the cases for removing or replacing the extension are
    easier to do with a method for that purpose. It is easier to explain
    using a Path.removeExtension() method than to explain how to convert
    the path to a string and then remove some number of characters from
    the end and recreate the Path. <br>
    <br>
    Rationale:<br>
    <ul>
      <li>Other Java libraries that provide path name utilities do not
        include the dot as part of the extension; (Guava and Apache
        Commons). A mismatch with them (and other common Java libraries)
        creates friction and room to make mistakes in conversions
        between different representations.</li>
      <li>The no-dot representation works just fine except in the case
        of trailing dot, which is quite uncommon in practice.<br>
      </li>
      <li>The APIs provided should do what the programmer needs to do,
        not be APIs from which the programmer can create the API they
        need and still avoid an explosion of APIs for narrow use cases.<br>
      </li>
      <li>Extensions are used in many ways, from switch statements to
        keys in maps to simple if/then/else; some are hard coded and
        others are configured or loaded as plugins. The semantics should
        be simple and direct.<br>
      </li>
    </ul>
    For 1) and 3) I would say that both "foo" or "foo." have an empty
    ("") extension.<br>
    Providing a removeExtension() or replaceExtension(String) method can
    embed the edge case handling and make the API easy to use without
    having to burden the Path.getExtension() method with a model that
    includes that complexity.<br>
    <br>
    Regards, Roger<br>
    <br>
    <br>
    <div class="moz-cite-prefix">On 10/10/23 2:31 PM, Brian Burkhalter
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:0B78F716-26F5-43B3-A911-A320ED9B2366@oracle.com">
      
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        I would like to resurrect this topic which has languished for
        quite a while now. It was discussed for probably decades before
        my involvement with it. A brief outline of its most recent
        history is included below. The essence is that it would be good
        to add a java.nio.file.Path.getExtension method, and possibly
        one or more companion methods. General comments on the topic are
        welcome regardless of whether the included chronology is
        reviewed. Things to consider include:</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        1) whether a getExtension method ever returns null;</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        2) whether a period character is included as the first character
        of the returned extension;</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        3) whether the extension of “foo” (no dot) differs from that of
        “foo.” (terminal dot).</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        Thanks,</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        Brian</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        --- snip --- TL;DR --- snip ---</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        [1] Feb. 2018</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        Path.hasExtension was initially proposed but dropped in favor of
        Path.getExtension. This method was for the most common cases
        equivalent to</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        Path path = ...;</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        String name = path.getFileName();</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        String extension = name.substring(name.lastIndexOf(“.”) + 1);</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        which is to say the extension is the portion of the file name
        string after but not including the last period character (dot).
        This effort faded out.</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        [2] Apr. 2021 - Mar. 2022</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        A pull request was proposed and culminated in the proposal of
        the Path method</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        String getExtension(String defaultExtension)</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        where in the common case the extension is once again the portion
        of the file name string after the last dot. For degenerate cases
        the “defaultExtension” parameter would be returned.  This effort
        was superseded by [3].</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        [3] Mar. 2022 - Dec. 2022</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        This pull request specified the Path method</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        String getExtension()</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        which in the common case returned the portion of the file name
        string after the last dot, and in unusual cases either the empty
        string (terminal dot) or null (no dot). For a time this proposal
        used Optional but that was dropped as unwieldy. This PR was
        approved and integrated.</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        [4] Dec. 2022</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        Due primarily to the undesirability of the possibility of a null
        return value and the lateness of the integration in the
        development cycle, the API added in [3] was backed out.</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        [5] Dec. 22</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        A new issue was filed to track the resumption of eventual work
        on this topic. This issue suggested that the last dot be
        included in the extension, e.g., the extension of “image.jpg”
        would be “.jpg” rather than “jpg” and that the value returned by
        getExtension would never be null. It also proposed a
        complementary method Path.removeExtension which, together with
        Path.getExtension, would form an invariant</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        Path path = ...;</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        assert path.equals(path.removeExtension() +
        path.getExtension());</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        which would obviate the need to handle a period character
        explicitly.</div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal; min-height: 17px;" class="">
        <br class="">
      </div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        [1] <a href="https://mail.openjdk.org/pipermail/nio-dev/2018-February/004716.html" class="moz-txt-link-freetext" moz-do-not-send="true">
https://mail.openjdk.org/pipermail/nio-dev/2018-February/004716.html</a></div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        [2] <a href="https://github.com/openjdk/jdk/pull/2319" class="moz-txt-link-freetext" moz-do-not-send="true">https://github.com/openjdk/jdk/pull/2319</a></div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        [3] <a href="https://github.com/openjdk/jdk/pull/8066" class="moz-txt-link-freetext" moz-do-not-send="true">https://github.com/openjdk/jdk/pull/8066</a></div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        [4] <a href="https://github.com/openjdk/jdk/pull/11566" class="moz-txt-link-freetext" moz-do-not-send="true">https://github.com/openjdk/jdk/pull/11566</a></div>
      <div style="margin: 0px; font-stretch: normal; font-size: 14px;
        line-height: normal;" class="">
        [5] <a href="https://bugs.openjdk.org/browse/JDK-8298318" class="moz-txt-link-freetext" moz-do-not-send="true">https://bugs.openjdk.org/browse/JDK-8298318</a></div>
    </blockquote>
    <br>
  </body>
</html>