I got into an interesting issue where I wanted to initialise an Array with a ResultBuild, the way I ended up doing it, cause my Array to be continuously reinitialised. I therefor propose that we can conform our types to an ExpressibleByFunctionLiteral so I could turn my code from this:
var components: [GKComponentSystem<GKComponent>] = .init {
NodeComponent.self
MoveComponent.self
VelocityComponent.self
}
To this
var components: [GKComponentSystem<GKComponent>] = {
NodeComponent.self
MoveComponent.self
VelocityComponent.self
}
My thought would be that the conformance looks like this:
What does the builder look like currently? It sounds weird that you'd need to reinitialize array every very often, and weirder that this pitch would help. Maybe we can go to another #swift-users thread to see if there's a better way for the builder.
It's not the builder that's the issue. It used to be just a computed property and that's why it go reinitialised about 60 times a second, and then I refactored it into what it is now which fixed the issue. This was just an example of what I needed, when I thought of the pitch.
The various bits you see here comes from the following:
Looking at the pitch, since generic conforms to protocol only once. You'd be locked to having only[GKComponentSystem<GKComponent>] be EBFL. It doesn't look very versatile.
PS
Note that you can make a builder that initializes the array only at the very end (buildResult). Admittedly, it's much more complex than the naive implementation.
There's also some discussion about adding ArrayBuilder after ResultBuilder landed, we'd probably need more use cases to know how to design it properly.
I tinkered a little with it, and ended up making my own protocol, it's not designed to be good and not going into this specific project either, but I did make something which worked.
protocol ExpressibleByFunctionLiteral {
associatedtype Input
associatedtype Output
associatedtype Function = (Input) -> Output
init(_ function: Function )
}
There's an issue here where it won't infer Input and Output based on init, not sure if that's intended behaviour. I then made an operator (with a throwaway operator)
There's two issues with this. inout doesn't take an uninitialised variable, not even if it's not read, and that seems like by design from a different thread (I'll link it in when I found it). And = is not overloadable, so I can't just write 100% my own Literal protocol.
It's just that associatedtype Function = ... does not require any relationship between Function and (Input) -> Output, just default to (Input) -> Output. It could easily be Int.
typealias just fixes Function to (Input) -> Output, so that the compiler has something to use.
The reason I have the struct wrapper is that I can conform it to ExpressibleBy... and attach static vars/funcs to it for easy use:
myFunc(state: myState, action: [.myAction1, .myAction2]) /// The array makes an action which performs a sequence of subactions
Right now, for a custom action defined by a closure, I either have to make a separate closure version of each function which takes an action, or make a static func wrapper .custom({…})
Not the worst thing in the world, but it would be nice to have ExpressibleAsFunction to allow {…} to just work™ the same way […] does for a sequence of actions...
Edit: In an ideal world, it would allow trailing closure syntax for the last parameter:
myFunc(state: myState) { state in
///Custom Action logic here
}
I am all for this. Currently implementing functional audio DSP framework and DSL for Swift, and it would really help make custom types that are equivalent to a function, and have some additional features to it - it would be kinda like extending function types. We already have callAsFunction, and this will fill in the gap at the other side as well.
This could be useful for dependency injection framework, where dependencies need to be defined as a factory method. Each dependency could have additional attributes if needed (hence they would be managed in a struct), but a standard dependency could be added with a simple block:
struct MyInjections {
var manager1: Injection(factory: { MyManager() }, isSingleton: true)
var manager2: { MyManager() } // default case
}