Skip to main content
added 1062 characters in body
Source Link
gnasher729
  • 47.5k
  • 4
  • 68
  • 133

The basis for type checking is not what the compiler does, it is what the language defines.

In the C language, every operand has a type. "abc" has type "array of const char". 1 has type "int". 1L has type "long". If x and y are expressions, then there are rules for the type of x + y and so on. So the compiler obviously has to follow the rules of the language.

On modern languages like Swift, the rules are much more complicated. Some cases are simple like in C. Other cases, the compiler sees an expression, has been told beforehand what type the expression should have, and determines the types of subexpressions based on that. If x and y are variables of different types, and an identical expression is assigned, that expression might be evaluated in a different way. For example assigning 12 * (2 / 3) will assign 8.0 to a Double and 0 to an Int. And you have cases where the compiler knows that two types are related and figures out what types they are based on that.

Swift example:

var x: Double
var y: Int

x = 12 * (2 / 3)
y = 12 * (2 / 3)

print (x, y)

prints "8.0, 0".

In the assignment x = 12 * (2 / 3): The left hand side has a known type Double, therefore the right hand side must have type Double. There is only one overload for the "*" operator returning Double, and that is Double * Double -> Double. Therefore 12 must have type Double, as well as 2 / 3. 12 supports the "IntegerLiteralConvertible" protocol. Double has an initialiser taking an argument of type "IntegerLiteralConvertible", so 12 is converted to Double. 2 / 3 must have type Double. There is only one overload for the "/" operator returning Double, and that is Double / Double -> Double. 2 and 3 are converted to Double. The result of 2 / 3 is 0.6666666. The result of 12 * (2 / 3) is 8.0. 8.0 is assigned to x.

In the assignment y = 12 * (2 / 3), y on the left hand side has type Int, so the right hand side must have type Int, so 12, 2, 3 are converted to Int with the result 2 / 3 = 0, 12 * (2 / 3) = 0.

The basis for type checking is not what the compiler does, it is what the language defines.

In the C language, every operand has a type. "abc" has type "array of const char". 1 has type "int". 1L has type "long". If x and y are expressions, then there are rules for the type of x + y and so on. So the compiler obviously has to follow the rules of the language.

On modern languages like Swift, the rules are much more complicated. Some cases are simple like in C. Other cases, the compiler sees an expression, has been told beforehand what type the expression should have, and determines the types of subexpressions based on that. If x and y are variables of different types, and an identical expression is assigned, that expression might be evaluated in a different way. For example assigning 12 * (2 / 3) will assign 8.0 to a Double and 0 to an Int. And you have cases where the compiler knows that two types are related and figures out what types they are based on that.

The basis for type checking is not what the compiler does, it is what the language defines.

In the C language, every operand has a type. "abc" has type "array of const char". 1 has type "int". 1L has type "long". If x and y are expressions, then there are rules for the type of x + y and so on. So the compiler obviously has to follow the rules of the language.

On modern languages like Swift, the rules are much more complicated. Some cases are simple like in C. Other cases, the compiler sees an expression, has been told beforehand what type the expression should have, and determines the types of subexpressions based on that. If x and y are variables of different types, and an identical expression is assigned, that expression might be evaluated in a different way. For example assigning 12 * (2 / 3) will assign 8.0 to a Double and 0 to an Int. And you have cases where the compiler knows that two types are related and figures out what types they are based on that.

Swift example:

var x: Double
var y: Int

x = 12 * (2 / 3)
y = 12 * (2 / 3)

print (x, y)

prints "8.0, 0".

In the assignment x = 12 * (2 / 3): The left hand side has a known type Double, therefore the right hand side must have type Double. There is only one overload for the "*" operator returning Double, and that is Double * Double -> Double. Therefore 12 must have type Double, as well as 2 / 3. 12 supports the "IntegerLiteralConvertible" protocol. Double has an initialiser taking an argument of type "IntegerLiteralConvertible", so 12 is converted to Double. 2 / 3 must have type Double. There is only one overload for the "/" operator returning Double, and that is Double / Double -> Double. 2 and 3 are converted to Double. The result of 2 / 3 is 0.6666666. The result of 12 * (2 / 3) is 8.0. 8.0 is assigned to x.

In the assignment y = 12 * (2 / 3), y on the left hand side has type Int, so the right hand side must have type Int, so 12, 2, 3 are converted to Int with the result 2 / 3 = 0, 12 * (2 / 3) = 0.

Source Link
gnasher729
  • 47.5k
  • 4
  • 68
  • 133

The basis for type checking is not what the compiler does, it is what the language defines.

In the C language, every operand has a type. "abc" has type "array of const char". 1 has type "int". 1L has type "long". If x and y are expressions, then there are rules for the type of x + y and so on. So the compiler obviously has to follow the rules of the language.

On modern languages like Swift, the rules are much more complicated. Some cases are simple like in C. Other cases, the compiler sees an expression, has been told beforehand what type the expression should have, and determines the types of subexpressions based on that. If x and y are variables of different types, and an identical expression is assigned, that expression might be evaluated in a different way. For example assigning 12 * (2 / 3) will assign 8.0 to a Double and 0 to an Int. And you have cases where the compiler knows that two types are related and figures out what types they are based on that.