Skip to content

Migrating from Heist 0.12 to 0.13

Doug Beardsley edited this page Sep 26, 2013 · 3 revisions

Splice Type Signatures

The biggest change in 0.13 is that all the splice type signatures change.

[(Text, a)]

becomes

Splices a

We did this because a list really isn't the proper representation of splices because it doesn't have the right semantics. A list doesn't define behavior for repeated keys. What we really want is a map. Also, the syntax for lists of isn't all that great. The Splices data type gives provides a more concise way of defining splices while at the same time making semantics explicit.

The old syntax looked like this:

userISplices AuthUser{..} =
    [ ("userId",    I.textSplice $ maybe "-" unUid userId)
    , ("userLogin", I.textSplice userLogin)
    , ("userEmail", I.textSplice $ fromMaybe "-" userEmail)
    ]

With the Splices data type, it becomes this:

userISplices AuthUser{..} = do
    "userId"    ## I.textSplice (maybe "-" unUid userId)
    "userLogin" ## I.textSplice userLogin
    "userEmail" ## I.textSplice (fromMaybe "-" userEmail)

The ## function forces the splice to be inserted even if that splice has already been defined. There is also another function #? that does not overwrite an existing splice. A third function #! calls error of the splice already exists. This is useful for getting early warning if you're unknowingly overwriting splices.

Before, if you used the ++ operator to concatenate lists of splices, you'll have to change that to the appropriate unionWith or mappend. The list cons function : should be replaced by insert. Any use of an empty list of splices should change to noSplices or mempty.

Compiled Splice API

The compiled splice API changed drastically. We developed a high level compiled splice API that does not use the Promise type at all. Some of the existing higher level functions changed or disappeared. If you were doing anything that relied on manual use of the Promise type, we highly recommend trying to reformulate to use our high level API. However there are some things that still require using Promise directly. If you need that, you can import the Heist.Compiled.LowLevel module.

Plural splice functions

We removed most of the functions that operated on lists of splices if there was also a version that operated on a single splice. This simplifies the API. It is a little more verbose than before, but we're trying to find the right balance of convenience and API complexity.

pureSplices and textSplices ---> mapS pureSplice and mapS textSplice

Promise functions

In general, any occurrence of Promise a will become RuntimeSplice m a.

Promise a -> C.Splice m becomes RuntimeSplice m a -> C.Splice m

If you had a code snipped like this in 0.12...

foo :: Promise Blah -> C.Splice m
foo blahPromise = return $ yieldRuntime $ do
    v <- getPromise blahPromise
    ...
bar = do
    p <- newEmptyPromise
    ...
    foo p

...it would look something like this in 0.13

foo :: RuntimeSplice m Blah -> C.Splice m
foo getBlah = return $ yieldRuntime $ do
    v <- getBlah
    ...
bar = do
    p <- newEmptyPromise
    ...
    foo (getPromise p)

And depending on what you were doing, you might not even need to create a Promise in bar. The most likely scenario is that you would have some function in your runtime monad that returns a Blah. In that case it's even easier:

blahMaker :: m Blah
bar = do
    ...
    foo (lift blahMaker)

promiseChildren

The promiseChildren function is a combination of runChildren and codeGen.

defer

Any uses of the defer function will usually just disappear (modulo the correct changes everywhere else).