Declares a new variant.
        First determines explicit properties for this variant, by
        refining parents' explicit properties with the passed explicit
        properties. The result is remembered and will be used if
        this variant is used as parent.

        Second, determines the full property set for this variant by
        adding to the explicit properties default values for all properties
        which neither present nor are symmetric.

        Lastly, makes appropriate value of 'variant' property expand
        to the full property set.
        name:                   Name of the variant
        parents_or_properties:  Specifies parent variants, if
                                'explicit_properties' are given,
                                and explicit_properties otherwise.
        explicit_properties:    Explicit properties.

def variant (name, parents_or_properties, explicit_properties = []):
    """ Declares a new variant.
        First determines explicit properties for this variant, by
        refining parents' explicit properties with the passed explicit
        properties. The result is remembered and will be used if
        this variant is used as parent.

        Second, determines the full property set for this variant by
        adding to the explicit properties default values for all properties
        which neither present nor are symmetric.

        Lastly, makes appropriate value of 'variant' property expand
        to the full property set.
        name:                   Name of the variant
        parents_or_properties:  Specifies parent variants, if
                                'explicit_properties' are given,
                                and explicit_properties otherwise.
        explicit_properties:    Explicit properties.
    """
    parents = []
    if not explicit_properties:
        explicit_properties = parents_or_properties
    else:
        parents = parents_or_properties

    inherited = property_set.empty()
    if parents:

        # If we allow multiple parents, we'd have to to check for conflicts
        # between base variants, and there was no demand for so to bother.
        if len (parents) > 1:
            raise BaseException ("Multiple base variants are not yet supported")

        p = parents[0]
        # TODO: the check may be stricter
        if not feature.is_implicit_value (p):
            raise BaseException ("Invalid base variant '%s'" % p)

        inherited = __variant_explicit_properties[p]

    explicit_properties = property_set.create_with_validation(explicit_properties)
    explicit_properties = inherited.refine(explicit_properties)

    # Record explicitly specified properties for this variant
    # We do this after inheriting parents' properties, so that
    # they affect other variants, derived from this one.
    __variant_explicit_properties[name] = explicit_properties

    feature.extend('variant', [name])
    feature.compose ("<variant>" + name, explicit_properties.all())