[Ur] FFI and transactions

Marc Weber marco-oweber at gmx.de
Sun May 29 07:30:59 EDT 2011


Excerpts from Robin Green's message of Sat May 28 20:02:34 +0200 2011:
> Hi,
> 
> Some FFI questions:
> 
> 1. What is the difference between marking a function as effectful (or
> benignEffectful) when writing an FFI function, and giving it a
> transactional return type? Doesn't one have to do both - and if so, why
> the redundancy?

Let me try (and be corrected by others): Transactional return types are
being used to enforce that the transaction is run once. Its being used
to prevent mixing different transactions in the same execution flow.

So the point is that you usually have combinators which take two
transactional code blocks making one transactional block which you can
run. If code fails usually everything which was done in the block fails/
gets reverted etc.

Eg STM (shared transactional memory) monad of Haskell is a nice example
here.

Example would look like this:

x = createSTMVar 2
y = createSTMVar 2

addToX = modifyVTMVar x (+1)

addToY = modifyVTMVar y (+1)

addToBoth = addToX >> addToY

Here the ">>" monadic combinator does the glueing:
Now if addToX is succeeds, but addToY deos not (because another thread
has written to y meanwhile) then the first action is taken back.
That this "taking back" takes place is enforced by type. You can't run
addToBoth in your main function because types don't match. You have to
embed the function some additional "do all the transaction stuff"
function. So the  final invokation looks like this:

main =  print "START" >> runSTM addToX >> print "DONE"
 
Note that >> here operates on IO monad, not the STM. It can be overloaded.
the runSTM turns the STM type into an ordinary IO type.

In urweb such a runTransaction wrapper would catch excetpions and do
database rollback or such. However I still haven't turned my head around
the urweb implementation. So this is only to give you an idea about what
this all is about.



Marking a function as effectfull will change the compilers behaviour.
Example:

let x = add(2,2)
let y = x + x

if x was not effectfull the compiler may choose to turn this into
y = add(2,2) + add(2,2)

if add did also a remove("file-path") then it should not do so, because 
the second run would fail cause you can delete a file once only.

However because urweb may retry any request arbitrarily  often
I don't know yet which is the best way to run code which cannot be
undone (such as comitting payments to external apis)

So when running effectful code on the server you have to keep some state
maybe do some result caching or handle "this transaction was already
completed" replies from the server in case urweb retries..

> 2. In the manual it says benignEffectful is for effects which are local to
> the session. Is this synonymous with request-local? I wouldn't expect it
> to be - in my understanding of the terms request and session, a user can
> make multiple simultaneous requests within a session.

> 3. What is the recommended way of passing back references to memory
> dynamically allocated from foreign code to Ur/Web code - assuming that the
> foreign code is going to *write* to that memory in future calls? Since
You have to do your very own memory management using malloc ..
and its also you having to free the memory.

If you want a quick and dirty way - you might want to look into the ruby
embedding. Then you can move this stuff into ruby (which of course will
make urweb a lot slower)..

Here you can keep state easily by assigning global vars.

However it has been testing code only.. no production use.

HTH
Marc Weber



More information about the Ur mailing list