[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