<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<font size="4"><font face="monospace">Part of what you are saying is
that "if we had a time machine, we should have reconsidered
whether `String` should have been a primitive in the language."
And I agree, String is pretty special, that might have been a
worthwhile conversation to have (in fact, I'm sure pretty it was
had.) But you're leaping from there to "of course it should
have been done that way", and then from there to "the only
reason we are not fixing it now is a misguided, slavish
adherence to compatibility." Both of these leaps are wrong.<br>
<br>
Let me give you an idea of the cost of what you are suggesting.
Your "solution" B want to create a new type, `string`, that is
better than the old String. Let's take for sake of argument
that it really will be better. That's the benefit. But let's
look at the costs:<br>
<br>
- Every single Java API ever written uses String as an argument
type, a return type, a field type, a type parameter, etc. So
under this plan, now 100% of the Java code out there instantly
becomes "the old code", and either needs to migrate, or clients
will stumble over converting between `String` and `string`.
This is a tax that will literally hit almost every line of Java
code ever written. <br>
<br>
- Even if a migration like this could be pulled off, how long
do you think it will take to get to a world where we don't have
both "old string" and "new string" simultaneously? Now users
will have to learn *both ways* and keep track of their subtle
differences. <br>
<br>
Having seen many, many proposals for improving the language, I
can say with confidence that the most dangerous source of such
proposals is the desire to "fix" "mistakes". The cost of
"fixing" those "mistakes" often exceeds the benefit by orders of
magnitude. <br>
<br>
"Solution" A is problematic in a different way. You are arguing
that String is so special that it alone should have different ==
semantics than every other class. Now, I agree that String is
pretty special, but such "solutions" have a cost too; they add
ad-hoc, arbitrary complexity to the language, which every user
has to learn. Now users have to learn `==` means one thing for
primitives, another for object references, but a third weird new
thing for strings. Which further makes it more likely that they
will misuse `==` on other object references, because that's how
String works! (And do you believe for a minute that if we did
this to String, there wouldn't be calls to do the same for, say,
LocalDateTime?) While the situation we have is not perfect, it
at least has simple, stable, principled, easy-to-understand
rules. Trading that for complex, ad-hoc, ever-changing,
hard-to-keep-track-of rules would require a benefit many orders
of magnitude bigger. <br>
<br>
<br>
<br>
</font></font><br>
<div class="moz-cite-prefix">On 10/26/2023 4:19 AM, tzengshinfu
wrote:<br>
</div>
<blockquote type="cite" cite="mid:CANj-iJeWdk=AqqXvgvopZx2_M70iMp_ygUUJ_UbBLQKYQJZNjw@mail.gmail.com">
<div dir="ltr">Hello, folks:<br>
<br>
I've noticed that `string comparison` in Java can be confusing
because, in certain contexts,<br>
their results are actually the same as `the wrapper classes of
Primitive Data Types`, as shown below:<br>
```java<br>
// wrapper class of int<br>
// PS:The constructor Integer(int) is deprecated since
version 9<br>
Integer int1 = new Integer(1);<br>
Integer int2 = new Integer(1);<br>
out.println(int1 == int2); // false<br>
out.println(int1.equals(int2)); // true<br>
<br>
String string1 = new String("1");<br>
String string2 = new String("1");<br>
out.println(string1 == string2); // false<br>
out.println(string1.equals(string2)); // true<br>
```<br>
<br>
After modifying the initialization and performing `+`
operations,<br>
the Integer results match expectations, but the String results
are unexpected:<br>
```java<br>
Integer int1 = 1;<br>
Integer int2 = 1;<br>
Integer int3 = int1 + 1;<br>
Integer int4 = int2 + 1;<br>
out.println(int3 == int4); // true<br>
out.println(int3.equals(int4)); // true<br>
<br>
String string1 = "1";<br>
String string2 = "1";<br>
String string3 = string1 + "1";<br>
String string4 = string2 + "1";<br>
out.println(string3 == string4); // Expected result is
`true`, but the actual result is `false`.<br>
out.println(string3.equals(string4)); // true<br>
```<br>
<br>
But it's not actually a mistake.<br>
Based on the naming convention, String is indeed a class, not a
Primitive Data Type.<br>
Because it's a class, using `Object::equals()` to compare its
contents is perfectly normal.<br>
<br>
However, from a user's perspective, as one of the commonly used
functionalities,<br>
the logic for comparing Strings is different from other
Primitive Data Types.<br>
This invisibly increases the learning curve for students,
newcomers,<br>
and developers transitioning from other programming languages.<br>
It should be more user-friendly, especially for the
aforementioned members.<br>
<br>
If there were a way to unify the comparison of strings with the
comparison of other Primitive Data Types,<br>
it would help newcomers use it correctly and enter the Java
world more rapidly.<br>
It would also lead to cleaner code and reduced typing for all
developers.<br>
<br>
I believe there should be a way to improve this inconsistency.<br>
Personally, ever since I learned about `String::equals()`, I
stopped using `==`,<br>
which led me to propose two solutions.<br>
<br>
Solution A: Make `String1 == String2` have the same result as
`String1.equals(String2)`.<br>
<br>
I find Solution A to be simpler, but making abrupt changes might
cause certain systems or software to break.<br>
How many disruptions would changing the result of `String1 ==
String2` cause?<br>
If it's rarely used or never used, we could safely remove it,
but we need to measure the cost of this disruption.<br>
The challenge is how to measure it.<br>
<br>
For all the APIs distributed in the JDK and third-party
packages, there are common APIs,<br>
but there are also less commonly used ones. We, as individual
developers, can't know this data.<br>
We can only voice our opinions on mailing lists, Reddit, or
GitHub and feel the response either upward or downward.<br>
Is there something like "telemetry"?<br>
Could we possibly collect statistics on various
package/class/method/syntax during compilation and return those
statistics after compilation?<br>
Or could we send surveys to Java developers and authors of major
packages/libraries?<br>
<br>
The fear that "I think it's rarely used, but in reality, it's
not, and everything breaks" holds people back.<br>
Additionally, another reason for hesitation is that there isn't
a feature currently in place that scans and safely converts old
projects to use updated syntax/APIs during JDK upgrades.<br>
<br>
So, what about Solution B?<br>
<br>
Solution B: Introduce a new class named `string/str` and
deprecate the String class.<br>
<br>
We could create a new class, named `string` or `str` (following
the convention of starting with a lowercase letter for Primitive
Data Types).<br>
This class's `string comparison` behavior would be the same as
Primitive Data Types, which means the result would be the same
as `String::equals()`.<br>
Since it mimics a Primitive Data Type class, we would remove
`string/str::equals()`.<br>
<br>
Then, we could mark the existing String class as "deprecated"
and instruct users to use `string/str` instead.<br>
<br>
Unfortunately, `string/str` is not a reserved word, and we don't
even know where it might have been used as a variable name or
how many times.<br>
Fortunately, we have a precedent "JEP 443: Unnamed Patterns and
Variables (Preview)" that used a lengthy preview period and
compile-time warnings to encourage users to abandon reserved
words ( _ ).<br>
I believe the same approach could work for `string/str`.<br>
<br>
I personally prefer Solution B because the safest approach would
be to prioritize creating the 'new' to replace the 'old' and
then, after a period,<br>
confirm that the usage of the 'old' has fallen below a certain
threshold before removing it.<br>
<br>
However, as Solution A mentioned, the current situation is that
I don't have good data to support either modifying or removing
the 'old' action.<br>
Similarly, I don't have good data to support whether creating
the 'new' is necessary.<br>
<br>
I agree that "backward compatibility" is a cornerstone of
Java's, and any language's, economic system's growth.<br>
Thanks to this persistence, we can confidently open projects
from many years ago in front of our bosses without worrying
about them breaking.<br>
Golang has also maintained its ecosystem thanks to "backward
compatibility",<br>
although it retains the right to break it under certain
circumstances (<a href="https://go.dev/doc/go1compat" moz-do-not-send="true" class="moz-txt-link-freetext">https://go.dev/doc/go1compat</a>).<br>
<br>
However, because Java has a long history, to remain competitive,
it will make various changes to its specifications.<br>
In my opinion, "backward compatibility" at such times should not
mean maintaining an unchanged status quo but giving developers
ample time to adapt to changes, at least when change is
possible.<br>
<br>
Changing the syntax of `string comparison` would, I believe,
make Java more user-friendly, change the perception of Java as a
language with a lot of ancient baggage,<br>
and reduce the cognitive burden on developers.<br>
But do others share this belief, or is it just me?<br>
<br>
Finally, thanks to David's reminder, Brian mentioned, "there's a
possibility in the future that we can use .equals() for state
comparison on any Primitive Data Types (since everything can be
treated as an Object). My perspective is to propose a
hypothesis: since String/string and other Primitive Data Types
are commonly used, can we simulate them to behave like a single
Primitive Data Type in order to coordinate their behavior?
Another reason is that I personally find that a == b is clearer
than a.equals(b) and less prone to typos (although it's not a
problem with the assistance of modern IDEs). From a visual
perspective, Andrew also brought up an interesting point, using
String1 .= String2 as syntactic sugar for .equals() is much
clearer (or maybe we can use String1 === String2?).<br clear="all">
<div>
<div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature"><br>
</div>
<div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature"><br>
/* GET BETTER EVERY DAY */<br>
</div>
</div>
</div>
</blockquote>
<br>
</body>
</html>