Default values for generic parameters?

In Alamofire 5 we added the ability to pass Encodable types as request parameters. Currently, the methods to do so look like this:

open func request<Parameters: Encodable>(_ convertible: URLConvertible,
                                         method: HTTPMethod = .get,
                                         parameters: Parameters? = nil,
                                         encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default,
                                         headers: HTTPHeaders? = nil,
                                         interceptor: RequestInterceptor? = nil) -> DataRequest

However, I've realized that, without the request overload we provide for compatibility with older, no generic parameters, this method can't be used without providing a parameters value, as otherwise the compiler can't infer that type. Within this method we capture the various parameters into a generic struct that gets passed further into Alamofire, and I could pass that value our Empty type as Optional<Empty>.none, and then offer an additional request overload that doesn't require parameters. However, that seems suboptimal, so I'm wondering if there's a way to get the default value for parameters to work the way I want, that is by allowing any type, but when one isn't provided, using some concrete value to represent no parameters.

Any ideas?

1 Like

Yes, all request components are eventually erased into a URLRequestConvertible value. However, JSONEncoder requires a generic Encodable parameter:

func encode<T>(_ value: T) throws -> Data where T : Encodable

Therefore we can't erase the Encodable parameters.

Bump. +1.

I'd also really like to see this addressed in some way. Here's part of an API I'm working on:

public mutating func replaceComponents<Components>(
  _ range: Range<Index>, with newComponents: Components
) -> Range<Index> where Components: Collection, Components.Element: StringProtocol {
  // ...
}

Unfortunately, this means users can't use empty array literals, because the compiler doesn't know what type Components should be:

replaceComponents(someRange, with: []) // Error: Value of protocol type 'Any' cannot conform to 'StringProtocol'; only struct/enum/class types can conform to protocols

If I wanted to support this, I'd have to replace the generic function with an _impl function, and add 2 entry-points - one from String, another from StringProtocol (the String version cannot call in to the generic version directly, as it itself is a more-specific overload so this would recurse until stack overflow). This function also has a fairly lengthy documentation comment, so I'd have to copy that and keep it synced.

It's manageable, but it's clunky. And if I decide it isn't worth the bother, users will be hit with a cryptic error talking about how Any can't conform to protocols :neutral_face::man_shrugging: