Fork me on GitHub

Synthetic Functions

In this documentation page, concept of synthetic methods for the SARL compiler is introduced. The documentation summarizes what a SARL synthetic method is, how one can be created and identified, and the implications of SARL synthetic methods on SARL development.

Any constructs introduced by the SARL compiler that do not have a corresponding construct in the source code must be marked as synthetic, except for default constructors and the class initialization method. For short, a synthetic function is a SARL construct introduced by the compiler.

1. Access to private fields

The SARL compiler creates synthetic methods on nested classes when their attributes specified with the private modifier are accessed by the enclosing class.

In the following code, the privateField field is accessed from the fct function. The SARL compiler generates a synthetic function for enabling this access.

class EnclosingClass {

	static class InnerClass {
		var privateField : int
	}

	def fct(param : InnerClass) {
		System.out.println(param.privateField)
	}
}

2. Synthetic or Default Constructors

In SARL programming language, the term default constructor can refer to a constructor that is automatically generated by the compiler in the absence of any programmer-defined constructors.

When the current type has not a super-type, the compiler generates a default constructor without formal parameter. For example, the MyType class is defined without explicit constructor. An instance of this type may be created by invoking the implicit/generated default constructor, as illustrated in the fct function.

class MyType {
}

class CallingType {

	def fct {
		new MyType
	}

}

When the current type has a super-type, the compiler generates a default constructor in the current type for each visible constructor in the super-type. In this case, the generated constructors have the same erasure, i.e. parameters as the super-type’s constructors.

class MySuperType {
	new (param1 : int, param2 : String = null) {
	}
	new (param3 : String) {
	}
}

class SubType extends MySuperType {
}

class CallingType {

	def fct {
		// Call the firstsynthetic constructor
		new SubType(14)
		new SubType(14, "")

		// Call the second synthetic constructor
		new SubType("")
	}

}

3. Equality Test Functions

Equality is being used in many programming-language constructs and data types. It is used to test if an element already exists in a set, or to access to a value through a key. It is used in switch statements to dispatch the control flow to the correct branch, and during the unification process in logic programming.

In SARL programming language, objects and data structures are accessed through references. There becomes a need to test for two different types of equality:

The first type of equality is supported by the === equality test, and the !== innequality test. The second type of equality is supported by the == equality test, and the != innequality test.

3.1. Semantic Equality

Because the SARL code is translated to Java code by the SARL compiler, the == operator is mapped to the Java equals(Object) function. The != operator is mapped to the Java code !equals(Object).

The standard implementation of the == operator is usually based on the equality tests on the type’s fields. In order to help the SARL developer, he does not need to provide explicitly an implementation of the equals function. Indeed, the SARL compiler generates a synthetic equals function when fields of the following types are declared:

For example, consider the following SARL code:

class MyType {

	var field1 : int
	
	var field2 : float
	
	var field3 : String

}

The SARL compiler generates the following equals function in the Java code:

public boolean equals(Object obj) {
	if (obj instanceof MyType) {
		MyType other = (MyType) obj;
		if (this.field1 != other.field1) {
			return false;
		}
		if (this.field2 != other.field2) {
			return false;
		}
		if (!Objects.equals(this.field3, other.field3)) {
			return false;
		}
		return true;
	}
	return false;
}

3.2. Hash code

Every class implicitly or explicitly provides a hashCode() method in SARL. It digests the datastored in an instance of the type into a single hash value (a signed integer). This hash is used by other code when storing or manipulating the instance, i.e. the values are intended to be evenly distributed for varied inputs for use in clustering. This property is important to the performance of hash tables and other data structures that store objects in groups (“buckets”) based on their computed hash values. Technically, in SARL (inherited from the Java programming language), hashCode by default is a internal object reference (pointer) provided by the JVM.

The general contract for overridden implementations of the hashCode method is that they behave in a way consistent with the same object’s equals method: that a given object must consistently report the same hash value (unless it is changed so that the new version is no longer considered “equal” to the old), and that two objects which equals says are equal must report the same hash value. There’s no requirement that hash values be consistent between different SARL implementations, or even between different execution runs of the same program, and while two unequal objects having different hashes is very desirable, this is not mandatory (that is, the hash function implemented doesn’t need to be a perfect hash).

In order to help the SARL developer, the SARL compielr generates automatically the hashCode fonction when it is not explicitly defined by the developer, and fields of the following types are declared:

4. Java Serialization Mechanism

Serialization is the process of translating data structures or object state into a format that can be stored (for example, in a file or memory buffer, or transmitted across a network connection link) and reconstructed later in the same or another computer environment. When the resulting series of bits is reread according to the serialization format, it can be used to create a semantically identical clone of the original object. For many complex objects, such as those that make extensive use of references, this process is not straightforward. Serialization of object-oriented objects does not include any of their associated methods with which they were previously linked.

This process of serializing an object is also called marshalling an object. The opposite operation, extracting a data structure from a series of bytes, is deserialization, which is also called unmarshalling.

In order to have a consistent generated Java code, the SARL compiler generates the private field serialVersionUUID when the generated Java type is an implementation of the Serializable interface. This interface is used in Java programs for identifying the objects that could be subject of serialization and deserialization. The Java specification recommends to create a private static field, named serialVersionUUID for identifying the implementation of the object, and ensuring that the desrialized object is really of the same type of the serialized object.

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.