Implicit type conversion: Difference between revisions

(Cleaned up task wording)
Line 989:
Checkit
</lang>
 
=={{header|Nim}}==
As a strongly typed language, Nim is very strict regarding implicit conversion. However, it provides some mechanisms which help the user to avoid to do a lot of explicit conversions.
 
By default, when doing operations or when assigning, Nim allows conversions between signed integer types (int8, int16, int32, int64), between unsigned integer types (uint8, uint16, uint32, uint64) and between floats (float32, float64). There is no implicit conversions between these three categories, except for literals.
 
Indeed, literals such as 1 are considered as being of type "int" (32 or 64 bits according to the platform). But they can be used in operations involving unsigned ints or floats. The compiler doesn’t generate code to convert but directly provide the converted value.
 
There is also implicit conversions between synonym types. If we declare <code>type MyInt = int</code>, "int" values are fully compatible with "MyInt". If we want the values to be incompatible, we have to declare <code>type MyInt = distinct int</code>. To assign a value such of 1 to a variable "x" of this type, we must use <code>x = MyInt(1)</code>.
 
The third case of implicit conversion regards the tuples. It is possible to assign named tuples to unnamed tuples and to assign unnamed tuples to named tuples without explicit conversion. But conversion between named tuples with different field names must be explicitly expressed.
 
The mechanisms allowing to avoid explicit conversions are only shortcuts. The conversion is still explicit, but done elsewhere. The first one is the overloading of procedures/operators. For instance, to avoid to specify explicit conversions when doing operations mixing integers and floats, we can import the module <code>lenientops</code> which defines a set of operators accepting mixed parameter types. These operators simply convert the integer parameter to a float, then apply the usual operator.
 
The second mechanism consists to define a converter. If, for instance, we define a converter from bool to int, then, after that, we can add ints and bools as in weakly typed languages. This mechanism is powerful, but must be used with care as it may weak the type system logic.
 
Here are some examples:
 
<lang Nim>
const A = 1 # "1" is considered as as int, so this is the type of "x".
const B: float = 1 # Implicit conversion from int to float done by the compiler.
 
var x: uint = 1 # Implicit conversion from int to uint done by the compiler.
var y = 1f32 # "y" is a float32.
var z: float64 = y # The compiler generates code to convert from float32 to float64.
 
# Tuple conversions.
# Note that these conversions doesn’t change the memory representation of the data.
 
var t1: tuple[a, b: int] # Named tuple.
var t2: tuple[c, d: int] # Named tuple, incompatible with the previous one.
var t3: (int, int) # Unnamed tuple.
 
t3 = (1, 2) # No conversion here.
t1 = t3 # Implicit conversion from unnamed to named.
t2 = (int, int)(t1) # Explicit conversion followed by an implicit conversion.
t3 = t2 # Implicit conversion from named to unnamed.
 
# Simplifying operations with "lenientops".
var f1, f2, f3: float
var i1, i2, i3: int
 
f1 = f2 + i1.toFloat * (f3 * i2.toFloat) + i3.toFloat
 
import lenientops
 
f1 = f2 + i1 * (f3 * i2) + i3 # Looks like implicit conversions for the user.
 
# Another example: / operator.
# This operator is defined for float32 and float64 operands. But is also defined
# for integer operands in "system" module. Actually, it simply converts the operands
# to float and apply the float division. This is another example of overloading
# hiding the conversions.
echo 1 / 2 # Displays 0.5.
 
# Converter examples.
# The following ones are absolutely not recommended as Nim is not C or Python.
converter toInt(b: bool): int = ord(b)
converter toBool(i: int): bool = i != 0
 
echo 1 + true # Displays 2.
if 2: echo "ok" # Displays "ok".</lang>
 
=={{header|Oforth}}==
Anonymous user