In Java 3 = 12
virtualspecies.com
virtualspecies.com
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.
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'Does static vs dynamic also imply that the strong-ness is checked at compile vs runtime? In other words, in python this bug can lurk undetected in your code
list = (1, 2, 3)
x = list + 1
while in Java it will throw the error at compile time int[] list = {1, 2, 3}
Object x = list + 1Well, if you use Python 3 and a modern editor, you will get a big red warning. mypy has been able to check types for a while and a lot of editors embed it.
Thinking about this more, if all that strong vs weak is referring to is implicit type coercions then it is a useless confusing term. Static vs dynamic refers to when the type checking occurs, implicit type coercions are just one of the things the type checker looks for.
- In statically-typed languages, variables are containers, which allow only objects of a certain type to be contained within.
- In dynamically-typed languages, variables are more like labels which can be attached to different objects, which can be of different types.
Each of these approaches have its merits, which is obvious when you look at all the lengths languages of one type go to to emulate the features of the other: interfaces and generics in statically-typed languages, or type hints and statical checkers in dynamic ones. But I have yet to see a language that would offer both types of variables...
As a Python developer, I can easily imagine a PEP that would introduce some kind of "container variables" that would accept only properly typed objects and throw a syntax error if a violation occurs at compile time. But I'm not holding my breath, with a language which ironically doesn't even have an implementation for constants.
It's less like "implies" and more like "it's the definition of".
you are seeing this error because python is strong typing language.
but this is weird that java is also strong typing language[0]
0: https://en.m.wikipedia.org/wiki/Java_(programming_language)
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.
Python, on the other hand, does not need to do a typing pass at parse-time. Instead, literals are stored as values, and those values are tagged with their source class. Python's way of doing it means that a + operation is called upon with an integer and a string.
Java might be able to yield the same kind of result as Python if it had operator overloading. It could define Integer's + operator as only taking other Integer values, therein yielding a type error at parse-time.
My own language uses ++ instead of + to distinguish between addition and concatenation, though I've considered some other token since the two are quite similar to each other.
Are you saying that Python can't make "a"+1 become "a1" because it lacks static typing? That's not true. If they wanted to, they could have added an overload for the string+integer case.
> Java might be able to yield the same kind of result as Python if it had operator overloading.
Not necessary. They would have just had to omit the built-in overload for string+integer (and perhaps also for string+object, given the newish auto-boxing feature).
All static typing does is mean that the type check, and so decision to insert the conversion call is done at compile time. Dynamic typing just means that the type check and decision to insert the conversion is done at the point the + is evaluated.
However, I do dislike relying on automatic type coercion anyway, because my intuition is not good at predicting what will happen, and I am too lazy to learn all the rules. ;-)
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.
I disagree. I think it's a product of bad language design.
https://dotnetfiddle.net/0vkSCV
Used .NET for 15 years and never knew this...
(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.htm...
Second time I've seen something like this on HN.
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 ;)
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."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"
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...
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.
See page 24 of 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.
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.
Coming from other languages maybe it does look a bit odd though
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.htm...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
- operator precedence
- implicit type casting
- how operator+ is defined per each type (e.g: numbers add, strings concatenate)
(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.