A Tour of Morfa

User-defined conversions

User-defined conversions are in fact a special kind of functions. They are always called convert, take one argument of the "source" type and return a value of the "target" type.

To define a user conversion between two types, define a convert function using appropriate argument and return types. In the following example a bool value is converted to text so that you may use 'true' and 'false' wherever a text value is expected:

public func convert(condition: bool): text
{
    if (condition) 
        return "true";
    else 
        return "false";
}

import morfa.Text.base: upperCase, replaceFirst;

unittest
{
    assert(upperCase(false) == "FALSE");
    assert(replaceFirst("I'm a false sentence.", false, true) == "I'm a true sentence.");
}

General rules of scoping and access modifiers apply to user-defined conversions as well. Note the use of conversions defined within a class.

// private, unsafe conversion unavailable outside the module
func convert(quantity: float): bool
{
    return quantity > 0.0;
}

class A
{
    // not accesible outside A, non-static - uses context of the instance of A
    func convert(what: text): A
    {
        if (what == "this")
            return this;
        else
            return A.init; // null
    }

    public func getThis(): A
    {
        return "this";
    }
}

Conversions may be templated as ordinary functions.

template <T>
class Classy
{
    var data: T;
    public func new(t: T) { data = t; }
}

template <T>
func convert(t: T): Classy<T>
{
    return new Classy<T>(t);
}

unittest
{
    // using the unsafe conversion from float to bool
    assert(3.14);
    assert(not -1.0);

    // the following uses a class-defined conversion in A
    var a = new A;
    assert(a == a.getThis());
    // var a: A = "this won't compile - conversion undefined here";

    // use a conversion from any type to its class wrapper
    var classy: Object = 5;
    assert(classy != null);
}

Similar to C++, at most one user conversion will be used in a conversion sequence, but any built-in conversions may be done before and after the user conversion. This happend in the var classy: Object = 5—the conversion from Classy to its supertype Object is built-in.

Redefining built-in conversions using func convert is illegal.