5 ms·
Eh. Improved error messages is good. The rest look like they aren't worth complicating the language over. Consider: map(\.name) Isn't really more concise
by jmull 7y ago
Eh. Improved error messages is good.
The rest look like they aren't worth complicating the language over. Consider:
map(\.name)
Isn't really more concise than
map { $0.name }
There's one more character and the conventions for whitespace are different. Both require that you know special Swift syntax sugar features, but at least the second one is more generally useful. All we get here is a virtually identical way to do the same thing but with alternate arbitrarily different syntax.
And what's better... this?
struct Dice {
var lowerBound: Int
var upperBound: Int
func callAsFunction() -> Int {
(lowerBound...upperBound).randomElement()!
}
}
let d6 = Dice(lowerBound: 1, upperBound: 6)
let roll1 = d6()
or this?
struct Dice {
var lowerBound: Int
var upperBound: Int
func roll() -> Int {
(lowerBound...upperBound).randomElement()!
}
}
let d6 = Dice(lowerBound: 1, upperBound: 6)
let roll1 = d6.roll()
callAsFunction() makes it a little harder to relate the calling code to the implementing code -- you've got to internalize the new syntax-sugar rule -- and the calling code gets a little less clear in some cases.
Default arguments to subscript functions is probably OK. It's better if all kinds of function have the same capabilities.
- zionic 7y agoPrecisely. Language designers seem to underestimate the cognitive overhead of syntax duplication. StateStream.map { $0.subState }.compactMap(\.subObject).flatMap { $0.objectProperty } Being correct is super frustrating.
- kbenson 7y ago> There's one more character and the conventions for whitespace are different. Never underestimate peoples (often irrational) hatred for sigils, or even things that remind them of sigils.
- anextio 7y agocallAsFunction() isn't really intended to be used in a type like Dice there. It's a bad example. It's for Swift for TensorFlow's integration with Python, in which a bridged Python object can be called as a function. Functions are, of course, objects in Python, so that makes sense, but it would be a pain to have to call fn.call(bar) instead of fn(bar) when fn is a reference to a python object that is a function in its runtime. It's also used in TensorFlow models, in which callAsFunction() is usually implemented as passing the model's input through all the defined layers in it. This makes it easy to treat models as if they were functions, which they mathematically are, unlike Dice. Example: struct MLP: Layer { var layer1 = Dense<Float>(inputSize: 2, outputSize: 10, activation: relu) var layer2 = Dense<Float>(inputSize: 10, outputSize: 1, activation: relu) @differentiable func callAsFunction(_ input: Tensor<Float>) -> Tensor<Float> { let h0 = layer1(input).withDerivative { print("∂L/∂layer1 =", $0) } return layer2(h0) } } (from: https://www.tensorflow.org/swift/tutorials/custom_differentiation https://www.tensorflow.org/swift/tutorials/custom_differenti... )
- zionic 7y ago>It's a bad example. It's a bad example enabled by a bad language feature. Just you wait until answers on stack overflow, sample code, and open source libs are littered with these "bad examples". Meanwhile, this example is terrible. There is no real need for callAsFunction in your example when you could have added a simple named function on the object to do so. Better yet, you could define a protocol and make sure your layer conforms to said protocol.
- chc 7y agoThere is an argument to be made against features that are more likely to cause harm than good (i.e. "footguns"), but I don't think this example of using it poorly sheds any light on whether that's the case here. You could, with roughly the same level of rigor, argue that allowing people to name variables is bad by constructing an example with variables named CONFUSING, CONFUSlNG and CONFUS1NG. Any feature, no matter how good, can be misused. Pointing that out about a specific feature isn't interesting, because it is true of every feature. And the absence of nearly any feature can be worked around, as ultimately all these features compile down to machine code, which doesn't have most features of a high-level language, so the existence of a workaround is also not a very compelling argument.
- deleted 7y ago[deleted]
- smabie 7y agoScala has the same thing with apply() and it works great, allowing the language to have a consistant syntax for function calls, object creation, and array index access.
- fauigerzigerk 7y agoWhat's the difference between a callable object and a closure? I don't see why a language needs both.
- 7y ago
- edflsafoiewq 7y agoYou can already do this func die(lowerBound: Int, upperBound: Int) -> () -> Int { { (lowerBound...upperBound).randomElement()! } } let d6 = die(lowerBound: 1, upperBound: 6) let roll1 = d6() so the syntax already exists.
- lostmsu 7y agoBut what if you want to do something apart from rolling with a die?
- edflsafoiewq 7y agoThen you can create a struct Die and change die to return that. By implementing callAsFunction you keep the same interface as before so existing callers don't break.
- jayd16 7y agoAha ok. This makes far more sense actually. Its a refactor tool for replacing lambdas with callable objects. But does it really work out? Surely you can't put these new structs into the same arrays as similar lambdas, can you?
- nwienert 7y agoTo take the contrary take, I actually welcome keypaths as functions. Why? Keypaths are used in other places and useful. But they aren’t used very often, and I felt I was forgetting their syntax when I first learned Swift. By making them useful in two areas with largely the same semantics, it helps you understand and use them in practice more. In the end it’s all fairly subjective, but it doesn’t bother me as a relative newcomer.
- zyang 7y agoThe key path snippet is not a good example. The real value of key path is nested structures.
- jmull 7y agoWell, what is a good example? The proposal doesn't seem to have one. https://github.com/apple/swift-evolution/blob/master/proposals/0249-key-path-literal-function-expressions.md https://github.com/apple/swift-evolution/blob/master/proposa...
- zyang 7y agoSee last example. https://medium.com/joshtastic-blog/swift-keypaths-ea5a1ec880e9 https://medium.com/joshtastic-blog/swift-keypaths-ea5a1ec880...
- jmull 7y agoI mean an example of why this new language feature -- the ability to implicitly treat a keypath as a function -- is useful. (The last example in your link shows using a keypath to specify a sort criteria. That's a nice use of keypaths, but isn't helped by this new feature.)
- slavapestov 7y ago> Default arguments to subscript functions is probably OK. It's better if all kinds of function have the same capabilities. This was the exact motivation. It was part of a refactoring to clean up some implementation details and resulted in a net deletion of lines of code.