Upgrade Guide
25 min read
22 min read
19 min read
15 min read
18 min read
17 min read
24 min read
16 min read
19 min read
Learn how to upgrade your application from Ice 3.7 to Ice 3.8.
This page guides you through the upgrade process for an application that uses Ice 3.7. We recommend reading the release notes for a general list changes and improvements.
Ice 3.8 does not maintain binary compatibility or source compatibility with Ice 3.7. When upgrading, you need to recompile your Slice files and in some cases update your source code to use the latest APIs.
Requirements
Supported Platforms for Ice 3.8.3 lists the operating systems, compilers and language versions that Ice 3.8.3 supports.
Packaging
Many Slice compilers such as slice2cs, slice2swift, etc. are no longer available as part of the general installation of the Linux, macOS, and Windows packages. To use these compilers, install the appropriate language-specific package.
C++ NuGet Package
The C++ NuGet package has been renamed to ZeroC.Ice.Cpp.
This package replaces the old zeroc.ice.vXXX packages from Ice 3.7.
It also includes the Slice tools for C++, so the zeroc.icebuilder.msbuild package is no longer required.
Upgrade Steps
Using the Visual Studio NuGet UI
Right-click your VC++ project → Manage NuGet Packages…
On the Installed tab, uninstall:
zeroc.icebuilder.msbuild- all
zeroc.ice.vXXXpackages
On the Browse tab, search for
ZeroC.Ice.Cpp.Select the desired 3.8 version and click Install.
Rebuild the solution.
C# NuGet Packages
The monolithic zeroc.ice.net package has been replaced with modular NuGet packages.
| Package | Description |
|---|---|
iceboxnet | The IceBox server for .NET, packaged as a dotnet tool. |
ZeroC.Glacier2 | The Glacier2 assembly, used by Glacier2 client applications. |
ZeroC.Ice | The main Ice assembly. |
ZeroC.Ice.Slice.Tools | The Slice compiler ( slice2cs) and MSBuild integration. Replaces the zeroc.icebuilder.msbuild package. |
ZeroC.IceBox | The IceBox assembly. |
ZeroC.IceDiscovery | The IceDiscovery plug-in. |
ZeroC.IceGrid | The IceGrid assembly, used by IceGrid client applications. |
ZeroC.IceLocatorDiscovery | The IceLocatorDiscovery plug-in. |
ZeroC.IceStorm | The IceStorm assembly, used by publishers and subscribers for IceStorm. |
Upgrade Steps
Using the Visual Studio NuGet UI
Right-click your C# project → Manage NuGet Packages…
On the Installed tab, uninstall:
zeroc.icebuilder.msbuildzeroc.ice.net
Install the required Ice 3.8 packages:
At minimum, install:
ZeroC.Ice.Slice.ToolsZeroC.Ice
If your project depends on additional Ice services (e.g., Glacier2, IceGrid, IceStorm), install the corresponding package as listed in the package table above.
Select the desired 3.8 version and click Install.
Rebuild the solution.
Editing the Project File
The Ice 3.8 assemblies target .NET 8. Set the TargetFramework of your project to net8.0 or later, then replace the package references:
<PropertyGroup>- <TargetFramework>net6.0</TargetFramework>+ <TargetFramework>net8.0</TargetFramework></PropertyGroup><ItemGroup> <SliceCompile Include="../slice/Greeter.ice" />- <PackageReference Include="zeroc.ice.net" Version="3.7.*" />- <PackageReference Include="zeroc.icebuilder.msbuild" Version="5.0.9" />+ <PackageReference Include="ZeroC.Ice" Version="3.8.*" />+ <PackageReference Include="ZeroC.Ice.Slice.Tools" Version="3.8.*" PrivateAssets="all" /></ItemGroup>Add a PackageReference for each service package your project uses, such as ZeroC.IceStorm.
iceboxnet, the IceBox server for .NET, is no longer an executable inside the zeroc.ice.net package: it is now a dotnet tool. Install it with:
dotnet tool install iceboxnet --create-manifest-if-neededSlice Compilation
ZeroC.Ice.Slice.Tools replaces Ice Builder for MSBuild and compiles your Slice files the same way: it uses the same SliceCompile items, with the same OutputDir, IncludeDirectories and AdditionalOptions metadata and the same EnableDefaultSliceCompileItems property. Your existing SliceCompile items work unchanged. See the ZeroC.Ice.Slice.Tools package for details.
slice2cs no longer accepts the --tie, --impl, --impl-tie and --checksum options. See Using the Slice Compiler for the options of slice2cs in Ice 3.8.
Java Gradle Projects
The com.zeroc.slice-tools Gradle plugin replaces the com.zeroc.gradle.ice-builder.slice plugin used in Ice 3.7 Java Gradle projects. It includes the slice2java compiler for Linux, macOS, and Windows and the Ice Slice files.
The plugin adds a slice block to each Java or Android source set. In this block, srcDir or srcDirs sets the directories that hold your Slice files, includeSearchPath replaces the include setting of the Ice Builder plugin, and compilerArgs replaces args.
Before (3.7) ice-builder:
plugins { id "com.zeroc.gradle.ice-builder.slice" version "1.5.0"}
slice { java { srcDir = '../slice' include = ["${projectDir}/../common/slice"] }}Now (3.8) slice-tools:
New configuration using Kotlin DSL:
Kotlin// build.gradle.ktsplugins {// Apply the Slice-tools plugin to enable Slice compilation.id("com.zeroc.slice-tools") version "3.8.+"}sourceSets {main {slice {// Build all Slice files from the "../slice" subdirectory.srcDirs("../slice")// Search the "../common/slice" directory for included Slice files.includeSearchPath.from("../common/slice")}}}New configuration using Groovy DSL:
Groovy// build.gradleplugins {// Apply the Slice-tools plugin to enable Slice compilation.id "com.zeroc.slice-tools" version "3.8.+"}sourceSets {main {slice {srcDirs "../slice"includeSearchPath.from("../common/slice")}}}
NPM Package
The Ice NPM package has been renamed and converted into a scoped package: @zeroc/ice. This new package also includes the slice2js compiler for Linux, macOS, and Windows.
Upgrade Steps
Uninstall the old packages:
Shellnpm uninstall ice slice2jsFor preview builds, add the ZeroC NPM feed to your project’s .npmrc file:
Properties# Use ZeroC nightly registry for @zeroc packages@zeroc:registry=https://download.zeroc.com/nexus/repository/npm-nightly/Install the new package:
Shellnpm install @zeroc/ice --save
Python Static Code Generation
The Python static code generation has been improved in Ice 3.8 to follow a more typical Python package layout and to better support type hints.
The following changes may require updates to your projects:
- The slice2py options --all and --prefix have been removed.
- The slice2py option --build replaces the --no-package and --build-package options.
- slice2py replaces the package index files (
__init__.py) each time it generates them. - The python:package and python:pkgdir metadata directives have been removed.
- The name and location of Python generated files has changed.
Upgrade Steps
Replacing --all
If you were using --all to automatically compile included Slice files, you must now list all required files explicitly.
Before (3.7):
slice2py --all Root.iceNow (3.8):
slice2py Foo.ice Bar.ice Root.iceHere Foo.ice and Bar.ice represent all files included by Root.ice.
Replacing --prefix
If you used --prefix to control the prefix of generated file names, remove it.
Instead:
- Use the default mapping for generated modules, and
- Apply the new python:identifier metadata when you need to remap a generated name (e.g., to avoid a collision with a Python builtin or standard library module).
Replacing python:package
If you used the python:package metadata directive to control the package of a generated module, remove it.
Instead, use python:identifier metadata, which works consistently with all Slice constructs (modules, classes, enums, etc.), not just modules.
-["python:package:zeroc"]+["python:identifier:zeroc.sys"] module sys { interface Process { // ... } }New File Layout
The Python mapping now generates a Python module for each Slice-defined type, placing it inside a package that corresponds to the Slice module.
module VisitorCenter{ interface Greeter { string greet(string name); }}Generated output (3.7):
./VisitorCenter/__init__.py./Greeter_ice.pyGenerated output (3.8):
./VisitorCenter/__init__.py./VisitorCenter/Greeter_forward.py./VisitorCenter/Greeter.pyKey points:
Generated files no longer use the
_icesuffix.All generated files are placed inside the corresponding package directory.
For Slice classes and interfaces, an additional
<name>_forward.pyfile is generated for forward declarations.Applications do not need to import these _forward modules directly.
Package Index Files
The package index file (__init__.py) that slice2py generates for a package exports the definitions of the Slice files passed to that slice2py command. The Ice 3.7 compiler added the Slice file it compiled to the existing index file, so a build could compile the Slice files of a module one at a time. The Ice 3.8 compiler replaces the index file each time it generates it.
For example, when Clock.ice and Alarm.ice both define types in the Slice module EarlyRiser, the second command below leaves generated/EarlyRiser/__init__.py with only the definitions of Alarm.ice:
slice2py --output-dir generated Clock.iceslice2py --output-dir generated Alarm.iceCompile all the Slice files that contribute to a package with one command:
slice2py --output-dir generated Clock.ice Alarm.iceIf your build compiles each Slice file with a separate command, generate only the modules with these commands, then generate the index files with a command that lists all the Slice files:
slice2py --output-dir generated --build=modules Clock.iceslice2py --output-dir generated --build=modules Alarm.iceslice2py --output-dir generated --build=index Clock.ice Alarm.iceReplacing --no-package and --build-package
The --build option replaces the --no-package and --build-package options. It accepts modules, index or all; all, the default, generates the modules and the package index files. See Using the Slice Compiler.
| Ice 3.7 option | Ice 3.8 option | Description |
|---|---|---|
--no-package | --build=modules | Generates the modules and leaves the package index files as is. |
--build-package | --build=index | Generates only the package index files. |
Tracking Generated Files
The Ice 3.7 compiler generated one file per Slice file, <name>_ice.py, plus the package index files. To get the files that the Ice 3.8 compiler generates from a set of Slice files, run slice2py with the --list-generated option and the value modules, index or all:
slice2py --output-dir generated --list-generated=all Clock.ice Alarm.iceWith this option, slice2py generates no file. It prints the path of each file, relative to the output directory, on a separate line.
Package Imports
In Ice 3.7, Python generated packages would automatically export nested sub-packages.
This is no longer the case in Ice 3.8: you must explicitly import nested packages.
Ice 3.7:
import Foo
# Nested subpackage is automatically availablec = Foo.Nested.Color.RedIce 3.8:
from Foo import Nested
c = Nested.Color.RedOr import only what you need:
from Foo.Nested import Color
c = Color.RedSwift Package
ZeroC distributes Ice for Swift as the Swift package https://github.com/zeroc-ice/ice.git. This package replaces the Carthage dependency and the ice-spm Swift package of Ice 3.7.
| Product | Description |
|---|---|
Ice | The main Ice library. |
Glacier2 | The Glacier2 library, used by Glacier2 client applications. |
IceBox | The IceBox library, used by IceBox client applications. |
IceGrid | The IceGrid library, used by IceGrid client applications. |
IceStorm | The IceStorm library, used by publishers and subscribers for IceStorm. |
CompileSlice | A build tool plugin that compiles Slice files with slice2swift. |
The package includes the slice2swift compiler, which the CompileSlice plugin runs during Swift Package Manager and Xcode builds.
Upgrade Steps
Remove Ice from the Carthage dependencies of your project, or remove the
ice-spmpackage fromPackage.swift.Add the
icepackage toPackage.swift, and add the products you need to the dependencies of each target. The package requires macOS 15 or later, or iOS 18 or later, and Swift 6.1 or later: set theswift-tools-versionofPackage.swiftto6.1.Diff-// swift-tools-version: 5.5+// swift-tools-version: 6.1import PackageDescriptionlet package = Package(name: "greeter",+ platforms: [.macOS(.v15)],dependencies: [- .package(url: "https://github.com/zeroc-ice/ice-spm.git", from: "3.7.11"),- .package(url: "https://github.com/mxcl/PromiseKit.git", from: "6.22.1"),+ .package(url: "https://github.com/zeroc-ice/ice.git", .upToNextMinor(from: "3.8.3"))],targets: [.executableTarget(name: "Server",- dependencies: [.product(name: "Ice", package: "ice-spm"), "PromiseKit"]+ dependencies: [.product(name: "Ice", package: "ice")],+ plugins: [.plugin(name: "CompileSlice", package: "ice")])])Add the
CompileSliceplugin to each target that compiles Slice files, as shown above. The plugin compiles the.icefiles among the source files of the target. To compile Slice files stored elsewhere, add aslice-plugin.jsonfile to the source files of the target. Paths in this file are relative to its directory.json{"sources": ["../../slice/Greeter.ice"]}Key Description sourcesThe Slice files that the plugin compiles. A directory stands for the.icefiles directly in it.search_pathsThe directories thatslice2swiftsearches for included Slice files (-Ioptions).The plugin adds the Slice files of Ice to the search path.
Slice
Local Slice
Support for local Slice has been removed. Previously defined local Slice types will need to be defined directly in your programming.
Operations on Classes
Support for operations on classes was removed. This feature was previously deprecated.
class Foo{- void bar();}A class can no longer implement an interface, and implements is no longer a Slice keyword. The Slice compilers also reject a proxy to a class (Foo*). Move the operations of such a class to an interface, and replace each proxy to the class with a proxy to that interface.
Optional Classes
Optional fields or parameters can no longer be a class or contain (including nesting) a class.
class Person{ string name; int number;}
interface ContactList{- void addContact(Person person, optional(1) Person alias) // error!}class Node{ string id;- optional(1) Node next; // error!}Several upgrade options are available depending on the application needs and constraints.
Replace optional fields or parameters by non-optional ones.
Diffclass Node{string id;- optional(1) Node next;+ Node next;}Diffinterface ContactList{- void addContact(Person person, optional(1) Person alias)+ void addContact(Person person, Person alias)}Replace simple classes by structs. This will not be possible for classes which use inheritance or where their usage requires reference semantics.
Diff- class Point+ struct Point{int x;int y;}
Interface by Value
Support for passing an interface by value was removed. This feature was previously deprecated.
interface Foo{- void passFooByValue(Foo foo); // error! void passFooProxy(Foo* foo);}Identifier Collisions
A Slice identifier can collide with a keyword or a reserved identifier of a programming language. The Ice 3.7 Slice compilers escaped such an identifier in the generated code. The Ice 3.8 Slice compilers no longer do: they use the Slice identifier as is, and you avoid the collision with the <lang>:identifier metadata, which gives a Slice definition another name in the code generated for one language.
For example, template is a keyword in C++:
interface Document{- string template();+ ["cpp:identifier:getTemplate"] string template();}The generated C++ function is then named getTemplate.
Connection Management
Active Connection Management
The connection management system used in Ice 3.7, Active Connection Management (ACM), has been removed. In its place is a new Idle Timeout mechanism which should usually require zero configuration.
The Ice.ACM.* properties have subsequently been removed.
-Ice.ACM.Heartbeat=0-Ice.ACM.Timeout=1-Ice.ACM.Close=2Ice 3.7 applications that wish to interoperate with Ice 3.8 are recommended to set the following properties.
+Ice.ACM.Heartbeat=3+Ice.ACM.Timeout=60 # or leave unset since 60 is the defaultIf you cannot change the configuration of the Ice 3.7 application, disable the idle check in the Ice 3.8 application by setting EnableIdleCheck to 0 for the connections to this Ice 3.7 application.
Connection Timeouts
The Idle Timeout also replaces the connection timeouts of Ice 3.7: the -t timeout option in proxy and object adapter endpoints, the ice_timeout proxy method, and the Ice.Default.Timeout and Ice.Override.Timeout properties. Ice 3.8 still accepts -t timeout in endpoints for backwards compatibility, but this option no longer has any effect. Remove the calls to ice_timeout and the two properties.
Ice 3.8 adds three connection timeouts, for inactivity, connection establishment and graceful closure. You configure them with the Ice.Connection properties; in most cases, the defaults are fine.
Heartbeat Callback
The setHeartbeatCallback operation has been removed from the Connection class.
Dispatch Flow Control
By default, Ice 3.8 stops reading from a connection once 100 dispatches of requests received on this connection are in progress, and resumes reading when a dispatch completes. If your application relies on dispatching more requests from one connection concurrently, increase MaxDispatches. Ice for JavaScript does not implement this limit.
Default Object Adapter
A default Object Adapter can now be associated with a Communicator. This greatly simplifies the creation of bidirectional connections. See Bidirectional Connections for more information.
Published Endpoints
The computation of an Object Adapter’s published endpoints has been updated.
With the exception of some filtering for loopback addresses, the previous algorithm would produce endpoints containing the IP addresses for all network interfaces; some of which may be internal and unreachable. The new algorithm is simpler and uses the Fully Qualified Domain Name (FQDN) of the system. See Object Adapter Endpoints for more information.
A new property _adapter_.PublishedHost has been added. It is used to compute the default published endpoints.
Additionally, the refreshPublishedEndpoints method has been removed from ObjectAdapter.
Secure Proxy Options, Properties, and Methods
Removed the secure proxy option, the PreferSecure proxy property, and all associated properties (Ice.Default.PreferSecure, Ice.Override.Secure) and proxy methods (ice_secure, ice_preferSecure, etc.).
Proxies should not contain a mix of secure and non-secure endpoints.
-ssl -h prod.host.name -p 4062:tcp -h prod.host.name -p 10000+ssl -h prod.host.name -p 4062Proxy Creation
Proxy creation has been simplified, allowing you to create a proxy from a communicator and endpoint string.
-std::shared_ptr<Ice::ObjectPrx> proxy =- communicator->stringToProxy("greeter: tcp -h localhost -p 4061");-std::shared_ptr<GreeterPrx> greeter = Ice::uncheckedCast<GreeterPrx>(proxy);+GreeterPrx greeter{communicator, "greeter:tcp -h localhost -p 4061"};-Ice.ObjectPrx proxy =- communicator.stringToProxy("greeter: tcp -h localhost -p 4061");-var greeter = GreeterPrxHelper.uncheckedCast(proxy);+var greeter =+ GreeterPrxHelper.createProxy(communicator, "greeter:tcp -h localhost -p 4061");-ObjectPrx proxy = communicator.stringToProxy("greeter: tcp -h localhost -p 4061");-var greeter = GreeterPrx.uncheckedCast(proxy);+var greeter =+ GreeterPrx.createProxy(communicator, "greeter:tcp -h localhost -p 4061");-const proxy = communicator.stringToProxy("greeter: tcp -h localhost -p 4061");-const greeter = GreeterPrx.uncheckedCast(proxy);+const greeter = new GreeterPrx(communicator, "greeter:tcp -h localhost -p 4061");-proxy = communicator.stringToProxy("greeter: tcp -h localhost -p 4061");-greeter = GreeterPrx.uncheckedCast(proxy);+greeter = GreeterPrx(communicator, 'greeter:tcp -h localhost -p 4061');-$proxy = $communicator->stringToProxy("greeter: tcp -h localhost -p 4061");-$greeter = GreeterPrxHelper::uncheckedCast($proxy);+$greeter =+ GreeterPrxHelper::createProxy($communicator, 'greeter:tcp -h localhost -p 4061');-proxy = communicator.stringToProxy("greeter: tcp -h localhost -p 4061");-greeter = GreeterPrx.uncheckedCast(proxy);+greeter = GreeterPrx(communicator, "greeter:tcp -h localhost -p 4061")-proxy = communicator.stringToProxy("greeter: tcp -h localhost -p 4061");-greeter = GreeterPrx.uncheckedCast(proxy);+greeter = GreeterPrx.new(communicator, "greeter:tcp -h localhost -p 4061")-let proxy = communicator.stringToProxy("greeter: tcp -h localhost -p 4061")!-let greeter = try uncheckedCast(prx: proxy, type: GreeterPrx.self)+let greeter = try makeProxy(+ communicator: communicator,+ proxyString: "greeter:tcp -h localhost -p 4061",+ type: GreeterPrx.self)C++ Mapping
Ice 3.7 provided two C++ mappings: the C++98 mapping and the C++11 mapping. Ice 3.8 provides a single C++ mapping, derived from the C++11 mapping of Ice 3.7. It requires a C++17 compiler.
This section has two parts: one for an application that uses the C++11 mapping of Ice 3.7, and one for an application that uses the C++98 mapping.
If your application uses the C++98 mapping, port it directly to the Ice 3.8 mapping: there is nothing to gain from porting it to the C++11 mapping first. A proxy, for example, is a GreeterPrx value in both the C++98 mapping and the Ice 3.8 mapping, while the C++11 mapping holds it in a std::shared_ptr<GreeterPrx>.
Upgrading from the C++11 Mapping
An application that uses the C++11 mapping of Ice 3.7 no longer defines ICE_CPP11_MAPPING, and links with libraries whose names have no ++11 suffix: Ice replaces Ice++11.
Proxies
In Ice 3.7, the C++11 mapping holds every proxy in a std::shared_ptr<GreeterPrx>. In Ice 3.8, a generated proxy class such as GreeterPrx is a concrete class with value semantics, and a proxy that can be null is a std::optional<GreeterPrx>. The Slice compiler maps a proxy parameter, return value or field to std::optional<GreeterPrx>.
Update the variables, data members, containers and servant operation signatures that hold a proxy, and replace nullptr with std::nullopt:
-std::shared_ptr<GreeterPrx> greeter = nullptr;+std::optional<GreeterPrx> greeter = std::nullopt;-void initiateCallback(std::shared_ptr<CallbackReceiverPrx> receiver, const Ice::Current& current) override;+void initiateCallback(std::optional<CallbackReceiverPrx> receiver, const Ice::Current& current) override;Both GreeterPrx and std::optional<GreeterPrx> provide operator->, so an invocation written as greeter->greet("alice") compiles unchanged.
The functions that create a proxy, such as Communicator::propertyToProxy, ObjectAdapter::add and Connection::createProxy, are now function templates: you choose the type of the proxy they return. The default is Ice::ObjectPrx; we recommend that you always specify the proxy type. For example:
// widget is a std::optional<WidgetPrx>auto widget = communicator->propertyToProxy<WidgetPrx>("MyWidget");Optional Values
std::optional replaces Ice::optional and IceUtil::Optional; std::nullopt replaces Ice::nullopt and IceUtil::None.
-Ice::optional<std::string> opString(Ice::optional<std::string> p1, Ice::optional<std::string>& p2,- const Ice::Current& current) override;+std::optional<std::string> opString(std::optional<std::string> p1, std::optional<std::string>& p2,+ const Ice::Current& current) override;Integer Types
The Slice compiler now maps the Slice integer types to the fixed-width integer types of the C++ standard library, and the Ice::Byte, Ice::Short, Ice::Int, Ice::Long, Ice::Float and Ice::Double aliases no longer exist.
| Slice type | Ice 3.7 (C++11 mapping) | Ice 3.8 |
|---|---|---|
byte | Ice::Byte (unsigned char) | std::uint8_t |
short | short | std::int16_t |
int | int | std::int32_t |
long | long long int | std::int64_t |
Update the servant operation signatures and the variables that use these types. A Slice sequence<byte> now maps to std::vector<std::byte>; in Ice 3.7, it mapped to std::vector<Ice::Byte>. std::int64_t and long long are distinct types on some platforms, such as 64-bit Linux where std::int64_t is long; there, a servant function declared with a long long parameter no longer overrides the generated function, and a std::vector<long long> is not a Slice sequence<long>.
-long long int opLong(long long int p1, long long int& p2, const Ice::Current& current) override;+std::int64_t opLong(std::int64_t p1, std::int64_t& p2, const Ice::Current& current) override;IceUtil
The IceUtil namespace and the IceUtil headers no longer exist:
Ice::CtrlCHandlerreplacesIceUtil::CtrlCHandler.- The string converter API, such as
StringConverterandsetProcessStringConverter, is now in theIcenamespace. - The other
IceUtilclasses, such asIceUtil::Mutex,IceUtil::ThreadandIceUtil::Time, have been removed: use the C++ standard library.
Plug-in Registration
Ice::registerPluginFactory and the Ice::registerXxx functions of Ice/RegisterPlugins.h have been removed. In Ice 3.8, you install a plug-in by adding its factory to the pluginFactories field of the InitializationData you pass to Ice::initialize:
-Ice::registerIceDiscovery();-auto communicator = Ice::initialize(argc, argv);+Ice::InitializationData initData;+initData.properties = Ice::createProperties(argc, argv);+initData.pluginFactories = {IceDiscovery::discoveryPluginFactory()};+auto communicator = Ice::initialize(initData);Ice::registerIceDiscovery,Ice::registerIceLocatorDiscovery,Ice::registerIceBTandIce::registerIceIAPbecomeIceDiscovery::discoveryPluginFactory(),IceLocatorDiscovery::locatorDiscoveryPluginFactory(),IceBT::btPluginFactory()andIce::iapPluginFactory()inpluginFactories.Ice::registerIceSSL,Ice::registerIceUDPandIce::registerIceWSgo away: the Ice library includes the SSL, UDP and WebSocket transports. When you link with the static Ice library, addIce::udpPluginFactory()andIce::wsPluginFactory()topluginFactoriesfor the UDP and WebSocket transports.
The string converter plug-in, installed with Ice::registerIceStringConverter or an Ice.Plugin property, has been removed. See String Converters for the string converters of Ice 3.8.
See Plug-in API for more information.
Upgrading from the C++98 Mapping
Proxies
A proxy remains a GreeterPrx value. In the C++98 mapping, a null proxy is written 0; in Ice 3.8, a proxy that can be null is a std::optional<GreeterPrx>, and std::nullopt replaces 0. The Slice compiler maps a proxy parameter, return value or field to std::optional<GreeterPrx>.
-GreeterPrx greeter = 0;+std::optional<GreeterPrx> greeter = std::nullopt;Ice::checkedCast and Ice::uncheckedCast replace the static checkedCast and uncheckedCast functions of the proxy classes, and Ice::checkedCast returns a std::optional:
-GreeterPrx greeter = GreeterPrx::checkedCast(base);+std::optional<GreeterPrx> greeter = Ice::checkedCast<GreeterPrx>(base);The functions that create a proxy, such as Communicator::propertyToProxy, ObjectAdapter::add and Connection::createProxy, are now function templates: you choose the type of the proxy they return. The default is Ice::ObjectPrx; we recommend that you always specify the proxy type. For example:
// widget is a std::optional<WidgetPrx>auto widget = communicator->propertyToProxy<WidgetPrx>("MyWidget");Servants and Class Instances
GreeterPtr, Ice::ObjectPtr and the other Ptr types are now aliases for std::shared_ptr, such as std::shared_ptr<Greeter>. Create servants and class instances with std::make_shared, and replace the dynamicCast function of these types with std::dynamic_pointer_cast:
-GreeterPtr servant = new GreeterI;+GreeterPtr servant = std::make_shared<GreeterI>();-MyClassPtr instance = MyClassPtr::dynamicCast(value);+MyClassPtr instance = std::dynamic_pointer_cast<MyClass>(value);A servant function receives its in-parameters by value, where the C++98 mapping passes them by const reference:
-virtual std::string greet(const std::string& name, const Ice::Current& current);+std::string greet(std::string name, const Ice::Current& current) override;Asynchronous Invocations
The begin_ and end_ functions and their callback objects no longer exist. Call the Async function of the operation instead: it returns a std::future, or accepts response, exception and sent callback functions.
-Ice::AsyncResultPtr result = greeter->begin_greet("alice");-std::string greeting = greeter->end_greet(result);+std::future<std::string> future = greeter->greetAsync("alice");+std::string greeting = future.get();Asynchronous Dispatch
For an operation with the amd metadata, the servant implements an Async function in place of the _async function, and the AMD_ callback object becomes two functions: response, which replaces ice_response, and exception, which replaces ice_exception.
-virtual void greet_async(const AMD_Greeter_greetPtr& cb, const std::string& name, const Ice::Current& current);+void greetAsync(std::string name, std::function<void(std::string_view)> response,+ std::function<void(std::exception_ptr)> exception, const Ice::Current& current) override;The Slice compiler also generates an asynchronous skeleton class, such as AsyncGreeter, in which every operation is dispatched this way, without the amd metadata.
Optional Values
std::optional replaces IceUtil::Optional, and std::nullopt replaces IceUtil::None.
Integer Types
The Slice compiler now maps the Slice integer types to the fixed-width integer types of the C++ standard library, and the Ice::Byte, Ice::Short, Ice::Int, Ice::Long, Ice::Float and Ice::Double aliases no longer exist.
| Slice type | Ice 3.7 (C++98 mapping) | Ice 3.8 |
|---|---|---|
byte | Ice::Byte (unsigned char) | std::uint8_t |
short | Ice::Short (short) | std::int16_t |
int | Ice::Int (int) | std::int32_t |
long | Ice::Long (IceUtil::Int64) | std::int64_t |
Update the servant operation signatures and the variables that use these types. A Slice sequence<byte> now maps to std::vector<std::byte>; in Ice 3.7, it mapped to std::vector<Ice::Byte>.
IceUtil
The IceUtil namespace and the IceUtil headers no longer exist:
Ice::CtrlCHandlerreplacesIceUtil::CtrlCHandler.- The string converter API, such as
StringConverterandsetProcessStringConverter, is now in theIcenamespace. std::shared_ptrreplacesIceUtil::Handle: a class held in astd::shared_ptrdoesn't derive fromIceUtil::Shared.- The other
IceUtilclasses, such asIceUtil::Mutex,IceUtil::ThreadandIceUtil::Time, have been removed: use the C++ standard library.
Plug-in Registration
Ice::registerPluginFactory and the Ice::registerXxx functions of Ice/RegisterPlugins.h have been removed. In Ice 3.8, you install a plug-in by adding its factory to the pluginFactories field of the InitializationData you pass to Ice::initialize:
-Ice::registerIceDiscovery();-Ice::CommunicatorPtr communicator = Ice::initialize(argc, argv);+Ice::InitializationData initData;+initData.properties = Ice::createProperties(argc, argv);+initData.pluginFactories = {IceDiscovery::discoveryPluginFactory()};+Ice::CommunicatorPtr communicator = Ice::initialize(initData);Ice::registerIceDiscovery,Ice::registerIceLocatorDiscovery,Ice::registerIceBTandIce::registerIceIAPbecomeIceDiscovery::discoveryPluginFactory(),IceLocatorDiscovery::locatorDiscoveryPluginFactory(),IceBT::btPluginFactory()andIce::iapPluginFactory()inpluginFactories.Ice::registerIceSSL,Ice::registerIceUDPandIce::registerIceWSgo away: the Ice library includes the SSL, UDP and WebSocket transports. When you link with the static Ice library, addIce::udpPluginFactory()andIce::wsPluginFactory()topluginFactoriesfor the UDP and WebSocket transports.
The string converter plug-in, installed with Ice::registerIceStringConverter or an Ice.Plugin property, has been removed. See String Converters for the string converters of Ice 3.8.
See Plug-in API for more information.
Optional Values
The Ice C# API and the code generated by slice2cs are now #nullable enable, and Ice uses the standard ? notation for all nullable types: a proxy that can be null is a GreeterPrx?, a class instance that can be null is a Person?, and so on. We recommend enabling nullable reference types in your own project (<Nullable>enable</Nullable>), so that the compiler checks your use of these types.
The Ice.Optional<T> struct and Ice.Util.None have been removed. An optional field or parameter now maps to a nullable type, where null means "not set". See Fields.
-public override void setAge(Ice.Optional<int> age, Ice.Current current)+public override void setAge(int? age, Ice.Current current){- if (age.HasValue)+ if (age is int value) {- _age = age.Value;+ _age = value; }}-person.nickname = Ice.Util.None;+person.nickname = null;Structures
A Slice struct now maps to a C# record struct or to a sealed record class, depending on the types of its fields. See Structures. Update the partial declarations that extend a generated struct to the new form:
// Slice: struct Point { int x; int y; }-public partial struct Point+public partial record struct Point// Slice: struct Person { string name; int age; }-public partial class Person+public sealed partial record class PersonAsynchronous Invocations
Proxies no longer provide the begin_ and end_ methods, and Ice.AsyncResult has been removed. Call the Async method of the operation, which returns a Task:
-Ice.AsyncResult result = greeter.begin_greet("alice");-string greeting = greeter.end_greet(result);+string greeting = await greeter.greetAsync("alice");Tie Classes
slice2cs no longer generates tie classes (GreeterTie_) and operations interfaces (GreeterOperations_), and Ice.TieBase has been removed. Derive your servant class from the generated skeleton class, and forward each operation to your implementation object:
-adapter.add(new GreeterTie_(new GreeterImpl()), Ice.Util.stringToIdentity("greeter"));+adapter.add(new GreeterServant(new GreeterImpl()), Ice.Util.stringToIdentity("greeter"));public class GreeterServant : GreeterDisp_{ private readonly GreeterImpl _impl;
public GreeterServant(GreeterImpl impl) => _impl = impl;
public override string greet(string name, Ice.Current current) => _impl.greet(name, current);}Plug-in Factories
Ice.Util.registerPluginFactory has been removed. In Ice 3.8, you install a plug-in by adding its factory to the pluginFactories property of the InitializationData you pass to Ice.Util.initialize:
-Ice.Util.registerPluginFactory("IceDiscovery", new IceDiscovery.PluginFactory(), true);-Ice.Communicator communicator = Ice.Util.initialize(ref args);+var initData = new Ice.InitializationData+{+ properties = new Ice.Properties(ref args),+ pluginFactories = [new IceDiscovery.PluginFactory()]+};+Ice.Communicator communicator = Ice.Util.initialize(initData);IceDiscovery.PluginFactoryandIceLocatorDiscovery.PluginFactorygo inpluginFactories, as shown above.IceSSL.PluginFactorygoes away: the SSL transport is part of theZeroC.Iceassembly.
The PluginFactory interface has a new pluginName property, which gives the name of the plug-in this factory creates. Add this property to your own plug-in factories. See Plug-in API.
public class MyPluginFactory : Ice.PluginFactory{+ public string pluginName => "MyPlugin";+ public Ice.Plugin create(Ice.Communicator communicator, string name, string[] args) => new MyPlugin(communicator);}Continuations in Asynchronous Code
The threads of an Ice thread pool no longer set a SynchronizationContext. In Ice 3.7, this synchronization context ran the continuation of an await made in an Ice thread pool thread in the same Ice thread pool, unless the code called ConfigureAwait(false). In Ice 3.8, when a servant awaits a proxy invocation that is not yet complete, the continuation runs in a .NET thread pool thread.
Review the asynchronous code of your servants. Code that relied on an Ice thread pool to limit the number of threads that execute these continuations, such as a thread pool with a single thread, now needs its own synchronization.
Slice Metadata
slice2cssilently ignores metadata with theclr:prefix, as it does metadata for other languages. Replace this prefix withcs::Diff-["clr:generic:List"] sequence<string> StringList;+["cs:generic:List"] sequence<string> StringList;cs:attributeapplies only to enums, enumerators, constants and fields;slice2csignores it elsewhere, with a warning. Put the attribute of a class, struct, exception or interface on a partial declaration of the generated type in your own source file:Diff-["cs:attribute:System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)"]struct Point { int x; int y; }C#[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]public partial record struct Point;The
cs:serializable,cs:tieandcs:implementsdirectives have been removed;slice2csignores them with a warning. Remove them from your Slice definitions. If you relied oncs:serializable, serialize the object in your own code. If you relied oncs:implements, declare the interface on a partial declaration of the generated type in your own source file.
See Slice Metadata Directives for the metadata directives of Ice 3.8.
Java Mapping
Java 17
Ice for Java 3.8 requires Java 17.
Communicator Creation
Communicator is now a class with public constructors, and Util.initialize has fewer overloads. The InitializationData overload covers every case: if your application passed both command-line arguments and an InitializationData to Util.initialize, parse the arguments into the properties field first:
-Communicator communicator = Util.initialize(args, initData);+initData.properties = new Properties(args, initData.properties);+Communicator communicator = new Communicator(initData);Thread Interrupts
Ice for Java now always supports thread interrupts: interrupting a thread blocked in an Ice call throws OperationInterruptedException. The Ice.ThreadInterruptSafe property, which enabled this behavior in Ice 3.7, has been removed.
Exceptions
Ice 3.8 removes the com.zeroc.Ice.Exception class, the base class of com.zeroc.Ice.LocalException in Ice 3.7. LocalException now derives directly from java.lang.RuntimeException, and com.zeroc.Ice.UserException derives from java.lang.Exception as in Ice 3.7. Catch LocalException where your code caught com.zeroc.Ice.Exception:
try { greeter.greet("alice");-} catch (com.zeroc.Ice.Exception ex) {+} catch (com.zeroc.Ice.LocalException ex) { ex.printStackTrace(); }Using null for a Struct or Enum
Ice 3.7 accepted null for a struct or enum parameter, return value, or field, and marshaled a default-constructed struct or the first enumerator in its place. Ice 3.8 requires a non-null value.
Slice Loaders
Ice 3.8 removes the ValueFactory and ValueFactoryManager interfaces. Set the sliceLoader field of InitializationData to create your own instances of Slice classes during unmarshaling. See Slice Loaders.
The java:package metadata is deprecated: slice2java warns when it sees it. Replace it with java:identifier on the module. java:identifier gives the full name of the Java package, where java:package gave a prefix. To keep the generated code unchanged, use the package that java:package produced:
-["java:package:com.example"]+["java:identifier:com.example.VisitorCenter"]module VisitorCenterYour Ice.Package.<module> or Ice.Default.Package property then keeps locating the generated classes, as in Ice 3.7. If you move the module to another package, such as com.example.visitorcenter, these properties no longer apply: install a ModuleToPackageSliceLoader for this module instead:
var initData = new InitializationData();initData.sliceLoader = new ModuleToPackageSliceLoader("::VisitorCenter", "com.example.visitorcenter");
try (Communicator communicator = new Communicator(initData)) { // ...}A Slice class with a compact ID also needs a Slice loader: pass its generated class to a ClassSliceLoader. Combine several loaders with a CompositeSliceLoader:
var initData = new InitializationData();initData.sliceLoader = new CompositeSliceLoader( new ClassSliceLoader(AtmosphericConditions.class), new ModuleToPackageSliceLoader("::VisitorCenter", "com.example.visitorcenter"));Dictionaries
A Slice dictionary now maps to a MATLAB dictionary. In Ice 3.7, it mapped to a containers.Map, or to a struct array with key and value fields when the key type was a Slice struct.
Create the dictionary with configureDictionary, giving the mapped key type and the mapped value type. For example, with dictionary<long, Employee> EmployeeMap, where Employee is a Slice struct:
-em = containers.Map('KeyType', 'int64', 'ValueType', 'any');+em = configureDictionary('int64', 'Employee'); em(31) = employee;A dictionary keyed by a Slice struct takes the mapped struct as its key. With dictionary<Point, string> PointNames:
-names = struct('key', {}, 'value', {});-names(1).key = Point(1, 2);-names(1).value = 'start';+names = configureDictionary('Point', 'string');+names(Point(1, 2)) = 'start';When the Slice value type is a sequence, a dictionary, a class or a proxy, the value type of the MATLAB dictionary is cell, and each value is a cell that holds the mapped value. Use curly braces to store and retrieve the value itself. With dictionary<string, Greeter*> GreeterMap:
-greeters = containers.Map('KeyType', 'char', 'ValueType', 'any');-greeters('fr') = greeter;-greeter = greeters('fr');+greeters = configureDictionary('string', 'cell');+greeters{'fr'} = greeter;+greeter = greeters{'fr'};A request context is a dictionary with string keys and string values:
-context = containers.Map('KeyType', 'char', 'ValueType', 'char');+context = configureDictionary('string', 'string'); context('language') = 'fr'; greeting = greeter.greet('alice', context);See Dictionaries for the value type that corresponds to each Slice type.
String Sequences
A generated proxy method now returns a sequence<string> as a string array and accepts a string array for a sequence<string> parameter. In Ice 3.7, a sequence<string> mapped to a cell array of character vectors. Review the code that indexes a returned sequence with curly braces.
names = directory.list();-first = names{1};+first = names(1);Typed Arguments and Properties
A generated proxy method now validates the type of each argument, except for optional parameters. A generated class, exception or struct declares a typed property for each field, except for optional fields and fields that hold class instances.
Pass an empty array of the mapped type for a null proxy or a null class instance. In a typed property, represent a null proxy with an empty array of the proxy type, and an empty sequence with an empty array of the mapped sequence type:
-registry.setGreeter([]);-entry.greeter = [];-entry.weights = [];+registry.setGreeter(GreeterPrx.empty);+entry.greeter = GreeterPrx.empty;+entry.weights = int32.empty;Struct Properties
In a generated class, exception or struct, a non-optional field of Slice struct type is now empty by default. In Ice 3.7, it held a new instance of the mapped struct, so you could set the fields of this instance directly. Assign an instance first:
line = Line();+line.start = Point(); line.start.x = 10;Slice Loaders
Ice 3.8 locates the generated class for a Slice class or exception through a Slice loader. The default Slice loader maps a Slice type ID such as ::M::Node to the MATLAB class M.Node. It cannot locate a class with a compact ID, or a class or exception whose name or enclosing module you rename with the matlab:identifier metadata: for these, create an Ice.ClassSliceLoader from the meta classes of the generated classes and give it to the communicator:
communicator = Ice.Communicator(args, SliceLoader = Ice.ClassSliceLoader(?Compact, ?CompactExt));PHP Requirements
Ice for PHP 3.8 requires PHP 8.0 or later and runs on Linux and macOS. See Supported Platforms for Ice 3.8.3 for the tested PHP versions and operating systems.
Flattened Mapping
The flattened mapping, deprecated in Ice 3.7 and selected with slice2php --no-namespace, has been removed. Ice 3.8 provides only the namespace mapping.
To upgrade an application that uses the flattened mapping:
- Remove the
--no-namespaceand-noptions from yourslice2phpcommands, then recompile your Slice files. - Replace each flattened name with its namespaced name. The flattened mapping joined the Slice module names and the type name with underscores, such as
VisitorCenter_GreeterPrxHelper; the namespace mapping maps each Slice module to a PHP namespace, such asVisitorCenter\GreeterPrxHelper. The same rule applies to the functions and classes of the Ice runtime:Ice_initializebecomesIce\initialize, andIce_InitializationDatabecomesIce\InitializationData. - Replace the
Ice_Unsetconstant, which marks an optional value as not set, withIce\None.
-$communicator = Ice_initialize($argv);-$greeter = VisitorCenter_GreeterPrxHelper::uncheckedCast($proxy);+$communicator = Ice\initialize($argv);+$greeter = VisitorCenter\GreeterPrxHelper::uncheckedCast($proxy);Using null for a Struct
When you passed null where an operation expects a Slice struct, Ice 3.7 marshaled an instance of the struct created with its default constructor. Ice 3.8 throws InvalidArgumentException from the proxy invocation. The same rule applies to a struct nested in another struct, a class, a sequence or a dictionary.
Pass an instance of the struct:
-$greeter->setLocation(null);+$greeter->setLocation(new VisitorCenter\Location);PHP Value Factories
Ice for PHP 3.8 has no value factories and no Slice loaders: when it unmarshals a Slice class, it always creates an instance of the class generated by slice2php. Remove your value factories and the calls that register them with getValueFactoryManager.
ice.hide_profiles
The ice.hide_profiles directive has been removed: remove it from your PHP configuration. To keep the PHP settings of an application private, run each application in its own PHP-FPM pool. See Profiles in PHP.
Loading Slice Files
Ice.loadSlice now takes a single argument: a list that holds one string per compiler argument. Ice 3.7 accepted a command string, optionally followed by such a list.
-Ice.loadSlice("-I. Greeter.ice")-Ice.loadSlice("-I.", ["Greeter.ice"])+Ice.loadSlice(["-I.", "Greeter.ice"])Like slice2py, Ice.loadSlice no longer accepts the --all option. Pass every Slice file of your application, including the files that your other Slice files include:
-Ice.loadSlice("--all Root.ice")+Ice.loadSlice(["Foo.ice", "Bar.ice", "Root.ice"])See Code Generation.
Arguments of Ice.initialize
Ice.initialize takes either an argument list, such as Ice.initialize(sys.argv), or an Ice.InitializationData object as the initData keyword argument.
To combine command-line arguments with an InitializationData object, create the properties of this object from the arguments:
initData = Ice.InitializationData() initData.logger = MyLogger()-communicator = Ice.initialize(sys.argv, initData)+initData.properties = Ice.createProperties(sys.argv, initData.properties)+communicator = Ice.initialize(initData=initData)To combine command-line arguments with a configuration file, add --Ice.Config to the arguments:
-communicator = Ice.initialize(sys.argv, "config.client")+sys.argv.append("--Ice.Config=config.client")+communicator = Ice.initialize(sys.argv)Optional Values
Ice 3.8 removes Ice.Unset and uses None in its place: Ice returns None for an optional parameter, return value or field without a value, an optional field with no default value in Slice is initially None, and a None you pass for an optional parameter or field means "not set".
-if greeting is not Ice.Unset:+if greeting is not None: print(greeting)Enumerations
A generated enumeration now derives from the enum.Enum class of Python, and Ice 3.8 removes Ice.EnumBase. An enumerator keeps its name and value attributes. Update the code that uses the following:
Color.valueOf(n)becomesColor(n).- The
<,<=,>and>=operators no longer work on enumerators: compare thevalueattributes. str(Color.Red)now returnsColor.Red; useColor.Red.nameto getRed.
-color = Color.valueOf(n)-if color < Color.Blue:+color = Color(n)+if color.value < Color.Blue.value: ...Using None for a Struct
Marshaling None for a struct parameter, return value, or field that is not optional now fails with a ValueError. Ice 3.7 marshaled a default-constructed struct in this case. Pass an instance of the struct:
-clock.setTime(None)+clock.setTime(TimeOfDay())Asynchronous Invocations
The synchronous proxy methods work as in Ice 3.7. For asynchronous invocations, we recommend the Async methods with asyncio: create the communicator with the running event loop, then await the invocation. The code is as simple as with the synchronous methods, and the event loop can run other tasks while the invocation is in progress:
async def main(): async with Ice.Communicator(sys.argv, eventLoop=asyncio.get_running_loop()) as communicator: greeter = GreeterPrx(communicator, "greeter:tcp -h localhost -p 4061") greeting = await greeter.greetAsync("alice") print(greeting)
asyncio.run(main())Ice 3.8 removes the begin_ and end_ methods and Ice.AsyncResult. Without an event loop, an Async method returns an Ice.InvocationFuture, as in Ice 3.7:
-result = greeter.begin_greet("alice")-greeting = greeter.end_greet(result)+future = greeter.greetAsync("alice")+greeting = future.result()Replace the _response and _ex callbacks of a begin_ method with a callback registered with add_done_callback on the future, and the _sent callback with a callback registered with add_sent_callback, which now receives a single argument:
-def sent(future, sentSynchronously):+def sent(sentSynchronously): ...
future.add_sent_callback(sent)Sequence Metadata
The python:seq:list, python:seq:tuple, python:seq:default and python:default metadata directives have been removed; slice2py ignores them with a warning. Replace python:seq:list and python:seq:tuple with python:list and python:tuple, and remove python:seq:default and python:default. See the sequence mapping.
-["python:seq:tuple"] sequence<string> StringSeq;+["python:tuple"] sequence<string> StringSeq;Ice 3.8 removes Ice.createArray and Ice.createNumPyArray, the factory functions that Ice 3.7 provided for the python:memoryview metadata. To map a sequence to an array.array or to a NumPy array, use the python:array.array or python:numpy.ndarray metadata instead:
-["python:memoryview:MyModule.createIntArray"] sequence<int> IntSeq;+["python:numpy.ndarray"] sequence<int> IntSeq;A factory function for python:memoryview now takes two parameters, the memory view and the element type; Ice 3.7 passed a third parameter, copy.
Marshaled Results
The marshaled-result metadata no longer affects the generated Python code: slice2py no longer generates the MarshaledResult helper methods, and the servant method returns the result itself:
def getNode(self, current):- return Demo.Tree.GetNodeMarshaledResult(self._node, current)+ return self._nodeKeep the marshaled-result metadata in a Slice file that you also compile for another language mapping, where it still applies.
Loading Slice Files
Ice::loadSlice now takes a single argument: an array that holds one string per compiler argument. Ice 3.7 accepted a command string, optionally followed by such an array.
-Ice::loadSlice("-I. Foo.ice")-Ice::loadSlice("-I.", ["Foo.ice"])+Ice::loadSlice(["-I.", "Foo.ice"])Arguments of Ice::initialize
Ice::initialize now takes at most one argument, either an argument array or an Ice::InitializationData object.
To combine command-line arguments with an Ice::InitializationData object, create its properties from the arguments, with the properties it already holds as the defaults:
-Ice::initialize(ARGV, initData) do |communicator|+initData.properties = Ice::createProperties(ARGV, initData.properties)+Ice::initialize(initData) do |communicator| ... endTo combine command-line arguments with a configuration file, add --Ice.Config to the arguments:
-Ice::initialize(ARGV, "config.client") do |communicator|+Ice::initialize(ARGV + ["--Ice.Config=config.client"]) do |communicator| ... endThe block given to Ice::initialize now takes a single parameter, the communicator. Ice 3.7 also accepted a block with a second parameter that received the remaining command-line arguments. Ice::initialize and Ice::createProperties remove the options they recognize from the array you pass, so read the remaining arguments from that array:
-Ice::initialize(ARGV) do |communicator, args|- run(communicator, args)+Ice::initialize(ARGV) do |communicator|+ run(communicator, ARGV) endOptional Values
Ice::Unset is now an alias for nil: Ice returns nil for an optional parameter, return value or field without a value, an optional field with no default value in Slice is initially nil, and a nil you pass for an optional parameter or field means "not set". Code that compares with Ice::Unset keeps working.
Using nil for a Struct
A non-optional struct parameter or field no longer accepts nil. Ice 3.7 marshaled a default-constructed struct in its place. Pass an instance of the struct:
-greeter.setLocation(nil)+greeter.setLocation(VisitorCenter::Location.new)async/await and Structured Concurrency
Ice for Swift now requires Swift 6.1, uses async/await and structured concurrency, and no longer depends on PromiseKit. Every proxy invocation is async:
-let greeting = try greeter.greet(name)+let greeting = try await greeter.greet(name)print(greeting)
-firstly {- greeter.greetAsync(name)-}.get { greeting in- print("\(greeting)")-}+let greeting = try await greeter.greet(name)print(greeting)Every operation of a skeleton protocol is now async throws, and the amd metadata directive no longer affects the generated code. A servant method that completes synchronously and throws no exception keeps its Ice 3.7 signature, since a method can omit async and throws:
func greet(name: String, current _: Ice.Current) -> String { ...}A servant method that implemented an amd operation with PromiseKit becomes an async method:
-func greetAsync(name: String, current _: Ice.Current) -> Promise<String> {+func greet(name: String, current _: Ice.Current) async throws -> String { ...}Sendable Servants
Skeleton protocols inherit Sendable from Ice.Dispatcher, and the object adapter dispatches each request in its own task, so several tasks can call the same servant concurrently. Implement a servant with mutable state as an actor, or as a final class that synchronizes access to its state and is declared @unchecked Sendable.
-class MFile: File {+actor MFile: File { private var lines: [String] = []
func write(text: [String], current _: Ice.Current) { lines = text }}Removed Dispatch Structs
The generated dispatch structs, such as GreeterDisp, have been removed: you now add an object that implements the skeleton protocol directly to the object adapter.
-try adapter.add(servant: GreeterDisp(Chatbot()), id: Ice.Identity(name: "greeter"))+try adapter.add(servant: Chatbot(), id: Ice.Identity(name: "greeter"))Property Validation
Ice now validates properties with that start with an Ice property prefix (Ice., IceSSL., etc.). Setting an unknown Ice property or a property configured for the wrong Ice service will now fail.
Please refer to the property reference for a complete list of Ice properties.
The following IceSSL properties of Ice 3.7 no longer exist in Ice 3.8, so setting one of them now fails: IceSSL.CertAuthDir, IceSSL.CertAuthFile, IceSSL.CertVerifier, IceSSL.Ciphers, IceSSL.DH.<bits>, IceSSL.DHParams, IceSSL.EntropyDaemon, IceSSL.FindCert.<location>.<name>, IceSSL.InitOpenSSL, IceSSL.PasswordCallback, IceSSL.PasswordRetryMax, IceSSL.Protocols, IceSSL.ProtocolVersionMax, IceSSL.ProtocolVersionMin, IceSSL.Random, IceSSL.SchannelStrongCrypto, IceSSL.SecurityLevel and IceSSL.VerifyDepthMax.
Communicator Initialization
- The
Applicationhelper class has been removed from the language mappings that provided it. Create and destroy the communicator in your own code, as described in Communicator Initialization and Destruction, and shut it down when your application receives Ctrl+C or a termination signal. - The
dispatcherfield ofInitializationDatais now namedexecutor.
Value Factories
ValueFactory and ValueFactoryManager have been removed. In Ice 3.7, an application registered a value factory mainly to supply the implementation of a class with operations. Classes no longer have operations, so in most cases you remove your value factories and replace them with nothing. If you still need to create instances of your own classes during unmarshaling, implement a Slice loader and set the sliceLoader field of InitializationData.
In Java, the Ice.Default.Package and Ice.Package.module properties still work, but they are deprecated: we recommend registering a Slice loader in InitializationData instead. In Java and MATLAB, a class with a compact ID requires a Slice loader.
SSL Transport
The SSL transport is now part of the Ice library and is no longer a plug-in.
- Remove the
Ice.Plugin.IceSSLproperty from your configuration: Ice 3.8 provides no IceSSL plug-in to load. - The
IceSSLcertificate API, the certificate verifiers and the password callbacks have been removed. You can still configure the SSL transport with the IceSSL properties in all language mappings except JavaScript, which supports only the secure WebSocket transport (WSS). In C++, C# and Java, we recommend the new programmatic configuration, which uses the API of the SSL engine of your platform and gives you more control than the properties.
Plug-ins
The recommended way to install a plug-in has changed in C++, C# and Java: register a plug-in factory in the pluginFactories field of InitializationData, and Ice creates the plug-in when it initializes the communicator. For example, in C++:
Ice::InitializationData initData;initData.pluginFactories = {IceDiscovery::discoveryPluginFactory()};Your application then uses the plug-in's library like any other library it depends on, and you no longer need an Ice.Plugin.name property to load the plug-in.
In the language mappings based on Ice for C++ (MATLAB, PHP, Python, Ruby and Swift), you install a plug-in with an Ice.Plugin.name property, as in Ice 3.7. These mappings now include the IceDiscovery and IceLocatorDiscovery plug-ins. You enable them with the properties Ice.Plugin.IceDiscovery and Ice.Plugin.IceLocatorDiscovery, and you can no longer choose another name for these plug-ins. For example:
Ice.Plugin.IceDiscovery=1See IceDiscovery and IceLocatorDiscovery.
Services
DataStorm
The DataStorm publisher/subscriber framework has been integrated into the Ice distribution, and is no longer a separate product.
Glacier2
The Slice definitions of Glacier2 are unchanged in Ice 3.8. As a result, you can use a 3.8 router with a 3.7 client, and vice-versa.
The buffered mode of the router has been removed. Glacier2 now has a single mode, the unbuffered mode of Ice 3.7, in which the router forwards each request without queuing it. Two features that depended on the buffered mode have been removed with it: request overrides (the _ovrd request context), and the batching of requests by the router (Glacier2.Client.AlwaysBatch and Glacier2.Server.AlwaysBatch).
A session now lasts as long as the connection that created it: the router destroys the session when this connection closes, and relies on the idle check to detect a dead client. The session timeout, Glacier2.SessionTimeout, has been removed.
The Glacier2 helper classes (Glacier2.Application, SessionFactoryHelper and SessionHelper) have been removed. Create and destroy the session with the Glacier2::Router proxy, as described in Getting Started with Glacier2.
IceGrid
The Slice definitions of IceGrid in Ice 3.8 are not compatible with the Ice 3.7 definitions. As a result, you cannot mix a 3.8 registry with a 3.7 node, or vice-versa. You also need to use the 3.8 version of the admin tools (icegridadmin and IceGridGUI) to manage a 3.8 deployment.
You can nevertheless:
- start/manage Ice 3.7 servers from IceGrid 3.8
- start/manage Ice 3.8 servers from IceGrid 3.7
The IceGrid registry database schema is the same in Ice 3.8 and Ice 3.7. This allows you to start a 3.8 registry with a LMDB database created by a 3.7 registry.
The distribution of server files through IcePatch2 has been removed, and with it the distrib descriptor; the dbenv descriptor has been removed too. An IceGrid 3.8 registry ignores these descriptors in the applications it loads from a 3.7 database, but it no longer accepts the distrib and dbenv elements in XML: remove them from your descriptor files, remove the application patch and server patch commands from your icegridadmin scripts, and distribute the files of your servers with another tool.
A client or administrative session now lasts as long as the connection that created it. The session timeout, IceGrid.Registry.SessionTimeout, has been removed.
The icegridadmin command server state has been renamed server status: update the scripts that call it.
IcePatch2
The IcePatch2 service has been removed.
IceStorm
The IceStorm configuration now uses the IceStorm prefix instead of the IceBox service name as prefix.
-DemoIceStorm.LMDB.Path=db-DemoIceStorm.TopicManager.Endpoints=tcp -p 9999-DemoIceStorm.Publish.Endpoints=tcp -p 10000+IceStorm.LMDB.Path=db+IceStorm.TopicManager.Endpoints=tcp -p 9999+IceStorm.Publish.Endpoints=tcp -p 10000Update the version in the IceStorm entry point of your IceBox configuration:
-IceBox.Service.IceStorm=IceStormService,37:createIceStorm+IceBox.Service.IceStorm=IceStormService,38:createIceStormThe Slice definitions of IceStorm are unchanged in Ice 3.8. This allows you to use a mix of 3.7 and 3.8 for your IceStorm service, publishers and subscribers. You can even use a mix of 3.7 and 3.8 IceStorm replicas in a replicated deployment.
Moreover, the IceStorm database schema is the same in Ice 3.8 and Ice 3.7. This allows you to start an IceStorm 3.8 service with a LMDB database created by IceStorm 3.7.
Miscellaneous
- The Objective-C mapping has been removed. You should upgrade to the Swift mapping.
- The Java Compat mapping has been removed. You should upgrade to the Java mapping.