Implementing a Swift undo stack the impossible way

14 views
Skip to first unread message

Jake Bromberg

unread,
Jul 9, 2015, 5:41:42 PM7/9/15
to swift-l...@googlegroups.com
I've been trying to implement an undo stack that leverages the type system in Swift. My particular approach is to memoize both the function used and the parameters passed to that function. If I can get this to work, as I see it, it would be an improvement over the pattern described in GOF. No success yet.

public struct Command <Parameters, Results> {
    let action : (Parameters -> Results)
    let parameters : Parameters

    init(action a : Parameters -> Results, parameters p : Parameters) {            action = a
        parameters = p
    }}

let cmd1 = Command(action: { return $0 + " World" }, parameters: ("Hello"))
let cmd2 = Command(action: { return $0 + $1 + $2 }, parameters: (1, 2, 3))

let undos = [cmd1, cmd2]

Error:

'_' is not convertible to 'Command<(Int, Int, Int), Int>'
Type of expression is ambiguous without more context

I get that the generic types are not equivalent for all instances of Command, but I'm not sure what the fix for this would be given the new semantics. 

I'm not going to define equality for every type of tuple that wants to participate in the undo system (this is more annoying than GOF).

So in an attempt to get the array to accept heterogeneous types, I tried pulling the generic types into a protocol as type aliases. Problem again: this only shifts the problem around, since it's the Command that now needs nail down the type of the alias, which forces a different Command implementation for each pair of associated types. 

At this point I've run out of ideas. What am I missing?

Thanks,
—Jake

Ken Ferry

unread,
Jul 9, 2015, 6:24:12 PM7/9/15
to Jake Bromberg, swift-l...@googlegroups.com
What do you want it to look like when the undos are used? Something like

    undo.invoke()

?  If that's the case, I think you want to remove the parametrized types from Command<Parameters,Results>. They're not relevant to users of resulting commands. 

You can often remove type parameters by using closures (when they're inessential). For example,

    public struct Command  {
        let invoker : ()->()
        init<Parameters, Results>(action a : Parameters -> Results, parameters p : Parameters) {
            invoker = { a(p) }
        }
    }

    let cmd1 = Command(action: { return $0 + " World" }, parameters: ("Hello"))
    let cmd2 = Command(action: { return $0 + $1 + $2 }, parameters: (1, 2, 3))

    let undos = [cmd1, cmd2]

You could also consider whether you need a custom Command type at all, or whether a closure already does the trick.

-ken



--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to swift-languag...@googlegroups.com.
To post to this group, send email to swift-l...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/CA%2B5croLgY2_bueJg%3DRqF5j6XqS4whRKDA2-hjKs%3DqQSNbToovQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages