On 1/7/26 12:34 PM, Brian Burkhalter wrote:
Resuscitating this discussion thread from last year ...
To summarize my rereading of the thread, there is good agreement that
Path.{ends,starts}With(String) should be deprecated and replaced with something
else, perhaps Path.{ends,starts}WithString(String). There was also a parallel
suggestion that Path.{ends,starts}With(Path) be deprecated in favor of
Path.{ends,starts}WithPath(Path). Thus:
* Path.{ends,starts}With(String) -> Path.{ends,starts}WithString(String)
* Path.{ends,starts}With(Path) -> Path.{ends,starts}WithPath(Path)
My experience is that deprecation for the purposes of renaming doesn't work very
well. I don't think we're intending to remove the old APIs, so they'd remain, so
"renaming" would merely be the addition of new APIs with similar names. This would
just make things more confusing.
The main problem is that Path.{ends,starts}With(String) is confusing and misleading,
so let's focus on that.
Among doubtlessly many others, one alternative is
1. Leave Path.{ends,starts}With(Path) unchanged
This makes sense. I haven't seen any evidence that this is a problem if one is
already working in the Path domain.
2. Deprecate Path.{ends,starts}With(String)
This is the confusing one, so yes, deprecate this (not for removal). It's an open
question regarding what the deprecation text should recommend be used instead.
Perhaps some of the discussion below will resolve this.
3. Add Path.pathString{ends,starts}With(String)
where "pathstring" in effect implies the value of Path.toString().
Before we start adding new APIs, I think we should consider which use cases we think
we want to support. The methods take a string argument, and the two cases are
whether the operation is performed on Paths and Path segments or whether the
operation is performed in terms of Strings.
For brevity I'll just use "EW" to represent the "endsWith" operation in either
domain, but the analysis applies equally to the "startsWith" operation.
Suppose we start off with
var path = Path.of("/one/two/three");
The cases are:
a) Path domain. The code path.EW(string) is equivalent to
path.endsWith(path.getFileSystem().getPath(string))
// note, this is Path.endsWith(Path)
and thus we have
path.EW("/two/three") ==> false
path.EW("two/three") ==> true
b) String domain. The code path.EW(string) is equivalent to
path.toString().endsWith(string)
// note, this is String.endsWith(String)
and thus we have
path.EW("/two/three") ==> true
path.EW("two/three") ==> true
=====
I'm not convinced we need any new APIs at all. It seems likely that many people want
to perform the string-based endsWith() operation, in which case maybe it's best to
be explicit and convert the path to a string using toString() before doing that.
Adding a deprecation for Path.endsWith(String) should warn people not to use this
method for the string-domain case.
If you want to perform this operation in the Path domain, maybe it's best to be
explicit about it. If you're writing library code that wants to be very general,
then you probably have the relevant FileSystem in a local variable already, and you
might construct Path objects explicitly before invoking the endsWith(Path)
operation. Using string literals directly, and having them implicitly be converted
to Path objects, seems like it easily leads to subtle problems (such as the
difference in behavior between my "/two/three" and "two/three" examples above.) So,
maybe being explicit is better, even if it is more verbose and less convenient.
If you're writing an application that uses the default FileSystem everywhere, and
you really want to perform a Path-based operation, you can just slap Path.of()
around your string literal and move on. I don't think we need another method to
handle this case.
So, maybe do (1) and (2) but omit (3). This boils down to just deprecating
endsWith(String) and startsWith(String).
s'marks
Comments?
Brian
On Nov 2, 2025, at 3:35 PM, David Alayachew <[email protected]> wrote:
As for deprecations, I still think all 4 methods should be deprecated. This path
variants are kind of ok, but the String variants are just too deceptively named.
I think Rob Spoor hit it on the head with this quote.
> Perhaps both can be added?
>
> Path.{start,end}sWithString would default to calling
> toString().{start,end}sWith(arg) and
> Path.{start,end}sWithPath would default to calling
> {start,end}sWith(arg). The latter could default to
> calling {start,end}sWith(getFileSystem().getPath(arg))
> but then custom implementations that do something else
> (in addition) may not work as expected.
Doing it this way, we can have (start|end)sWithPath() have both String and Path
overloads with no ambiguity.