This is a very odd post. It basically boils down to default arguments only work on named functions, they don't work on function values (whether this is a curried function, or a declared value of function type). Which seems like a perfectly reasonable restriction to me; default argument values are a property of named functions, not of function types, and cannot be expressed in the type system. While it's not out of the realm of possibility for Swift to extend the type system to support this, it's not something I'd hold my breath for and it's not something I feel that I could rightly criticize Swift for not having. And yet, the author declares "Now, you hate Swift" based on this one perceived limitation.
It's not "one perceived limitation" though. You work with Swift enough, you start tripping over things like this on a regular basis. I think I've had "Oh this isn't implemented yet… wait, my workaround isn't implemented either!" dance several times.
They aren't limitations by design. They are just things that the Swift team haven't gotten around to doing yet. Take a look at some of the messages from Apple engineers tracked by Swift in Flux [0], for example. It's full of things like:
> Optional methods in protocols are limited to @objc protocols only because we haven't implemented them in native protocols yet. This is something we plan to support.
…and:
> > [Is there any] specific reason why you can't reference initializers like a function?
> No particular reason, it's just not implemented.
…and:
> We currently have limitations in the type system and implementation that force some things (e.g. countElements and many others) to be global functions instead of methods, but we consider this a deficiency, not a feature.
…and:
> The prevalence of generic free functions is more about current language limitations than an intentional stylistic direction
It's a good language, but it's terribly unfinished. Back when Swift was in beta, things like this were to be expected, but Swift 1.2 feels more like Swift 0.2 to me. Apple are filling in the missing parts, but at the rate they are going, it will probably only end up feeling like a complete language at next year's WWDC.
Yeah, it boils down to that, but there's a reason the author wrote this article, rather than a three-sentence paragraph.
His point is that this is not just a "perceived problem", but a real problem that affects regular working programmers. What's more meat-and-potatoes than HTTP requests?
The author wanted to "generalize everything" and "wrap everything." And I can't imagine that he will ever use all the functionality that he tried to "cover."
Compare that to pragmatism of not spending time trying to do what's not going to be needed.
it is clearly a language related problem where the author shows that the language design is not consistent.
You can always work around these issues after all the language is turing complete.
However, this is not about if there is a program that functionally equivalent, this is about writing code that is minimal and can be read well and can be supported easily over a longer period of time.
What makes you say the language is not consistent? Default parameters are a feature of named functions. Currying is a different feature of functions. A curried function is equivalent to a non-curried function that returns a function. Since the returned function is not a named function, it cannot have default parameters. Therefore, default parameters are not allowed in curried functions.
Beyond that, the author's proposed API is most definitely not the best API design to use here, even if the default parameters did work in curried functions. A builder pattern would make a lot more sense. Or just do as Cocoa already does and provide a request object that can be customized before initiating the HTTP call.
If the goal is "is minimal " and "can be supported easily over a longer period of time" he should stick to the API and not try to wrap everything. He can make his own functions which are more minimal for his use cases. I argue that he will never in his code use most of the things he tries to cover. If he just writes just what he really needs in his real use cases he'll have much less problems for supporting it.
The worst code to support is "I don't use that but I might need it once."
> default argument values are a property of named functions, not of function types, and cannot be expressed in the type system.
For what reason? Isn't the gripe exactly with the fact that it's not implemented?
Also why are arguments required to be named in all calls after the first, but not the first?
func f(a: Int)(b: Int)(c: Int) -> Int {
return a + b + c
}
let v = f(2)(b: 5)(c: 5)
Stuff like this just eats at me when i use a language, especially when that language is brand new and other languages have had nice syntax for similar features for a long time.
> For what reason? Isn't the gripe exactly with the fact that it's not implemented?
How should it be represented in the type system? There's no clear answer to that question.
The type of a function is `(Args) -> Ret`. `->` is basically an infix type constructor with two type parameters; it's basically sugar for something along the lines of `Func<(Args),Ret>` (except there's no actual type named that). The arguments list here is actually just a tuple, and functions with named arguments have an arguments list which is a tuple with named fields (since Swift supports that). Given all this, I don't see how default parameters could be crammed in. At a syntactic level, you could say something like `(a: Int = default, b: String = default) -> String`, but when you realize that the arguments list is a tuple, a "tuple with default field values" is a nonsense thing to try and construct.
Also, more generally, a function with default parameters is actually a family of functions, one for each valid combination of parameters. But a function value is a single function, not a family of functions. When you think about it like that, trying to return a function value with default parameters makes no more sense than trying to return a generic function that hasn't been instantiated with concrete type parameters (e.g. you cannot say `func foo() -> (<T>(x: T) -> T)` or anything along those lines). Function values must be a single concrete function, not a family of functions.
They're not required, they just default to having a name. You can tell the compiler you don't want a name, and it works:
func f(a: Int)(_ b: Int)(_ c: Int) -> Int { return a + b + c }
let v = f(2)(5)(5)
The rules for what gets an externally visible name automatically are pretty weird, to be sure. But it's easy to have it do what you want if you don't want the default.