Compilation mode

Understand when to use Slice1 or Slice2.

Slice supports two compilation modes: Slice1 and Slice2. Slice2 is the default mode, recommended for most applications. Slice1 provides interoperability with Ice applications and must be enabled explicitly.

The compilation mode of a Slice file can be specified with the mode statement. This statement can only appear once per file, and must come before any other statement. For example:

slice
// Copyright (c) ACME Corp.
mode = Slice1
module Warehouse

A file without a mode statement uses the default mode: Slice2.

The compilation mode of a Slice file determines the types and features you can use in that particular file. For example, you can define a class type in a Slice1 file (a Slice file with mode = Slice1), but not in a Slice2 file (a Slice file with mode = Slice2). Conversely, you can define an operation with a stream parameter in a Slice2 file but not in a Slice1 file.

As you would expect, the Slice1 feature set is largely equivalent to the feature set of the IDL provided by Ice (the original Slice language).

Since you typically use a single compilation mode per project, this documentation is split between Slice1 and Slice2. When you select Slice2, you don't see Slice1-specific features, and vice-versa.

The mode is part of the contract between a client and a server: if you change the mode, you break the contract.

For example, the following operations are not compatible even though they are identical except for the compilation mode.

slice
mode = Slice1
module Example
interface Widget {
spin(speed: int32)
}
slice
// default mode is Slice2
module Example
interface Widget {
spin(speed: int32)
}

The encoding used for operation arguments is determined by the compilation mode. As a result, a call to spin from a client using the Slice2 file will fail if the remote service is implemented with the Slice1 file.

It is possible but uncommon to use Slice files with different modes in the same application.

If you are in this situation, you need to observe the following rules:

  • a Slice2 file can use a type defined in Slice1 file provided this type is Slice2-compatible (see below)
  • an interface defined in a Slice2 file can derive from an interface defined in a Slice1 file
  • a Slice1 file cannot use a type, an interface, or any other construct defined in a Slice2 file

A type defined in a Slice1 file is Slice2-compatible if it's an enum type, a custom type, or if this type could be defined as-is in a Slice2 file. For example:

slice
mode = Slice1
module Example
// Slice2-compatible: an enum is always Slice2-compatible.
enum Fruit { Apple, Orange }
// Slice2-compatible: `Point` could be defined as-is in a Slice2 file.
compact struct Point { x: int32, y: int32 }
// Slice2-incompatible: a class cannot be defined in a Slice2 file.
class Vehicle {
hasEngine: bool
}
// Slice2-incompatible: `VehicleCarrier` references a Slice1-only type (`Vehicle`).
compact struct VehicleCarrier {
vehicle: Vehicle?
}

The mode statement is not mapped to anything in C#. It does however influence the C# mapping of most other Slice definitions.

Was this page helpful?