Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Leave Comments, Critiques, and Suggestions Here

How to Migrate from Phobos to Tango

WORK IN PROGRESS

This page will try address the different modules of Phobos, and how one might approach a conversion to Tango. Many of the modules are just renamed, and in those cases just that is mentioned. For more complex usecases, we try to provide examples.

To make the transition easier, you may find Tangobos useful. This is a port of the Phobos source code that runs on top of Tango. With this you can port a little at a time.

Note that Tango fixes some bugs and limitations in Phobos.

object

Object

The toString method in Tango was originally renamed toUtf8 to better reflect what the method actually does. Recently Tango reverted back to toString in order to make it easier for code to be compatible with both Phobos and Tango.

Error

This class has been removed from Tango, as it was a subclass of Exception, and thus could be silently ignored with a

catch (Exception e) { } 

which don't make sense when Errors are supposed to be unrecoverable.

std.base64

std.bitarray

The BitArray struct in std.bitarray compares to the one in tango.core.BitArray, which should provide all the functionality present in Phobos.

Use

import tango.core.BitArray;

std.boxer

See tango.core.Variant.

std.compiler

std.conv

A generic to!(Type)(fromVal) template like that in D2's std.conv can be found in tango.util.Convert.

The Format object in tango.text.convert.Format can also do many conversion tasks. It is an instance of a tango.text.convert.Layout.

For more information about Tango's formatting functions, see API docs, the manual or the formatting tutorial.

std.cover

The contents of this module, and the code coverage feature itself, are compiler-specific and are currently not available in an import library. Until a package can be devoted to compiler extensions, the following functions may be declared and used to access code coverage features:

extern (C) void dmd_coverSourcePath( char[] pathname );
extern (C) void dmd_coverDestPath( char[] pathname );
extern (C) void dmd_coverSetMerge( bool flag );

std.ctype

std.date

std.demangle

From Tango 0.99.9 you will find demangling by using

import tango.core.stacktrace.Demangler;

std.file

The functionality in this module is covered mostly by the FileProxy class and it's subclass, File in the tango.io.FileProxy and tango.io.File modules. These classes corresponds to the DirEntry struct in std.file, but provides more functionality. They can be used by importing

import tango.io.File;
// or if no reading or writing is required
import tango.io.FileProxy;

Most of the operations require the instantiation of either of the classes mentioned above, for instance

auto file = new File("/home/foo/myfile.txt");

The first 3 functions require a File instance, whereas the rest is found in FileProxy, except if otherwise noted.

read

By using the File instance from above, read the file using

auto res = file.read();

write

Writing to the file can be done in a similar fashion:

file.write(mycontent);

append

To append, follow the same pattern.

file.append(mycontent);

rename

If the object has been creating with an existing file or directory, it can be renamed.

scope target = new FilePath("/home/foo/newfilename.txt");
file.rename(target);

remove

Removal of the file follows the same pattern.

file.remove();

getSize

This function is also comparable.

file.getSize();

getTimes

This function is divided into three to give each of it's out parameters:

auto created = file.getCreatedTime();
auto modified = file.getModifiedTime();
auto accessed = file.getAccessedTime();

exists

To check if the path File or FileProxy instance points to, exists as a file or directory, do

if (file.isExisting) {
    ...
}

getAttributes

Don't currently exist in Tango.

isfile, isdir

Since these are mutually exclusive options, FileProxy.isDirectory will return true if it is a directory, false if it is a file.

if (file.isDirectory) {
     // f is a directory
}
else {
     // f is a file
}

chdir

This functionality is provided in the tango.io.FileSystem, to use it do

import tango.io.FilePath;
import tango.io.FileSystem;

scope dir = new FilePath("/home/foo/changetodir");
FileSystem.setDirectory(dir);

mkdir

To create a directory pointed to by a FileProxy instance, do

file.createDirectory();

rmdir

To remove a file or folder pointed to by a FileProxy instance, do

file.remove(); 

getcwd

This functionality is provided in the tango.io.FileSystem, to use it do

import tango.io.FileSystem;

auto dir = FileSystem.getDirectory();

listdir

The basic listdir corresponds to FileProxy.toList, which can be used as follows

auto list = f.toList();

std.format

Tango's tango.text.convert.Layout module is the one most similar to std.format, in that the functionality in Layout is used to provide formatting for various purposes such as formatted printing via Stdout.formatln. This is much the same as how std.format is used to do the formatting for std.stdio.writefln and other functions in Phobos.

Layout is a template that can be instantiated for different character types (char,wchar,or dchar). A default char (UTF8) instance is available in tango.text.convert.Format.

For more information about Tango's formatting functions, see API docs, the manual or the formatting tutorial.

std.gc

Interface to interact with the garbage collector, is found in tango.core.Memory.

std.intrinsic

The symbol names for these functions are hardcoded into DMD, however, Tango provides a wrapper module for std.intrinsic that is the preferred method for accessing these functions. This module is tango.core.Intrinsic and may be imported by doing:

import tango.core.Intrinsic;

Be aware that if any name collisions occur, the Phobos name must be provided to disambiguate (ie. std.intrinsic.*).

std.math

Most of the functions in std.math have their equivalents in tango.math.Core, so for those, do

import tango.math.Core;

Note that all the functions here are pure D implementations, and do not use any standard C routines.

Some of the functions present in std.math are low-level math functions, used mainly in library functions. These are imported from tango.math.IEEE by doing

import tango.math.IEEE;

See below for which functions this concerns.

Some of the functions are currently just wrappers around standard C routines, but will replaced by D routines at a later time. Do not use tango.stdc.math to access those functions.

The error functions erf() and erfc() are found in tango.math.ErrorFunction. The gamma functions tgamma() and lgamma() have been moved to tango.math.GammaFunction, but with names changed to gamma() and logGamma().

rndtol

This function does not have an equivalent in Tango.

rndtoln

This function does not have an equivalent in Tango.

modf

This function is just a wrapper around the standard C routine, use from tango.stdc.math.

fabs

Use abs from tango.math.Core instead.

nearbyint

rint

This function is just a wrapper around the standard C routine, use from tango.stdc.math.

lrint

Use rndlong from tango.math.Core.

round

This function is just a wrapper around the standard C routine, use from tango.stdc.math.

lround

This function is just a wrapper around the standard C routine, use from tango.stdc.math.

trunc

This function is just a wrapper around the standard C routine, use from tango.stdc.math.

remainder

Use the mod operator (%) instead.

remquo

This function is just a wrapper around the standard C routine, use from tango.stdc.math.

isnan, isfinite, isnormal, issubnormal, isinf

These classification functions can all be found in tango.math.IEEE, with name capitalisation changes. Many of these functions also have built-in equivalents in the language.

  • isNan(x) is equivalent to x!<>0.
  • isFinite(x) is equivalent to abs(x)<real.max.
  • isInfinity(x) is equivalent to abs(x)==real.infinity.

signbit, copysign

Found in tango.math.IEEE.

nan

The Phobos version of this function did nothing. In Tango, NaN payloads are created with the NaN functions in tango.math.IEEE.

nextafter

Included in tango.math.IEEE with the name nextAfter(), but consider using nextUp() or nextDown() instead.

fdim, fma

Included in tango.math.IEEE.

fmax, fmin

tango.math.Core has max, min, maxNum and minNum.

feqrel

LOCATION NOT YET DETERMINED. Currently in tango.math.IEEE.

std.md5

std.mmfile

std.openrj

std.outbuffer

std.path

The functionality in std.path can mostly be found in tango.io.FilePath. Where std.path provides stand alone functions, FilePath provides two classes, one mutable and one immutable. These classes takes a path as the constructor argument, and provide queries towards this. Since the object is filled at construction, there might be a slight performance hit if you need to query only once, whereas the information is already there for every subsequent query towards the same path, and performance should be better for those cases.

The separator constants are provided in the tango.io.FileConst and changed to camelCase style naming.

Unless otherwise specified, all imports for the Tango examples are

import tango.io.FilePath;
import tango.io.FileConst; // if you need path constants

getExt

char[] mypath = "myfile.ext";
char[] res = getExt(mypath);

translates to

scope mypath = new FilePath("myfile.ext");
auto res = mypath.getExt();

getName

char[] mypath = "/home/foo/bar";
char[] res = getName(mypath);

translates to

scope mypath = new FilePath("/home/foo/bar");
auto res = mypath.getFullPath();

getBaseName

char[] mypath = "/home/foo/bar";
char[] res = getBaseName(mypath);

translates to

scope mypath = new FilePath("/home/foo/bar");
auto res = mypath.getName();

getDirName

char[] mypath = "/home/user";
char[] res = getDirName(mypath);

translates to

scope mypath = new FilePath("/home/user"); 
auto res = mypath.getPath();

getDrive

char[] mypath = r"C:\foo\bar";
char[] res = getDrive(mypath);

translates to

scope mypath = new FilePath(r"C:\foo\bar");
auto res = mypath.getRoot();

defaultExt

This function don't have an equivalent in Tango.

addExt

char[] mypath = "myfile.foo";
char[] res = addExt(mypath, "ext");

translates to

scope mypath = new FilePath("myfile.foo");
auto res = mypath.asSuffix(mypath.getSuffix() ~ ".ext");

isabs

char[] mypath = "/home/foo";
bool absolute = isabs(mypath);

translates to

scope mypath = new FilePath("/home/foo");
auto absolute = mypath.isAbsolute();

join

char[] res = join("/home/foo", "bar/readme.txt");

translates to

scope myPath = new FilePath("bar/readme.txt");
auto res = myPath.join("/home/foo");

fncharmatch

The equivalent resides in tango.util.PathUtil, with the name charMatch().

fnmatch

The equivalent resides in tango.util.PathUtil, with the name patternMatch().

expandTilde

This currently resides in the tango.posix project, the module posix.utils.Tilde.

length

If you need to check whether the path has a length larger than zero, or not, use

if (mypath.isEmpty) {
    ...
}

std.process

Phobos only presents a wrapper around the common C API for executing external programs, while Tango provides an abstraction that is easy to use and extend in tango.sys.Process and tango.sys.Pipe . It also lets you use stdin, stdout, and stderr within the Tango IO/conduit framework, so you can iterate over output, redirect using pipes, and more.

For just executing a process, do

import tango.sys.Process;

If you also want to manipulate the pipes, use the import

import tangy.sys.Pipe;

A simple example follows

try
{
    import tango.sys.Process;
    
    uint i = 0;

    auto p = new Process("ls -al");
    p.execute();
    Stdout.formatln("Output from {0}:", p.programName);

    foreach (line; new LineIterator!(char)(p.stdout))
    {
        Stdout.formatln("line {0}: '{1}'", i++, line);
    }

    auto result = p.wait();
    Stdout.formatln("Process '{0}' ({1}) exited with reason {2}, status {3}",
                    p.programName, p.pid, cast(int) result.reason, result.status);
}
catch (ProcessException e)
{
    Stdout.formatln("Process execution failed: {0}", e.toString());
}

The C execvpe function is present as a static function of the Process class.

std.random

The std.random functions have their equivalents in the tango.math.Random module, and to access them, do

import tango.math.Random;

rand_seed

The random number generator in Tango is a class with static methods that seeds itself from the current time through a static constructor. If you want to reseed, do

Random.seed(mynewseed);

rand

To get the next random number from the generator, you can either do

auto randomnumber = Random.get();

or

auto randomnumber = Random.get(limit);

where limit is the maximum number you want returned.

std.regexp

Tango's tango.text.Regex has been imported from Phobos and can be found by doing

import tango.text.Regex;

std.signals

std.socket

std.socketstream

std.stdint

This module is available as a part of the standard C library in Tango, which is located in the package tango.stdc.

std.stdio

The functionality in std.stdio corresponds mostly to that found in tango.io.Stdout, especially can writef be exchanged with Stdout, although note that Tango uses the new format string syntax found in .Net String.format. Thus

import std.stdio;
writefln("Lucky number is %s.", 42);

becomes

import tango.io.Stdout;
Stdout.format("Lucky number is {}", 42).newline;

For the extended functionality in Tango's formatted output, see API docs, the manual or the formatting tutorial.

std.cstream

std.stream

std.string

toString(int) can be found in tango.text.convert.Integer (Note the recent change: It used to be called toUtf8 in Tango).

toString

int myint = 3;
char[] res = toString(myint);

translates to

import tango.text.convert.Integer;
int myint = 3;
auto res = toString(myint);

format

import std.string;
char[] res = std.string.format("Completed %s of %s", i,N);

translates to

import tango.text.convert.Format;
char[] res = Format("Completed {} of {}", i,N);

For more information about Tango's formatting functions, see API docs, the manual or the formatting tutorial.

std.system

std.thread

Tango exposes its threading features in tango.core.Thread with a similar interface to the one available in Phobos. Differences which may affect existing code are:

  • Thread.wait() is called Thread.join().
  • Thread.wait( milliseconds ) is not available.
  • stacksize is not available as a a ctor option, though its addition is being considered.
  • Thread.run() is not available. Classes deriving from Thread should pass a delegate to super().
  • Thread.getState() is not available. Thread.isRunning() is offered in its place.
  • Thread.setPriority() is not available. Scheduling features may be added later.
  • Thread.isSelf() is not available. Thread.getThis() can easily be used for a similar purpose.
  • Thread.pause(), resume(), pauseAll(), and removeAll() are not available as they are dangerous.

The Tango thread module also has many features which Phobos lacks. These are explained in the module documentation, and further in the threading chapter of the manual.

std.traits

Basic type traits functionality in Tango is available in tango.util.meta.Traits, which may be imported as

import tango.util.meta.Traits;

std.typetuple

std.uni

std.uri

std.utf

std.zip

std.zlib

std.c.*

std.outofmemory

This module unnecessarily exposes internal functionality and is not available in Tango. Its nearest equivalent would be tango.core.Exception which may be impoted as

import tango.core.Exception;