Not relevant to most situations, but I'll just add that this also makes it extremely difficult to teach a language.
I have taught Ruby -- a language with quite a sweet tooth -- for almost twenty years, and I feel like it gets worse and worse every year. Students run off to look at example code online (as they should), but discover that I have been teaching them what seems to them like a different language.
It really leaves me with no choice but to spend a lot of time in lectures saying, "You can do it this way . . . or this way . . . or this way . . . and by the way, these are all semantically equivalent."
Pretend you know nothing about a language, why would you assume .map { $0.thing } and .map(\.thing) are even remotely similar?
The beginner types a declaration of "I want to _____" and the interface uses ML to auto-suggest code. The auto-suggest would be context-sensitive and fit in with previously written code. Auto-correct would work similarly. If the declaration isn't specific enough, then the auto-suggest tool would ask a series of questions that illustrate the different choices a programmer can make in achieving their goal. Finally, the tool would output code that reflects the beginner's choices.
This would increase the speed of the think-do feedback loop. Beginners would be able to jump into coding with very minimal education and "make" the application they want straight away. Of course, it would usually behoove them to eventually read some programming books and take classes, but this tool would pique their interest. The power of the auto-complete would scale back as the beginner progresses unless they get stuck. Maybe this would only work on a finite set of projects that the ML was trained on, which is fine because you can just give a lot of projects to choose from. That is until the ML becomes more powerful and generalizable.
Swift is a lot like Scala. Swift creators, please not repeat Scala's mistakes.
I'm not sure how invested your team is in Swift, but since we do nothing but Typescript, the investment in time (2-3 days for one the lead engineer) tweaking the linter has more than paid off ten-fold in the months since.
This is one of my concerns with adopting Typescript in my team. Would you please share more info about the kinds of things you prohibit, and why you chose them?
I generally love syntax sugar that makes me more productive, cuts out boilerplate, and reduces cognitive overhead... but for me, callAsFunction and even maybe Key Path Expressions as Functions are going to ADD cognitive overhead.
I suppose if I only used Swift, and used it every day, they would be OK, but otherwise it's just more fiddly things that deviate from existing patterns.
Think most agree expressive syntax while minimizing boilerplate is at times going to require sugar. It's interesting you bring cognitive load into the question – perhaps I come at it more from an architectural light than PL fans, but that load seems largely correlated with one's purposes and patterns in using the language.
On that front, Swift has lofty and broad goals (including DSLs), but that surface area doesn't make the language worse. To take your other example, KeyPath Functions don't change anything about KeyPaths; the concept is and remains no different than anywhere else it's implemented (whether in Swift or in another language). Beginners can still use the concept, skill comes with understanding how/why it works, and mastery comes with knowing when/how to use it simply.
If Swift achieves said goals, one needn't be able to understand the last mile of any specific domain where it's used as a language. But it'll be quicker and easier than coming from another language, and the sugar will still be as sweet.
Frankly, it's misleading/silly for me to complain about Swift additions since I don't have the opportunity to write much of it, and primarily only read/consume it with Obj-C code. (I have no choice in this matter.) Basically the language already has a high cognitive load for me, so of course any additions feel burdonsome.
Also, I'm unfamiliar with using KeyPaths like that, so I'm clearly way off on my reaction to them.
The general goals of Swift make me want to learn it better and use it, honestly.
I could (and do) say the same thing about Perl.
I can already imagine cases where callAsFunction() would be handy. For example, having a viewTemplate = SomeView(customization: etc) then creating copies via viewTemplate()
I could create button templates then make slightly different copies of those templates without having to subclass Button or attaching .copy()
SwiftUI is all about succinctness.
Seeing .copy() makes it much clearer to understand that what I’m receiving is a copy of something.
If you want a Button template, either extend Button with a method taking the parameters you want, or write a curried free function or something. callAsFunction adds absolutely nothing to the language, bar confusion at the call site.
The first time I have to dig into someone's backwards codebase that uses I'm gonna flip.
Objects defining named functions allows you to reason about them logically. Car.tireSizeInches() returns an Int type. Any other developer can see that and know whats up, or type "Car." and explore relevant functionality. What the crap does Car() do? Etc.
This is a huge backwards step for swift syntax. I hope most of the large open source libs ban it.
As for implementation difficulty, see my sibling reply.
If I've got a new team member, I'm not going to put him on async/await. I'm going to find him something simpler to work on.
Or maybe I've been working on a feature for a few months and I need a break to clear my head so I'll work on a smaller feature for a while.
Software development isn't just assembling widgets on an assembly line. It's a creative process. Developers aren't chained to their desks pumping out a non-descript streams of "code" that become different features. Likely incremental time spent on this had almost no real impact on more difficult and useful features.
Sure, but why should this non-feature which makes code harder to read and reason about even be built in the first place? All to save `.parse` at the call site of a parser, for example?
Chances also are that it is inspired by python’s callable (https://en.wikipedia.org/wiki/Callable_object#In_Python), which, as far as I know, people don’t complain about much.
I have seen something similar before in Python where a class implements __call__, but I have never needed to use it.
Isn't this more like a problem you have with the team, rather than a problem with the language itself?
That's the same reply that people have to "C++ has too large a surface area". Granted, Swift isn't quite at C++ levels of complexity yet, but ideally, I shouldn't have to cordon off sections of the language I'm using just so my team can stay sane.
One thing I wish Swift had was an easy way to add more generic functionality. For example, if I want to add drop(), dropWhile(), take(), takeWhile(),... there’s no nice way to extend Array
[1,2,3].take(2)
[“a”,”b”,”c”].take(2)
Btw, I’m working a Swift Cookbook for anyone who quickly wants to come up to speed on Swift. All open source. Feel free to comment or commit.That’s why I provided two examples containing different types to illustrate what I meant.
I don’t believe you can add a generic function to the array to handle this.
In another repo, I’ve used the FloatingPoint protocol with some luck. However, this should also work with Int’s, for instance:
extension Array where Element: FloatingPoint {
var sum: Element {
self.reduce(0, +)
}
}
https://github.com/melling/data-science-from-scratch-swift/b...What’s wrong with something like this?
extension Array {
func take(_ n: Int) -> ArraySlice<Element> {
self[0..<n]
}
}
For your other example, you can make the function accept an array of Ints by constraining Element to AdditiveArithmetic instead of FloatingPoint. extension Sequence where Element: AdditiveArithmetic {
func sum() -> Element {
return reduce(.zero, +)
}
} [1,2,3].take(2)
[“a”,”b”,”c”].take(2)
[p1,p2,p3].take(2)
How much logic are we going to need to repeat for all the types for all the functions? extension Array {
func take(_ n: Int) -> [Element] {
self[0..<n]
}
}
Apple provides this warning for ArraySlice:“Long-term storage of ArraySlice instances is discouraged. A slice holds a reference to the entire storage of a larger array, not just to the portion it presents, even after the original array’s lifetime ends. Long-term storage of a slice may therefore prolong the lifetime of elements that are no longer otherwise accessible, which can appear to be memory and object leakage.”
https://developer.apple.com/documentation/swift/arrayslice
Would it be acceptable to put these implementations in a Functional library?
However, this has nothing to do with generics.If you're willing to sacrifice performance, you could easily write
extension Array {
func take(_ n: Int) -> [Element] {
Array(self[0..<n])
}
}That one and the need for generic associatedTypes trip me up all the time.
I think about it every time I see new feature announcements like today's. The opportunity cost of the wasted effort, the new thing that will probably make things harder for everyone. Possibly including those who try to fulfill the generics manifesto.
This time around it's callAsFunction. Yeah, pretty easy to understand in their toy example. When it's deployed IRL with a ton of other things going on, and larger distances between declaration and usage, it looks like a nightmare.
I love writing Swift for myself, but I write it in a pretty boring way. When I have to work with people who get creative and clever, it's awful.