Fork me on GitHub

Cast and Type Conversions

Because SARL is statically-typed at compile time, after a variable is declared, it cannot be declared again or assigned a value of another type unless that type is implicitly convertible to the variable’s type. For example, the String cannot be implicitly converted to int. Therefore, after you declare i as an int, you cannot assign the string "Hello" to it, as the following code shows:

var i : int
i = "Hello" // Error: "Cannot cast String to int"

However, you might sometimes need to copy a value into a variable or method parameter of another type. For example, you might have an integer variable that you need to pass to a method whose parameter is typed as double. Or you might need to assign a class variable to a variable of an interface type. These kinds of operations are called type conversions. In SARL, you can perform the following kinds of conversions:

1. Implicit Conversions

For built-in types, e.g. numeric types, an implicit conversion can be made when the value to be stored can fit into the variable without being truncated or rounded off. For example, a variable of type long (64-bit integer) can store any value that an int (32-bit integer) can store. In the following example, the compiler implicitly converts the value of num on the right to a type long before assigning it to bigNum.

var num : int = 2147483647
var bigNum : long = num

The following table shows the predefined implicit conversions between SARL types.

From To
T[] List
boolean Boolean
Boolean boolean
byte Byte, short, int, long, float, double
Byte byte, short, int, long, float, double
char Character, String
Character char, String
double Double
Double double
float Float, double
Float float, double
int Integer, long, float, double
Integer int, long, float, double
List T[]
long Long, float, double
Long long, float, double
short Short, int, long, float, double
Short short, int, long, float, double
String char, Character (if string length is 1)

2. Explicit Conversions

However, if a conversion cannot be made without a risk of losing information, the compiler requires that you perform an explicit conversion, which is called a cast. A cast is a way of explicitly informing the compiler that you intend to make the conversion and that you are aware that data loss might occur. To perform a cast, specify the value or variable to be converted, followed by the as keyword and the type that you are casting. The following program casts a double to an int. The program will not compile without the cast.

var x : double = 1234.7
var a : int
// Cast double to int.
a = x as int

For object types, an explicit cast is required if you need to convert from a base type to a derived type:

// Create a new derived type
var g = new Giraffe

// implicit conversion to base type is safe.
var a : Animal = g

// Explicit conversion is required to cast back to derived type.
// Note: This will compile but will throw an exception at run time if the right-side
// object is not in fact a Giraffe.
var g2 : Giraffe
g2 = a as Giraffe

A casting operation between reference types does not change the run-time type of the underlying object; it only changes the type of the value that is being used as a reference to that object.

The following table shows the predefined explicit conversions that are predefined into SARL.

From To
boolean String
byte byte, short, int, long, float, double, AtomicInteger, AtomicLong, AtomicDouble, BigInteger, BigDecimal
char String
double byte, short, int, long, float, double, AtomicInteger, AtomicLong, AtomicDouble, BigInteger, BigDecimal
float byte, short, int, long, float, double, AtomicInteger, AtomicLong, AtomicDouble, BigInteger, BigDecimal
int byte, short, int, long, float, double, AtomicInteger, AtomicLong, AtomicDouble, BigInteger, BigDecimal
long byte, short, int, long, float, double, AtomicInteger, AtomicLong, AtomicDouble, BigInteger, BigDecimal
Number byte, short, int, long, float, double, AtomicInteger, AtomicLong, AtomicDouble, BigInteger, BigDecimal
Object String
short byte, short, int, long, float, double, AtomicInteger, AtomicLong, AtomicDouble, BigInteger, BigDecimal
String boolean, char, byte, short, int, long, float, double, AtomicInteger, AtomicLong, AtomicDouble
  BigInteger, BigDecimal

3. Type Conversion Exceptions at Run Time

In some reference type conversions, the compiler cannot determine whether a cast will be valid. It is possible for a casting operation that compiles correctly to fail at run time. As shown in the following example, a type cast that fails at run time will cause an ClassCastException to be thrown.

class Animal {}

class Reptile extends Animal {}

class Mammal extends Animal {}

class Test {
    static def main {
    	test(new Mammal())
    }
	static def test(a : Animal) {
		// Cause a ClassCastException at run time
		// because Mammal is not convertible to [:reptiletype].
		var r : Reptile
		r = a as Reptile
	}
}

SARL provides the instanceof operator to enable you to test for compatibility before actually performing a cast.

The instanceof operator evaluates type compatibility at runtime. It determines whether an object instance or the result of an expression can be converted to a specified type. It has the syntax:

expr instanceof type

where expr is an expression that evaluates to an instance of some type, and type is the name of the type to which the result of expr is to be converted. The instanceof operator is true if expr is non-null and the object that results from evaluating the expression can be converted to type; otherwise, it returns false.

4. Conversion Operators

SARL enables programmers to declare conversions on classes or basic types so that classes or basic types can be converted to and/or from other classes or basic types. Conversions are associated to the as type casting operator. When the compiler cannot proceed an implicit nor explicit casting, it tries to find within the current code scope the definition of a casting operator function. Depending on the category of the type to cast to, the name of this casting operator function is different:

Additionnally, the return type of the casting operator function must be the cast type, and not a sub-type of the type specified as right operand of the casting operator.

A single parameter may be specified or not. If it is specified, it is the expression to cast. It means that the type of the formal parameter is the expected type of the expression. If the formal parameter is omitted, the current object (this) is assumed to be converted.

In the following example, the function toInteger is defined for converting a Type to Integer. When the expression obj as Integer is evaluated by the compiler, the function toInteger is discovered and used for proceeding the cast.

class Type {
	def toInteger : Integer { 0 }
}
class Test {
    def main {
    	var obj : Type
    	var value = obj as Integer
    }
}

In the second example below, the function toInteger is defined in the same class as the one where the cast operator is defined. When the expression obj as Integer is evaluated by the compiler, the function toInteger is discovered and used for proceeding the cast.

class Type {
}
class Test {
    def main {
    	var obj : Type
    	var value = obj as Integer
    }
	def toInteger(v : Type) : Integer { 0 }
}

Any function that is declared into the scope of the cast operator, and following the rules that are described above, may be a candidate for being the cast operator function.

The two previous example have an object type as the cast type. The two following examples have the basic type int. The declarations of the toInteger are replaced by declarations of intValue.

class Type {
	def intValue : int { 0 }
}
class Test {
    def main {
    	var obj : Type
    	var value = obj as int
    }
}
class Type {
}
class Test {
    def main {
    	var obj : Type
    	var value = obj as int
    }
	def intValue(v : Type) : int { 0 }
}

5. Acknowledgements

This documentation is inspired by the documentations from the Xtext and Xtend projects.

Copyright © 2014-2023 SARL.io, the Original Authors and Main Authors.

Documentation text and medias are licensed under the Creative Common CC-BY-SA-4.0; you may not use this file except in compliance with CC-BY-SA-4.0. You may obtain a copy of CC-BY-4.0.

Examples of SARL code are licensed under the Apache License, Version 2.0; you may not use this file except in compliance with the Apache License. You may obtain a copy of the Apache License.

You are free to reproduce the content of this page on copyleft websites such as Wikipedia.

Generated with the translator docs.generator 0.14.0-SNAPSHOT.