Fields

6 min read

7 min read

9 min read

7 min read

8 min read

6 min read

6 min read

6 min read

7 min read

A field is defined as Type name, where Type is the field's type and name is the field's name. For example:

Slice
string name;
ByteSeq image;
Fruit fruit;

Each field definition must be followed by a semicolon. You can define several fields on the same line if you wish, as in:

Slice
struct Point { int x; int y; }

The type of a field can be a basic type, a user-defined type, Object* (an untyped proxy), or Value(an untyped class instance).

Fields with proxy and class types are nullable. Optional fields (presented below) are also nullable. All other fields are non-nullable, meaning they must have a value when transmitted through Ice.

Slice
struct Example
{
int count; // must be set
Greeter* greeter; // proxy type, so it can be null
Node node; // class type, so it can be null
}

A field of a Slice class or exception may be declared as optional to indicate that a program can leave its value unset. Fields not declared as optional are known as required fields; a program must supply legal values for all required fields.

Each optional field must be assigned a unique, non-negative integer tag:

Slice
module M
{
class C
{
string name;
bool active;
optional(2) string alternateName;
optional(5) int overrideCode;
}
}

It is legal for a base type's tag to be reused by a derived type:

Slice
exception BaseException
{
optional(1) int systemCode;
}
exception DerivedException extends BaseException
{
optional(1) string diagnostic; // OK
}

The scope of a tag is limited to its enclosing type and has no effect on base or derived types.

Optional fields and required fields can appear in any order in your class definition. You can also assign tags in any order. For example:

Slice
class UnusualButValidPerson
{
optional(5) string nickname;
string name;
optional(0) Date dateOfBirth; // Date is a struct
string currentAddress;
optional(123) Fruit favoriteFruit; // Fruit is an enum
}

You can specify a default value for a field that has one of the following types:

For example:

Slice
struct Location
{
string name;
Point pt;
bool display = true;
string source = "GPS";
}

The legal syntax for literal values is the same as for Slice constants, and you may also use a constant as a default value. The language mapping guarantees that fields are initialized to their declared default values using a language-specific mechanism.

You can declare a default value for optional fields just as you can for required fields:

Slice
class C
{
string name;
bool active = true;
optional(2) string alternateName;
optional(5) int overrideCode = -1;
}

An optional field with a default value is considered to be set by default.

A Slice field maps to a C++ data member with the same name. The type of the C++ data member is the default, memory-owning, mapping of the Slice type.

For example:

Slice
struct Person
{
string name;
}

maps to:

C++
struct Person
{
std::string name; // not std::string_view
...
};

A Slice field with a class type maps to a C++ data member with a shared pointer type. For example:

Slice
class Address { ... }
struct Person
{
string name;
Address address;
}

maps to:

C++
class Address { ... };
using AddressPtr = std::shared_ptr<Address>;
struct Person
{
std::string name;
AddressPtr address; // can be null
...
};

A Slice field with a proxy type maps to a C++ data member with a std::optional<T> type. For example:

Slice
interface Widget { ... }
struct Person
{
Widget* favoriteWidgetProxy;
}

maps to:

C++
class WidgetPrx { ... };
struct Person
{
std::optional<WidgetPrx> favoriteWidgetProxy; // can be nullopt
...
};

An optional field maps to a C++ data member with the same name. The data member's type is the mapped type, wrapped in a std::optional. The tag value is not mapped to C++.

For example:

Slice
class C
{
optional(2) string alternateName;
optional(5) int overrideCode;
optional(1) Widget* favoriteWidgetProxy;
}

maps to:

C++
class C
{
std::optional<std::string> alternateName;
std::optional<std::int32_t> overrideCode;
std::optional<WidgetPrx> favoriteWidgetProxy; // single optional
...
};

Proxies are not wrapped twice in std::optional, as illustrated above. As a result, you cannot distinguish between an optional proxy field that is not set and an optional proxy field set to null.

Slice default values map to default member initializers in C++.

For example:

Slice
struct Location
{
string name;
Point point;
bool display = true;
string source = "GPS";
}

maps to:

C++
struct Location
{
std::string name;
Point point;
bool display{true};
std::string source{"GPS"};
...
};

A Slice field maps to a C# field, with by default the same name. The type of the C# field is the mapped Slice type.

In C#, we often remap the field name with cs:identifier to convert the name for Pascal case. For example:

Slice
class Address { ... }
struct Person
{
["cs:identifier:Name"]
string name;
["cs:identifier:Address"]
Address address;
}

maps to:

C#
public sealed partial record class Person
{
public string Name = ""; // Slice string maps to C# string
public Address? Address; // Slice Address maps the nullable C# Address
...
}

An optional field maps to a C# field with the same name. The mapped field’s type is nullable, and the tag value is not mapped to C#.

For example:

Slice
class C
{
["cs:identifier:AlternateName"]
optional(2) string alternateName;
["cs:identifier:OverrideCode"]
optional(5) int overrideCode;
["cs:identifier:FavoriteWidgetProxy"]
optional(1) Widget* favoriteWidgetProxy;
}

maps to:

C#
public partial class C : Ice.Value
{
public string? AlternateName;
public int? OverrideCode;
public WidgetPrx? FavoriteWidgetProxy;
...
}

Optional and non-optional proxies are mapped the same way, as illustrated above. As a result, you cannot distinguish between an optional proxy field that is not set and an optional proxy field set to null.

Slice default values map to default values in C#.

For example:

Slice
struct Location
{
["cs:identifier:Name"]
string name;
["cs:identifier:Point"]
Point point;
["cs:identifier:Display"]
bool display = true;
["cs:identifier:Source"]
string source = "GPS";
}

maps to:

C#
public sealed partial record class Location
{
public string Name = "";
public Point Point;
public bool Display = true;
public string Source = "GPS";
...
}

When you don’t define a default value in Slice, and you initialize a field without providing a value for this field, the generated code uses the following default:

Optional Field?Slice Field TypeC# Default Value
No
string
Empty string
enum
default
struct
default (when the struct is mapped to a C# struct), null! (when the struct is mapped to a C# class)
Numeric
0
bool
false
sequence, dictionary
null!
class, proxy
null
Yes
Any
null

A Slice field maps to a Java field with the same name. The type of the Java field is the mapped Slice type. This is the default mapping.

For example:

Slice
class Address { ... }
struct Person
{
string name;
Address address;
}

maps to:

Java
public final class Person implements java.lang.Cloneable, java.io.Serializable {
public String name; // Slice string maps to Java String
public Address address; // Slice Address maps the Java Address
...
}

Use the metadata directive java:getset to map a Slice field to two or more JavaBean-style methods instead of a public field.

For each field val of type T, the mapping generates the following methods:

Java
public T getVal();
public void setVal(T v);

The mapping generates an additional method if T is the bool type:

Java
public boolean isVal();

Finally, if T is a sequence type with an element type E, two methods are generated to provide direct access to elements:

Java
public E getVal(int index);
public void setVal(int index, E v);

Note that these element methods are only generated for sequence types that use the default mapping.

You can apply the java:getset directive to an individual field, or to enclosing construct, as illustrated by the following example:

Slice
sequence<int> IntSeq;
class C
{
["java:getset"] int i;
double d;
}
["java:getset"]
struct S
{
bool b;
string str;
}
["java:getset"]
exception E
{
IntSeq seq;
}

JavaBean get-set methods are generated for all fields of struct S and exception E, but for only one field of class C. Relevant portions of the generated code are shown below:

Java
public class C extends com.zeroc.Ice.Value {
private int i;
public double d;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
public final class S implements java.lang.Cloneable, java.io.Serializable {
private boolean b;
private java.lang.String str;
public boolean getB() {
return b;
}
public void setB(boolean b) {
this.b = b;
}
public boolean isB() {
return b;
}
public java.lang.String getStr() {
return str;
}
public void setStr(java.lang.String str) {
this.str = str;
}
...
}
public class E extends com.zeroc.Ice.UserException {
private int[] seq;
public int[] getSeq() {
return seq;
}
public void setSeq(int[] seq) {
this.seq = seq;
}
public int getSeq(int index) {
return this.seq[index];
}
public void setSeq(int index, int val) {
this.seq[index] = val;
}
...
}

The mapping for optional fields in Slice classes and exceptions uses a JavaBean-style API that provides methods to get, set, and clear a field’s value, and test whether a value is set. Consider the following Slice definition:

Slice
class C
{
string name;
optional(2) string alternateName;
optional(5) bool active;
}

The generated Java code provides the following API:

Java
public class C extends com.zeroc.Ice.Value {
public String getAlternateName()...
public void setAlternateName(String alternateName)...
public boolean hasAlternateName()...
public void clearAlternateName()...
public void optionalAlternateName(java.util.Optional<String> v)...
public java.util.Optional<String> optionalAlternateName()...
public boolean isActive()...
public boolean getActive()...
public void setActive(boolean v)...
public boolean hasActive()...
public void clearActive()...
public void optionalActive(java.util.Optional<Boolean> v)...
public java.util.Optional<Boolean> optionalActive()...
...
}

The has method allows you to test whether a field’s value has been set, and the clear method removes any existing value for a field.

The optional methods provide an alternate API that uses standard Java types to encapsulate the value:

  • java.util.OptionalDouble Encapsulates a value of type double
  • java.util.OptionalInt Encapsulates a value of type int
  • java.util.OptionalLong Encapsulates a value of type long
  • java.util.Optional<T> Encapsulates all other Slice types

Slice default values change the implementation of the parameterless constructor of the enclosing type.

For example:

Slice
struct Location
{
string name;
Point point;
bool display = true;
string source = "GPS";
}

maps to:

Java
public final class Location implements java.lang.Cloneable, java.io.Serializable {
public String name;
public Point point;
public boolean display;
public String source;
public Location() {
this.name = "";
this.point = new Point();
this.display = true;
this.source = "GPS";
}
...
}

When you don’t define a default value in Slice, and you initialize a field without providing a value for this field, the generated code uses the following default:

Optional Field?Slice Field TypeDefault Java Value
No
string
Empty string
enum
First enumerator in enumeration
struct
New instance created with no argument
Numeric
0
bool
false
class, proxy, sequence, dictionary
null
Yes
Any
Not set

A Slice field maps to a JavaScript class field with the same name. The type of the JavaScript field is the mapped Slice type.

For example:

Slice
class Address { string city; }
struct Person {
string name;
Address address;
}

Generates the following JavaScript code:

JavaScript
M.Person = class {
constructor(name = "", address = null) {
this.name = name;
this.address = address;
}
....
};

And the corresponding TypeScript declarations:

TypeScript
export class Address extends Ice.Value {
constructor(city?: string);
...
city: string;
}
export class Person {
constructor(name?: string, address?: Address);
...
name: string;
address: Address | null;
}

An optional field maps to a JavaScript class field with the same name. The mapped field’s type is optional, and the tag value is not mapped to JavaScript.

For example:

Slice
class C
{
optional(2) string alternateName;
optional(5) int overrideCode;
optional(1) Widget* favoriteWidgetProxy;
}

Generates the following JavaScript code:

JavaScript
M.C = class extends Ice.Value {
constructor(
alternateName = undefined,
overrideCode = undefined,
favoriteWidgetProxy = undefined) {
super();
this.alternateName = alternateName;
this.overrideCode = overrideCode;
this.favoriteWidgetProxy = favoriteWidgetProxy;
}
...
}

And the corresponding TypeScript declarations:

TypeScript
export class C extends Ice.Value {
constructor(
alternateName?: string,
overrideCode?: number,
favoriteWidgetProxy?: WidgetPrx);
alternateName?: string;
overrideCode?: number;
favoriteWidgetProxy?: WidgetPrx | null;
...
}

Slice default values map to default values in JavaScript.

For example:

Slice
class Point { int x; int y; }
struct Location
{
string name;
Point point;
bool display = true;
string source = "GPS";
}

Generates the following JavaScript code:

JavaScript
M.Location = class {
constructor(name = "", point = null, display = true, source = "GPS") {
this.name = name;
this.point = point;
this.display = display;
this.source = source;
}
...
}

Generates the following JavaScript code:

TypeScript
export class Location {
constructor(name?: string, point?: Point, display?: boolean, source?: string);
name: string;
point: Point | null;
display: boolean;
source: string;
}

When you don’t define a default value in Slice, and you initialize a field without providing a value for this field, the generated code uses the following default:

Optional Field?Slice Field TypeDefault JavaScript Value
No
string
Empty string
enum
First enumerator in enumeration
struct
New instance created with no argument
Numeric
0
bool
false
sequence, dictionary, class, proxy
null
Yes
Any
undefined

A Slice field maps to a MATLAB property, with by default the same name. We often remap the field name with matlab:identifier to convert the name to Pascal case.

The MATLAB class for the property is the mapped type, as presented earlier, except the following properties don’t specify a MATLAB class:

  • properties mapped from optional fields
  • properties mapped from fields of class type or that reference class types.

The size and validation function(s) of each property depends on the field type:

Slice Field TypeMATLAB SizeMATLAB Validation FunctionRemarks
bool, numeric type, enum, dictionary
Scalar: (1, 1)
string
(1, :)
An empty array (of char) represents an empty string.
sequence
(1, :)
An empty array or an empty cell array represents an empty sequence.
class, proxy
No size constraint
{mustBeScalarOrEmpty}
An empty array represents a null class instance or null proxy.
struct
No size constraint
{mustBeScalarOrEmpty}
An empty array is a temporary value. Replace this empty array with a scalar.

For example:

Slice
class Address { ... }
struct Person
{
["matlab:identifier:Name"]
string name;
["matlab:identifier:Address"]
Address address;
}

maps to:

MATLAB
classdef Address < Ice.Value
...
end
classdef (Sealed) Person
properties
Name (1, :) char
% empty corresponds to null
Address {mustBeScalarOrEmpty} = Example.Address.empty
end
...
end

An optional field maps to a MATLAB property just like a regular field, except you can also set this property to the marker value Ice.Unset. The tag value is not mapped to MATLAB.

A well-behaved program must test a MATLAB property (mapped from an optional field) before using its value:

MATLAB
obj = ...;
if obj.OptionalField ~= Ice.Unset
fprintf('OptionalField = %s\n', obj.OptionalField);
else
fprintf('OptionalField is unset\n');
end

Slice default values are mapped to default MATLAB property values.

For example:

Slice
struct Location
{
["matlab:identifier:Name"]
string name;
["matlab:identifier:Point"]
Point point;
["matlab:identifier:Display"]
bool display = true;
["matlab:identifier:Source"]
string source = "GPS";
}

maps to:

MATLAB
classdef (Sealed) Location
properties
Name (1, :) char
Point Example.Point {mustBeScalarOrEmpty} = Example.Point.empty
Display (1, 1) logical = true
Source (1, :) char = sprintf('GPS')
end
methods
function obj = Location(Name, Point, Display, Source)
if nargin > 0
assert(nargin == 4, 'Invalid number of arguments');
obj.Name = Name;
obj.Point = Point;
obj.Display = Display;
obj.Source = Source;
end
end
...
end
end

When you don’t define a default value in Slice, and you initialize a property without providing a value for this property, the generated code uses the following default:

Optional Field?Slice Field TypeMATLAB Default Value
No
bool, numeric type
0 (implicit default)
string
Empty 1-by-0 array of char (implicit default)
enum
First enumerator (implicit default)
Object*, proxy
MappedPrx.empty(implicit default)
Value, class, struct
MappedType.empty(implicit default when the MATLAB class is specified)
sequence
MappedElementType.empty(implicit default), or {} (implicit default when the MATLAB class is specified).
dictionary
configureDictionary('keyType', 'valueType')
Yes
Any
Ice.Unset

A Slice field maps to a PHP public variable with the same name.

For example:

Slice
class Address { ... }
struct Person
{
string name;
Address address;
}

maps to:

PHP
class Address extends \Ice\Value
{
...
}
class Person
{
public $name;
public $address;
public function __construct($name='', $address=null)
{
$this->name = $name;
$this->address = $address;
}
...
}

An optional field maps to a PHP public variable with the same name. Tag values are not mapped to PHP.

For example:

Slice
class C
{
optional(2) string alternateName;
optional(5) int overrideCode;
optional(1) Widget* favoriteWidgetProxy;
}

maps to:

PHP
class C extends \Ice\Value
{
public $alternateName;
public $overrideCode;
public $favoriteWidgetProxy;
public function __construct($alternateName=\Ice\None, $overrideCode=\Ice\None, $favoriteWidgetProxy=\Ice\None)
{
$this->alternateName = $alternateName;
$this->overrideCode = $overrideCode;
$this->favoriteWidgetProxy = $favoriteWidgetProxy;
}
...
}

The default value for optional fields is \Ice\None; it represents the “not set” value.

Slice default values map to default values in the constructor of the mapped class.

For example:

Slice
struct Location
{
string name;
Point point;
bool display = true;
string source = "GPS";
}

maps to:

PHP
class Location
{
public $name;
public $point;
public $display;
public $source;
public function __construct($name='', $point=null, $display=true, $source="GPS")
{
$this->name = $name;
$this->point = is_null($point) ? new \Example\Point : $point;
$this->display = $display;
$this->source = $source;
}
...
}

When you don’t define a default value in Slice, and you initialize a field without providing a value for this field, the generated code uses the following default:

Optional Field?Slice Field TypeDefault PHP Value
No
string
Empty string
enum
First enumerator in enumeration
struct
New instance created with no argument
Numeric
0
bool
false
sequence, dictionary, class, proxy
null
Yes
Any
\Ice\None

A Slice field maps to a Python dataclass field with the same name. The type of the Python field is the mapped Slice type.

For example:

Slice
class Address { ... }
struct Person
{
string name;
Address address;
}

maps to:

Python
@dataclass
class Person:
name: str = ""
address: Address | None = None

An optional field maps to a Python field with the same name. The mapped field’s type is the mapped type or None, and the tag value is not mapped to Python.

For example:

Slice
class C
{
optional(2) string alternateName;
optional(5) int overrideCode;
optional(1) Widget* favoriteWidgetProxy;
}

maps to:

Python
@dataclass(eq=False)
class C(Value):
alternateName: str | None = None
overrideCode: int | None = None
favoriteWidgetProxy: WidgetPrx | None = None

Optional and non-optional proxies are mapped the same way, as illustrated above. As a result, you cannot distinguish between an optional proxy field that is not set and an optional proxy field set to null (None).

Slice default values map to default values in Python.

For example:

Slice
struct Location
{
string name;
Point point;
bool display = true;
string source = "GPS";
}

maps to:

Python
@dataclass(order=True, unsafe_hash=True)
class Location:
name: str = ""
point: Point = field(default_factory=Point)
display: bool = True
source: str = "GPS"

When you don’t define a default value in Slice, and you initialize a field without providing a value for this field, the generated code uses the following default:

Optional Field?Slice Field TypeDefault Python Value
No
string
Empty string
enum
First enumerator in enumeration
struct
New instance created with no argument
Numeric
0
bool
False
sequence, dictionary
Empty list, empty dictionary
class, proxy
None
Yes
Any
None

A Slice field maps to a Ruby instance variable with the same name, plus accessors to read and write this instance variable.

For example:

Slice
class Address { ... }
struct Person
{
string name;
Address address;
}

maps to:

Ruby
class Address < Ice::Value
...
end
class Person
attr_accessor :name, :address
def initialize(name='', address=nil)
@name = name
@address = address
end
...
end

An optional field maps to a Ruby instance variable and accessors, just like a non-optional field. Tag values are not mapped to Ruby.

For example:

Slice
class C
{
optional(2) string alternateName;
optional(5) int overrideCode;
optional(1) Widget* favoriteWidgetProxy;
}

maps to:

Ruby
class C < Ice::Value
attr_accessor :alternateName, :overrideCode, :favoriteWidgetProxy
def initialize(alternateName=Ice::Unset, overrideCode=Ice::Unset, favoriteWidgetProxy=Ice::Unset)
@alternateName = alternateName
@overrideCode = overrideCode
@favoriteWidgetProxy = favoriteWidgetProxy
end
end

The default value for optional fields is Ice::Unset; it represents the “not set” value.

Slice default values map to default values in the mapped initialize method.

For example:

Slice
struct Location
{
string name;
Point point;
bool display = true;
string source = "GPS";
}

maps to:

Ruby
class Location
attr_accessor :name, :point, :display, :source
def initialize(name='', point=::Example::Point.new, display=true, source="GPS")
@name = name
@point = point
@display = display
@source = source
end
def hash
...
end
def ==(other)
...
end
def eql?(other)
...
end
end

When you don’t define a default value in Slice, and you initialize a field without providing a value for this field, the generated code uses the following default:

Optional Field?Slice Field TypeDefault Ruby Value
No
string
Empty string
enum
First enumerator in enumeration
struct
New instance created with no argument
Numeric
0
bool
false
sequence, dictionary, class, proxy
nil
Yes
Any
Ice::Unset

A Slice field maps to a Swift property with the same name. The type of the property is the mapped Slice type. When the Slice field is non-optional, the property type is non-optional as well, except for class and proxy fields.

For example:

Slice
class Address { ... }
struct Person
{
string name;
Address address;
}

maps to:

Swift
public final class Person {
public var name: String = "" // non-optional String
public var address: Address? = nil // optional Address
...
}

An optional field maps to a Swift stored property with the same name. The mapped property’s type is optional. The tag value is not mapped to Swift.

For example:

Slice
class C
{
optional(2) string alternateName;
optional(5) int overrideCode;
optional(1) Widget* favoriteWidgetProxy;
}

maps to:

Swift
open class C: Ice.Value {
public var alternateName: String? = nil
public var overrideCode: Int32? = nil
public var favoriteWidgetProxy: WidgetPrx? = nil
...
}

Optional and non-optional proxies are mapped the same way, as illustrated above. As a result, you cannot distinguish between an optional proxy property that is not set and an optional proxy property set to nil.

Slice default values map to default property values in Swift.

For example:

Slice
struct Location
{
string name;
Point point;
bool display = true;
string source = "GPS";
}

maps to:

Swift
public struct Location: Hashable, Sendable {
public var name: String = ""
public var point: Point = Point()
public var display: Bool = true
public var source: String = "GPS"
...
}

When you don’t define a default value in Slice, and you initialize a property without providing a value for this property, the generated code uses the following default:

Optional Field?Slice Field TypeDefault Swift Value
No
string
Empty string
enum
First enumerator in enumeration
struct
New instance created with no argument
Numeric
0
bool
false
sequence
Empty array
dictionary
Empty dictionary
class, proxy
nil
Yes
Any
nil