- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
Would it not depend on how the variable was initialized prior to the call (i.e. one of the three string constants or some other "unknown" - in which case it would default to Center....)
Admin
Not too bad a WTF if the intention was to return the opposite alignment to "alignment".
Admin
Normally, yes, except that normally we'd expect that if we set the variable to some other string value that contains the same sequence of characters as, say, the left-align constant, the code will behave as if it used the left-align constant, and it won't, because of the difference between:
and
For members of the audience who don't know this one: In Java, the first is true only if they point to the same string object behind the scenes, while the second is true if they point to string objects (possibly different objects) that contain the same sequence of characters.
Admin
The real WTF, of course, is Java offering both "equals" and "==", but then deciding they mean two different things. But also only sometimes.
Admin
That is one of my pet peeves in Java and .NET. I get it, it's hard to create a new framework and mistakes were made. Still, the == means reference equality is silly. You rarely need reference equality, yet the main operator is for that.
Admin
Steve, Yes, I know that.. it is why I phrase my response in the way I did. Reference equality is actually a very useful differentiator. Of course, if you are not expecting it, then it can bite you.
Admin
"You rarely need reference equality" -- I need duplication of data values even less often.
Admin
"You rarely need reference equality" -- I need duplication of data values even less often.
Addendum 2022-03-10 08:55: (but perhaps I do need duplication of comments)
Admin
.net doesn't have this one. == can be overloaded fine, and String does, as do, IIRC, structs and things declared with
recordK/code>
Meanwhile Rust has an entirely different set of annoyances around ==, mostly to do with references, and the slightly odd rules for when you can omit the &.
Admin
I don't disagree with this statement, but I have to qualify it and say TRWTF is people not doing the required RTFM and then blaming the language for behaving as designed. This is not a "Java-only" problem...
Admin
It may be a useful differentiator, but reference equality is rarely useful for strings because the non-Java mindset expects
==
to mean that the contents are equal (ref: std::string's operator ==()).Then again, == for "C strings" is also reference equality (as opposed to
strcmp() == 0
which is content equality), but almost never useful in C.Addendum 2022-03-10 09:35: Edit: I'm aware that "non-Java mindset" indicates new newbies to Java, but ...
Admin
True, it's not Java-only, which just means that as a design choice, it's broken in places other than Java.
Admin
The real problem is that Java's design should have allowed for an operator for comparison of references explicitly and have the == be designed to be syntactic sugar for a .equals() call. You don't even need true operator overloading to make that work - just a compiler the performs the substitution at compile time. But of course that wasn't in anyone's head back in the late 80s when Java's design was being firmed up and C style reference equality was just considered a normal approach.
Admin
The real WTF is if someone is trying to code without understanding basic concepts of the language. In Java it's pretty clear what == and equals does and yes, both are useful.
Admin
Why do you need syntactic sugar if you can do everything without it? The == means value compare (usually one CPU instruction) and equals() is a method call, it's pretty simple and straightforward. Any syntactic sugar would always force the developer to think about it.
Admin
Let's do COBOL: COMPUTE AREA = LENGTH TIMES HEIGHT. AREA = LENGTH * HEIGHT. MULTIPLY LENGTH BY HEIGHT GIVING AREA.
Depending on the non-typely values of LENGTH and HEIGHT, there's three different answers up there. It's been broken for a very long time ;)
Addendum 2022-03-10 11:45: I really need to remember the code tags!
Admin
When is it useful to see if two string variables refer to the same underlying string object?
Admin
I was referring specifically to this question of reference equality vs value equality.
Admin
When the character strings themselves are 2,000 characters log and differ in the 1,999th character?
Admin
Sort of makes sense if you're dealing with a language that reads right-to-left.
But:
"Modern software development" includes these things. Why were they not applied?
Admin
And I was demonstrating that this [broken] design element has nothing to do with object references or the value of their pointers, going back to before there were objects. Standard COBOL is not an objective language so there's no reference vs. value. Equality comparisons are only done on values. (There is an Objective COBOL, but it doesn't work the way you might think it does.)
Admin
...yes but what is more efficient, and does it really matter for what you're implementing?
Admin
Value equals is only one instruction for word-sized values. Such as references. The things references point at are basically never a single word in Java.
Substituting
Making that do the right thing is the point of string interning. It's valuable in dynamic languages with no enums (eg, Lua), and in parsers. If you're gonna do a lot of equality comparisons against the same, say, XML element names or JSON keys, you want them to be cheap. Ref equals is cheaper than value equals.equals()
for==
is perfectly reasonable, especially if you banish it to anIEquatable
interface. Rust does something similar, but its lack of inheritance means you don't get potential oddities from==
being dispatched statically and method calls by vtable, like C# does.Admin
I'm certain that I was told at one point (and I have a suspicion it was when I was doing a Java course run by Oracle) that all Java string objects, with the same text, should equate to being the same as they are all pointing to the same object behind the scenes.
Admin
Isn't it called ADD ONE TO COBOL. ?
Admin
Ha, it's funny because this is one topic where c# is different to Java.
In C# all strings are intern (or actually this the .net behavior for all languages since the beginning) before they are compared. This means every unique string has an unique address, so you can simply compare pointers to check for equality.
So it's pretty easy to spot Java developers which have no clue about .net, when they use the virtual methods Equals() to compare strings instead of the equality operators == and !=. This is super bad, because Equals() does a binary comparison of the full string instead of just checking the pointer plus it's a virtual method, which cannot be optimized by the compiler.
This also means you can use a switch statement with strings because it's again just a 64-bit pointer comparison.
The downside obviously is that it's poison to join strings without using a StringBuilder especially in iterations, because the runtime might intern temporary strings for no reason. And no, I'm not talking string.Join() or string.Concat() here, it's using a StringBuilder internally. I'm actually talking here about operator chaining, like var x = "A" + "B" + "C";.
Long story short, when you code in C# you should use always the operators first, Equals() is only there if you want compare objects of unknown type.
Admin
The real WTF is using Java. I mean seriously? == made absolutely abysmally totally mind-numbingly useless, 'cause it's oh so much more object oriented when you are supposed to use oneCrazyLongBraindeadVariable.Equals(otherStupidIdioticVadiable)? Hey, why not javaIsStupid.Add(5).MultiplyBy(7)?
Admin
TRWTF is people doing the required RTFM and still deciding to use Java.
Admin
Except:
https://ericlippert.com/2013/10/07/math-from-scratch-part-six-comparisons/
I can't think of a single language that doesn't have problems with equality. (At least, not one that relies on any non-native type being essentially a pointer, which is most of them.)
C# is preferable in so many ways that I lose count. But both languages have a history behind them. Java used to intern strings (don't know whether it still does), and C# .... well ... just read the article.
Any language that enforces strict bit-by-bit equality via an operator like === is the way forwards. PHP ftw!
Admin
reference versus value is in no way related to objects.
Admin
There's also potential gotchas when you compare strings that are part of COM objects. Even if they have the same string of characters they're likely not in the same memory location. In this case .Equals can be the way to go.
Admin
Oh I see you've also had to use BigDecimal as well because the primitives double or float don't maintain precision properly.
Admin
iirc, java does to string deduplication for string constants in the JVM; however it does not do that for runtime-constructed strings:
Admin
In general, there are cases where you know that all instances are unique and then the == is just faster replacement of equals and thus it's useful. It doesn't matter if those instances are Strings or Points or something else. Maybe you are treating Strings as just some texts but they can be used as keys, identification of something etc., depends on the problem to solve.
Admin
If you don't see any use for that it doesn't mean it's useless. It's just that you either don't need it or you don't understand that you need it ;-)
Admin
Can you provide an example?
When you have a BSTR* from a COM+ object, you use the marshalling method Marshal.PtrToStringBSTR() to create a proper string instance. This method makes (potentially) a copy of the string and it's unique again.
So there is no special behavior with COM strings, when correctly handled. And I have never seen a COM object or Proxy that doesn't behave correctly; in fact especially in the beginning a lot of objects in the .net framework where COM proxies.
https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.ptrtostringbstr?view=net-6.0
Admin
As in small integer values (between -128 and 127) where the runtime pools those values, so that == and equals are the same. Add a common human tendency to use small numbers in test cases and...
Admin
Everything you wanted to know about string interning in C# but were afraid to ask: https://docs.microsoft.com/en-us/dotnet/api/system.string.intern?view=net-6.0
C# interns string literals at compile time. For these, reference equality could be used as value equality. At runtime, when you programatically create a string, it always allocates a new block of memory; even if the text matches an existing string in the intern pool. When you assign the string to a different variable it copies the reference (no new memory allocation). This is OK because string contents are immutable. You can use String.Intern() to find or create an entry in the intern pool, which then allows the allocated block to be garbage collected.
BUT - once you intern a string it stays in memory for the lifetime of your app. Interning a string could get progressively slower the more strings you put into the intern pool (I would like to see a benchmark on that).
I think it's a pretty good design, since: You can use the == operator without gotchas Comparison can be optimised to reference equality first, value equality second Embedded string literals will get reference comparison because of the interning at compile time. The cases where you'd need to use String.Intern() are few and far between.
Admin
It may make sense to explicitly intern some dynamically-created Strings if you're a long-running process (like an application server) and you're very very certain that you know which of these are likely to be repeatedly reused and compared against. But like most performance optimizations, you really should construct a benchmark and measure it; don't just guess. In twenty years I've only found a good use once, and now I'm not even sure about that one.
Admin
I suppose it depends upon whether you are a language designer, or a language user.
In this part of (theoretical) Java, the "syntactic sugar" is confined to the compiler/interpreter/pick. I tend to prefer tricky choices to be made at the compiler state, although YMMV. Once sugared, or de-sugared, the result can be jittered ... and the semantics are preserved, and nobody would notice a difference.
Oh, and to correct the poster previous to this: Java is not a "late 80s" language. Gosling, Sheridan, and Naughton began designing "Oak" in 1991, and version 1.0 was released by Sun in 1996.
Regrettably, all three of them spend five years learning nothing very useful, as far as I can see. Pretty much the paradigm for the twenty five years since.
Admin
Nope. String constants are guaranteed to be interned at creation, but all other strings have to be interned manually by calling
String.Intern()
first.Also wrong.
String.operator ==(String a, String b)
is implemented asreturn null == a ? null == b : a.Equals(b)
, and the first thing everyString.Equals
overload does is a reference equality check.Switch statements on strings are actually converted into a large
String tempS = s; if (tempS == "a") { ... } else if (tempS == "b") { ... } ...
construct. No fancy jump tables, unfortunately.The compiler knows about that particular example and will silently transform it into
var x = String.Concat("A", "B", "C")
(assuming those aren't actually constants but other variables, because otherwise it will just emitvar x = "ABC"
instead).