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.
_______________________________________________ Ur mailing list [email protected] http://www.impredicative.com/cgi-bin/mailman/listinfo/ur
