6 ms·
In Java 3 = 12
- danielmg 9y agoIt's evaluates left to right. (1+2)=3 then concat with string = then concat with 1 and concat with 2. The optimiser converts these concats to a StringBuilder. https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.18.1 https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.htm... Second time I've seen something like this on HN.
- essuraj 9y agoso does javascript
- deleted 9y ago[deleted]
- partycoder 9y agoThings to consider here are: - operator precedence - implicit type casting - how operator+ is defined per each type (e.g: numbers add, strings concatenate)
- Seol 9y agoThe interesting thing is that the "obvious correct" behaviour would require the precedence of the + operator to depend on the types of the operands - which is obviously impossible if it's done at the parse stage...
- struppi 9y agoI suppose that's something every Java programmer should know: How types are automatically converted during "arithmetic" operations. There are some subtleties (like byte+short => int), but it's not too much to remember. The deeper question is: Was it a wise choice to disallow operator overloading BUT use "+" as a string concatination operator AND convert all values to strings during string concatenation? I think not, but it's a rather moot point, since that desing decision is not likely to change...
- nicwilson 9y agoThats why I'm glad D chose '~' as a binary concatenation operator so that there is never any confusion.
- cm2187 9y agoThere is something to be said about using all the special characters of the ASCII table in term of readability. Looking forward languages that will start making good use of Unicode! I am actually surprised Greek letters haven’t made it already. Lots of computer scientists are mathematicians that are used to math papers looking like an Ancient Greek tablet.
- cakoose 9y agoThe Fortress programming language was a research project at Sun that incorporated mathematical notation. See page 24 of http://www.oracle.com/technetwork/systems/ts-5206-159453.pdf http://www.oracle.com/technetwork/systems/ts-5206-159453.pdf They also had an ASCII-only representation for everything, so you could use a regular text editor if you wanted, kind of like Markdown.
- kelnos 9y agoEh, it's just a design decision. They could have required that people construct strings using printf-style formatting (which you can do, with String.format(), but isn't required), or have some sort of interpolation (like Scala does with s"This var is $foo"), but they just opted to let people concat with + instead. You could argue it any way, I suppose; there's no one right answer. The behavior in the OP's example is unsurprising for a language that defines + to be left-associative and has a well-defined order of operations.
- gambiting 9y agoSo on mobile you can't see the entire width of that website, but trying to scroll to the left or right changes articles. Absolutely brilliant, why do people think that overriding the scroll on mobile is a good thing is beyond me.
- Insanity 9y agoI feel the title is a bit unfair. Technically it is '= + 1 + 2'. Which is expected as a Java developer. Coming from other languages maybe it does look a bit odd though
- ramblerman 9y ago1 + 2 + "=" + (1 + 2)
- usrusr 9y agoOr as one might write in real life: (1 + 2) + "=" + (1 + 2) A few braces here and there are a very practical substitute to wasting brain cycle about subtleties in operator precedence and associativity.
- Karliss 9y agoMy question is why shouldn't it be assuming there is no compiler error and funny pointer arithmetic. If surprising part was lack of error then 1 + "0" would be a sufficient example. Is left associativity and + operator precedence not being dependent on data types the surprising part?
- zvrba 9y agoI expected to see something more sophisticated than a simple implicit conversion to string.
- brobdingnagians 9y agoThis isn't at all surprising if you know how Java works; you could probably point out this kind of a strange feature case in nearly any language if you look hard enough. It does left to right order of operands, so 1 + 2 happens as integer addition since both operands are integers, then + "=" does string concatenation since one of the operands is a String, then "3=" + 1 evaluates as a concatenation since one of the operands is a String, giving "3=1" + 2, which evaluates to "3=12" by the same logic. Parenthesis solves this by explicitly specifying order of operations. And explicitly specifying order of operations is almost always a good idea for making sure it does what you want and maintenance purposes.
- Peaker 9y ago> you could probably point out this kind of a strange feature case in nearly any language if you look hard enough I disagree. I think it's a product of bad language design.
- guelo 9y agoThe bad design here is having implicit type conversion at all. The few characters you save with this rarely used feature are not worth the potential confusion. But it is a trade-off, Java is normally criticized in the other direction, for forcing you to be overly explicit.
- reacweb 9y agoI disagree. I am not an expert of java language subtleties, but I had no problem to predict and explain this output. I think it is a product of the language simplicity. I have a deeper knowledge of C and more experience, but I regularly fail to predict output in similar exercises.
- estomagordo 9y agoI think it's mildly amusing that Python produces a TypeError here, while the altogether stricter Java does not.
- leibnitz27 9y agoI really don't think this should be confusing - having a decent grasp on associativity and precedence is a pretty useful skill - so for example understanding WHY println(3 * 2 + "-" + 6 * 3) behaves "differently" is something I'd hope people would get. And let's be honest, you definitely don't want to 'fix' this by tweaking precedence to include types. That way madness lies. ;) Definite shout to ubernostrum's commment though - perhaps the confusing thing is that string concatenation is +, but a world of explicit Appends seems horrid, and that ship has very much sailed. Just be (maybe) glad java doesn't allow generalised operator overloading ;)
- IanCal 9y agoI think + for append is fine, it certainly seems to make sense to me that you get "helloworld" from "hello"+"world". I think the confusing thing is the type coercion. Does it make sense that "2"+3 is "23" but 2+"3" is not 5? (3*4).toString() + "=" + 3.toString() + 4.toString()) would not be as surprising that the two sides are different.
- touisteur 9y agoIn Ada the (String) concatenation operator is '&' (and of course, no implicit promotion to String there, you'll have to use your_type'Image(your_var) or with GNAT your_var'Img).
- olliej 9y agoThis is standard behaviour I would expect in most languages that have implicit type conversions. The article seems to be willfully disregarding that. I can think of no language that would not produce either that string, a fault, or (on the outside) NaN. Java is doing a completely sensible thing here. That majority of operators are left associative, and that associativity is not dependent on the types involved. Very high level let's say the grammar is: Expr :- Expr + Primitive | Primitive Primitive :- Integer | String And then determining the type is always: type(Integer) = int type(String) = string type(Expr) = type(Primitive) or minimum_type(left, right) With the simple rule (in this case) minimum_type(left, right) if (left == right) return left; return string In java the type conversions are done as pass during compile time, doing something like this for (node in AST) if (type(node) != required type) replace node with type_conversion_node(node, required_type) But none of this is java specific -- all statically typed languages (with implicit conversion) would do this. Dynamically typed languages in general cannot do this (in practice you can do a degree of it with local inference, etc), but that just changes when the type check is done. [Edit, because the same confusion about static/dynamic/strong/weak typing is being made in multiple places. Strong typing: The language does not allow you to perform an operation on a type if that operation were invalid when applied to that type. In java (to make it explicit) I could do (int[])someUnrelatedObject - that cannot be statically verified but it will fault at run time, because it is strongly typed. The equivalent in C will happily go off into the weeds and destroy everything. Weak typing: A language does not guarantee that invalid operations will be prevented. For example C and C++ do have types, and they will disallow invalid uses, but there is no guard to prevent you from casting to an unrelated type. A more extreme example is some older languages that don't even disallow argument mismatches, etc. Static typing: the types in the code are static, specifically they do not change run-to-run. The types of fields, variables, etc in the source could be inferred, or explicit by the programmer, but they are all known before the code is ever run. So C, C++, Java, etc are statically typed. Mostly. Because of Java's boneheaded array sub typing behaviour Object array[]; array[0] = someObejct; can fail at runtime due to a dynamic type check. Dynamic typing: some or all expression types are not known until the code is run, everyone knows python, js, etc (getting tired running out of steam) So anyway, you can have: Strong/Dynamic: Python, JavaScript, ... Strong/Static: Haskell, etc Weak/Dynamic: Can't think of a good example here because tired :D Weak/Static: C And obviously there's a tonne of in-between C++: all of C, plus statically type safe casts, and dynamically type safe casts Objective-C: all of C, but the ObjC object system which lets you send arbitrary messages to arbitrary targets. But you don't have to have the correct parameter types... ... And this all ignores what caused this article in the first place: implicit type conversions. These do not effect the Strong/Weak description of the language if they are well defined, eg. people often complain about string promotion, but neglect to comment on someInt + someFloat promoting the int to a float, even though such a promotion can lose data. The distinction is purely a matter of "does the language allow you to perform an operation on a value of a type that is not compatible with that operation". One way to achieve that is the say it's completely illegal: throw an exception at runtime, fail to compile, etc another alternative is to implicit convert the type to something that is valid. Note that /converting/ a value changes the value being used. Compare that to the not type safe version where you literally ignore the type of the value being used. In the case of int + float it's the difference between converting the int to a float value, and just treating the bits of the integer as if they were the bits in a float. Many apologies about the awful writing, but it's late :D
- rusk 9y agoI had to look twice at this. I was surprised that I could add the string “=“ to ‘3’. I guess what’s happening here is the int gets boxed and then gets implicitly converted to String. Proof of the pudding would be to try it with a simple string assignment rather than System.out.println. What happens after the “=“ is more straightforward
- rusk 9y agoThis code gives the same result: String splat = 1 + 2 + " = " + 1 + 2; System.out.println(splat); So the author's assertion that it is based on some `System.out.println` compiler magic is false. The JLS spec [0] accounts for this in its treatment of the '+' operator: "If the type of either operand of a + operator is String, then the operation is string concatenation." This does seem like idiosyncratic behaviour for java to be honest. I don't think it's the compiler doing it either, because this will throw a null-pointer exception: Integer borken = null; String splat = borken + 2 + " = " + 1 + 2; System.out.println(splat); EDIT: Also interesting, if I drop the language level to 1.4 I get this error: Plus.java:8: error: bad operand types for binary operator '+' String splat = borken + 2 + " = " + 1 + 2; [0] https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.18.1 https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.htm...
- yulapshun 9y agoI was expecting something more interesting, very disappointed.
- wahern 9y ago1) Left-associativity 2) The price you pay for type coercion. Be thankful Java defines the order of evaluation. Not all languages which coerce specify the order of evaluation.
- infogulch 9y agoI'm glad some of the newer languages like rust and go just dump implicit coersion altogether. Yeah it's convenient but it's not worth the headache and subtle bugs.
- sametmax 9y agoYes but that's strange. Java is such a staticaly typed language you would not expect it to do that if you are like me and don't know it very well. While Python is very dynamic, but: >>> print(1 + 2 + "=" + 1 + 2) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'int' and 'str'
- pmontra 9y agoRuby is like Python, Perl and JavaScript are like Java. Type coercion has little to do with being strongly or weakly typed, dynamically or statically typed, interpreted or compiled, which are orthogonal axis. It's more like syntactic sugar to save a str(), a .to_s or a printf pattern. Maybe the Java implementation just overloads the + operator and converts the types inside it.
- ubernostrum 9y agoStrong/weak is not a useful thing most of the time, but when people do try to define it, often they do so in terms of the presence and number of implicit conversions the language will perform for you in order to allow operations to succeed despite being provided operands of the wrong type. Also, overloading the "+" operator is basically what Java is doing, which is an odd inconsistency for a language which doesn't allow end-user code to do operator overloading.
- 9y ago
- magnat 9y agoAnd in php (after https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/ https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/): "foo" == TRUE and "foo" == 0 but TRUE != 0 123 == "123foo" but "123" != "123foo" "6" == " 6", "4.2" == "4.20" and "133" == "0133", but 133 != 0133, "0x10" == "16" and "1e3" == "1000"
- deleted 9y ago[deleted]
- lossolo 9y agoThis was touched literally on second exercises (so second hour of learning Java) on university when I learned Java.
- philliphaydon 9y agoDoes the same in .NET https://dotnetfiddle.net/0vkSCV https://dotnetfiddle.net/0vkSCV Used .NET for 15 years and never knew this...
- arnarbi 9y agoOne of these plusses is not like the other.
- pietrovismara 9y agoOh but it's not an article about how shitty javascript is, so let's just ignore it.
- _pmf_ 9y agoThe explanation is horribly wrong.