> 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.
AFNetworking seems to still have too much in the way for my taste, but maybe i'm missing something. Couple of questions:
If i want to generate url requests, i have to use a serializer class. For me, it seems like overkill to have a stateful serializer. Are there a lot of cases where people change the state of the serializer once created? If not, then wouldn't it be better to just expose all the setup functionality through simple wrapper functions instead of wrapper classes, and let people layer these as they see fit (possibly with server-specific categories)?
For multipart requests, why did a protocol with appends and requiring a block with stateful appends end up making more sense than just taking an array of the parts? My impression is that it feels like a lot of chatter for multipart setup. It seems like something that could just be encapsulated as one output from a set of inputs (function). In practice, i've found this approach works better for me.
> If i want to generate url requests, i have to use a serializer class...
No, you don't. There's nothing stopping you from creating `NSURLRequest` directly.
> ...wouldn't it be better to just expose all the setup functionality through simple wrapper functions?
Request serializers are not unlike any other class in Cocoa, like say NSURLSessionConfiguration, which is not often mutated beyond initial setup, but exposes properties to remain flexible and not overwhelm the user with init parameters.
What you're suggesting sounds much, much worse.
> For multipart requests, why did a protocol with appends and requiring a block with stateful appends end up making more sense than just taking an array of the parts?
Not using a protocol / builder pattern here would be awful.
You'd have to create classes for each kind of part, which gets complicated because AFNetworking handles data, files, and streams alike. So that's, like, 3 extra top-level classes. And even that doesn't really work, since it makes it really difficult to just append data to the multipart body manually, in case there was some missing functionality that AFN didn't provide. Add to that the consideration of how to specify options on the stream itself, like throttling...
You should give all of that another look—it's one of the best parts of AFNetworking.
> No, you don't. There's nothing stopping you from creating `NSURLRequest` directly.
There is a lot of basic http setup missing from NSMutableURLRequest that needs to live somewhere.
> Request serializers are not unlike any other class in Cocoa, like say NSURLSessionConfiguration, which is not often mutated beyond initial setup, but exposes properties to remain flexible and not overwhelm the user with init parameters.
Except NSURLSessionConfiguration is more of a data type, right? By that I mean it is just a blob of parameters that can be inspected. The serializer is not just a configuration, it's something with an 'er' on the end. Plus, many of its properties are direct duplications of NSMutableURLRequest that could just be set after the fact in a wrapper function. AFJSONRequestSerializer and others suggest i follow a pattern of subclass inheritance to provide further customization when everything is just permutations on values of a core set of parameters.
> You'd have to create classes for each kind of part, which gets complicated because AFNetworking handles data, files, and streams alike. So that's, like, 3 extra top-level classes. And even that doesn't really work, since it makes it really difficult to just append data to the multipart body manually, in case there was some missing functionality that AFN didn't provide. Add to that the consideration of how to specify options on the stream itself, like throttling...
I don't understand this argument. What's wrong with creating the simple data types for the cases you need to cover? What is the importance of the top level class count metric? Would a fourth top level data type for the raw data case suffice? Can't throttling go in a parameter of the outer configuration data type?
> You should give all of that another look—it's one of the best parts of AFNetworking.
Maybe. When i look at it i see class hierarchies, singletons, and protocols with contractual state manipulation for a case that seems to (maybe it doesn't?) reduce to an output (NSMutableURLRequest) that's a straight function of a bunch of inputs.
Still too complicated. IMO none these libraries should hide NSMutableURLRequest. A lot of their functionality can and should just be exposed as category extensions to NSMutableURLRequest and a bag of utility functions.
We should expose composable pieces to assist with use of the existing APIs, not build monolithic wrappers that get in our way by hiding entire chunks of APIs in the guise of simplicity, since eventually this just requires us to reimplement the needed abstractions in a different way once our wrappers' limitations become apparent.
So today, it's simple. Tomorrow, since it sees more use by people with different needs and it ends up looking a little more like AFNetworking. The next day upstream adds some features that don't quite fit with how simple we thought everything should be, so we twist things a little. And one day we look up and it's all really complicated, so we scrap everything and start again with a nice simple wrapper to hide all that stupid stuff.
And some days later, someone needs to satisfy a network requirement, but since the authors of all of their different dependencies chose different network wrappers (they each had an opinion about what not to expose), everything is really hard to centralize.
Agreed, application-level tab support is a short term win. I wouldn't want to use a browser without them, but i would rather it was all a well thought out part of my main interface.
Is Super Mario Bros. a kernel? Every NES, Game Boy, Sega Genesis, etc... game ran on the "bare metal" without anything resembling an OS (or even a BIOS, really).
Things get even more exciting when you want to push that submodule commit afterwards to fix things, only to find out that someone sneaked in a commit in the meantime! Now you’ll have to create a new commit on the top-level project to point it to your rebased commit, hah!
I don't quite understand this one. "Now you’ll have to create a new commit...". At this point, you haven't yet created a top-level project commit at all.
If the sequence is commit to submodule, push submodule, update top-level module, where is the headache that is unique to submodules here?
If that’s not enough to convince you, you should try branching with this setup. You’ll have to manually branch (and later merge) each of your submodules when you create a new branch. In the past, I have worked with a git repository containing a dozen tightly-coupled submodules for code-sharing with other teams. Needless to say, it didn’t take very long to realize that submodules are not suited for that use case.
Why was submodule better than just using a single repo and multiple remotes in this case? Or put another way, what did you gain by having separate repos if all the repos branch and come back in exactly the same way.
I feel like i can still make a lot of commits on both top-level and submodules but not have a headache, the parallel branching thing seems odd to me.
I don't quite understand this one. "Now you’ll have to create a new commit...". At this point, you haven't yet created a top-level project commit at all.
That sentence intends to illustrate what can happen when you forget to push your submodule commit before commiting on the top-level repository.
Why was submodule better than just using a single repo and multiple remotes in this case?
I'm not sure what you mean with this.
Or put another way, what did you gain by having separate repos if all the repos branch and come back in exactly the same way.
We used submodules because the code in the submodules was shared with another team.
You want to also branch the submodules so as not to break another branch.
I set a one hour timer on my phone. The agreement with myself is that i will not stand up, not open a browser for something unrelated, not go to the bathroom, not speak to anyone, not listen to anyone, not do anything but focus on the one task at hand until the timer goes off. This can be planning or actually writing code, but i only work on the task.
By the time the timer goes off, i'm usually pretty immersed. The more i do it the less i use the timer, i just need it to get out of slumps.
And i don't start the timer unless i'm sure i'm ready to commit the hour. Deciding to commit alone helps me get rolling.
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.