[Ur] FFI and transactions

Adam Chlipala adamc at impredicative.com
Sun May 29 12:25:29 EDT 2011


Robin Green wrote:
> 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?
>    

Marking transactionality in a function's type is essential to the 
Haskell-inspired injection of impurity within a pure functional language.

Effectfulness annotations in .urp files are used in two places: checking 
that no page meant to be accessed via GET requests could have persistent 
side effects, and taking advantage of some possibilities for algebraic 
rewriting during optimization.  It turns out that this rewriting happens 
on intermediate code that has lost the original type information, which 
is the proximate reason why the extra annotations are needed.  The 
difference between benign and normal effectfulness is certainly an 
important one that couldn't be recovered from types, but that doesn't 
preclude the possibility that it would be better to make normal 
effectfulness the default for any transactional value.  I just haven't 
decided to implement such a thing yet.

There _is_ the (admittedly minor) fact that a function with a 
transactional type may turn out to have a completely pure implementation 
under the hood, such that effectfulness annotations can help the 
optimizer make better decisions.

> 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.
>    

Yes, the intent is synonymous with "request-local."  I recognize that 
"session" was a poor choice of words, since many web frameworks assign 
an entirely different meaning to the word (and Ur/Web assigns no 
meaning, which leaves me wondering what I was thinking when I wrote that 
:]).  I've updated the manual accordingly.

> 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
> Ur/web ints are C long longs (which should be at least as wide as a
> pointer, as far as I know) I guess casting a pointer to an Ur/web int and
> returning that is OK - whereas returning a blob isn't, because that would
> end up breaking purity on subsequent calls that write to the blob. I
> assume that the function should return a transaction *and* be marked as
> benignEffectful?
>    

Why not just use the most natural C pointer type for such values?  
Perhaps I've misunderstood your question.  As Marc pointed out in 
another reply in this thread, you are responsible for manual memory 
management within C FFI code, just as in usual C code, so no choice of 
type encoding will get the Ur/Web runtime system to track storage 
lifetime.  Data values meant to last through just a single transaction 
may, however, be allocated with uw_malloc(), in which case you can trust 
the runtime system to free them afterward.

Perhaps the piece you're missing is that abstract types in FFI modules 
may be implemented with arbitrary C types, with no restrictions?  (They 
may even be implemented with structs (not just struct pointers)!)

Any function causing any side effect should indeed have a transactional 
type and be marked as effectful.  "benignEffectful" is the appropriate 
choice when the function's effects don't outlive the transaction.



More information about the Ur mailing list