• (nodebb)

    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....)

  • Prime Mover (unregistered)

    Not too bad a WTF if the intention was to return the opposite alignment to "alignment".

  • (nodebb) in reply to TheCPUWizard

    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:

        string1 == string2
    

    and

        string1.equals(string2)
    

    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.

  • (nodebb)

    The real WTF, of course, is Java offering both "equals" and "==", but then deciding they mean two different things. But also only sometimes.

  • (nodebb) in reply to chucker23n

    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.

  • (nodebb) in reply to Steve_The_Cynic

    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.

  • (nodebb) in reply to Mr. TA

    "You rarely need reference equality" -- I need duplication of data values even less often.

  • (nodebb) in reply to Mr. TA

    "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)

  • Kythyria (unregistered) in reply to Mr. TA

    .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 &.

  • (nodebb) in reply to chucker23n

    The real WTF, of course, is Java offering both "equals" and "==", but then deciding they mean two different things. But also only sometimes.

    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...

  • (nodebb) in reply to TheCPUWizard

    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.

        const char *str = some_function(some,arguments,here);
    
        if ( str == "Hello, world" )
        {
            // Never called
        }
    

    Addendum 2022-03-10 09:35: Edit: I'm aware that "non-Java mindset" indicates new newbies to Java, but ...

  • (nodebb) in reply to Bananafish

    True, it's not Java-only, which just means that as a design choice, it's broken in places other than Java.

  • Nony Mouse (unregistered) in reply to Steve_The_Cynic

    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.

  • IA (unregistered) in reply to chucker23n

    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.

  • IA (unregistered) in reply to Nony Mouse

    ... designed to be syntactic sugar ...

    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.

  • (nodebb) in reply to Steve_The_Cynic

    True, it's not Java-only, which just means that as a design choice, it's broken in places other than Java.

    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!

  • (nodebb) in reply to IA

    When is it useful to see if two string variables refer to the same underlying string object?

  • (nodebb) in reply to Bananafish

    I was referring specifically to this question of reference equality vs value equality.

  • JamesTheBeliever (unregistered) in reply to Steve_The_Cynic

    When the character strings themselves are 2,000 characters log and differ in the 1,999th character?

  • DrPepper (unregistered)

    Sort of makes sense if you're dealing with a language that reads right-to-left.

    But:

    1. A code review should have caught the mis-application of strings instead of enums
    2. A unit test or two would have revealed that this code simply does not work.
    3. End-to-end testing of the application would have revealed that this code does not work.

    "Modern software development" includes these things. Why were they not applied?

  • (nodebb) in reply to Steve_The_Cynic

    I was referring specifically to this question of reference equality vs value equality.

    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.)

  • white5moke (unregistered) in reply to chucker23n

    ...yes but what is more efficient, and does it really matter for what you're implementing?

  • Kythyria (unregistered)

    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 equals() for == is perfectly reasonable, especially if you banish it to an IEquatable 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.

    When is it useful to see if two string variables refer to the same underlying string object?
    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.
  • (nodebb)

    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.

  • Argle (unregistered) in reply to Bananafish

    There is an Objective COBOL

    Isn't it called ADD ONE TO COBOL. ?

  • MaxiTB (unregistered)

    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.

  • (nodebb)

    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)?

  • (nodebb) in reply to Bananafish

    TRWTF is people doing the required RTFM and still deciding to use Java.

  • Sole Purpose Of Visit (unregistered) in reply to Kythyria

    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!

  • (nodebb) in reply to Bananafish

    reference versus value is in no way related to objects.

  • JamesTheBeliever (unregistered) in reply to MaxiTB

    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.

  • ZZartin (unregistered) in reply to Jenda

    Hey, why not javaIsStupid.Add(5).MultiplyBy(7)?

    Oh I see you've also had to use BigDecimal as well because the primitives double or float don't maintain precision properly.

  • Airdrik (unregistered)

    iirc, java does to string deduplication for string constants in the JVM; however it does not do that for runtime-constructed strings:

    String helloWorld = "Hello World";
    String hello = "Hello";
    String world = "World";
    assert helloWorld == "Hello World";
    assert helloWorld != hello + " " + world; 
    
  • IA (unregistered) in reply to Steve_The_Cynic

    When is it useful to see if two string variables refer to the same underlying string object?

    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.

  • IA (unregistered) in reply to Jenda

    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 ;-)

  • MaxiTB (unregistered) in reply to JamesTheBeliever

    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

  • Bruce (unregistered) in reply to chucker23n

    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...

  • (nodebb)

    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.

  • (author) in reply to 0x80040005

    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.

  • Sole Purpose Of Visit (unregistered) in reply to IA

    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.

  • clubs21ids (unregistered)
    Comment held for moderation.
  • clubs21ids (unregistered)
    Comment held for moderation.
  • Shahid Mustafa (unregistered)
    Comment held for moderation.
  • Framingnoone (unregistered)
    Comment held for moderation.
  • (nodebb) in reply to MaxiTB

    In C# all strings are intern

    Nope. String constants are guaranteed to be interned at creation, but all other strings have to be interned manually by calling String.Intern() first.

    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.

    Also wrong. String.operator ==(String a, String b) is implemented as return null == a ? null == b : a.Equals(b), and the first thing every String.Equals overload does is a reference equality check.

    This also means you can use a switch statement with strings because it's again just a 64-bit pointer comparison.

    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.

    I'm actually talking here about operator chaining, like var x = "A" + "B" + "C";.

    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 emit var x = "ABC" instead).

Leave a comment on “Constantly Sinister”

Log In or post as a guest

Replying to comment #:

« Return to Article