Can a meta-type parameter have a default value?

So far, I had to have two related functions like:

extension Collection {
    /// Returns the ranges for the longest possible subsequences of the collection, in order, that don't contain elements satisfying the given predicate, in a collection of the given type.
    func rangesFromSplitting<T: RangeReplaceableCollection>(storingAs: T.Type, withLimitOf limit: Int?, omittingEmptySubsequences: Bool, whereSeparator isSeparator: (Element) throws -> Bool) rethrows -> T where T.Element == Range<Index>
    { /* ... */ }

    /// Returns the ranges for the longest possible subsequences of the collection, in order, that don't contain elements satisfying the given predicate.
    func rangesFromSplitting(withLimitOf limit: Int?, omittingEmptySubsequences: Bool, whereSeparator isSeparator: (Element) throws -> Bool) rethrows -> [Range<Index>] {
        return try rangesFromSplitting(storingAs: Array.self, withLimitOf: limit, omittingEmptySubsequences: omittingEmptySubsequences, whereSeparator: isSeparator)
    }
}

because this doesn't work:

extension Collection {
    /// Returns the ranges for the longest possible subsequences of the collection, in order, that don't contain elements satisfying the given predicate.
    func rangesFromSplitting<T: RangeReplaceableCollection>(storingAs: T.Type = Array<Element>.self, withLimitOf limit: Int?, omittingEmptySubsequences: Bool, whereSeparator isSeparator: (Element) throws -> Bool) rethrows -> T where T.Element == Range<Index>
    { /* ... */ }
}

Where the use of Array<Element>.self as a argument default is flagged as an error by:

Default argument value of type 'Array<Self.Element>.Type' cannot be converted to type 'T.Type'

Is there some sort of safety or type-theory reason why this isn't supported? Or did the implementers just forgot this case? Or is there a way to do this?

(BTW, using "Array.self" doesn't work because "Generic parameter 'Element' could not be inferred". A fix was offered, which changes the type to Array<Any>.self, and then goes to the conversion error from my main case.)

Default argument expressions must be valid for all type arguments. This means they can only be defined in terms of API made visible by the constraints on the corresponding type argument.

I pitched [Pre-pitch] Conditional default arguments a while ago which would allow you to specify this default conditionally. That pitch is syntactic sugar to avoid needing to write overloads that omit the type argument and corresponding method argument. Short of that feature being implemented, it’s always possible to write the overloads manually, even if it is not ideal.

So would a generic default argument capability like:

func rangesFromSplitting<T = [Element]: RangeReplaceableCollection>(storingAs: T.Type,  //...

be better instead? Am I misunderstanding what you said?

This is an orthogonal feature that would also be very nice to have. It wouldn’t let you specify a default argument expression that depended on the default type argument being the actual type argument though.

Terms of Service

Privacy Policy

Cookie Policy