Skip to main content

Active Objects Based on Algebraic Effects

  • Chapter
  • First Online:
Active Object Languages: Current Research Trends

Abstract

Algebraic effects are a long-studied programming language construct allowing the implementation of complex control flow in a structured way. With OCaml 5, such features are finally available in a mainstream programming language, giving us a great opportunity to experiment with varied concurrency constructs implemented as simple libraries. In this article, we explore how to implement concurrency features such as futures and active objects using algebraic effects, both in theory and in practice. On the practical side, we present a library of active objects implemented in OCaml, with futures, cooperative scheduling of active objects, and thread-level parallelism. On the theoretical side, we formalise the compilation of a future calculus that models our library into an effect calculus similar to the primitives available in OCaml; we then prove the correctness of the compilation scheme.

This is a preview of subscription content, log in via an institution to check access.

Access this chapter

Chapter
USD 29.95
Price excludes VAT (USA)
  • Available as PDF
  • Read on any device
  • Instant download
  • Own it forever
eBook
USD 59.99
Price excludes VAT (USA)
  • Available as EPUB and PDF
  • Read on any device
  • Instant download
  • Own it forever
Softcover Book
USD 74.99
Price excludes VAT (USA)
  • Compact, lightweight edition
  • Dispatched in 3 to 5 business days
  • Free shipping worldwide - see info

Tax calculation will be finalised at checkout

Purchases are for personal use only

Institutional subscriptions

Notes

  1. 1.

    In our implementation we choose to adopt the Actor terminology instead of active objects because we believe actors are better known in the functional programming community.

  2. 2.

    For this purpose, we use PPX, a specific hook that allow to extend OCaml with new lightweight syntax extensions.

  3. 3.

    In the future, we hope to turn asynchronous calls in a into delegation automatically.

  4. 4.

    Already in [6], the authors prevented forward from appearing inside a closure.

  5. 5.

      denotes the reflexive transitive closure of the relation .

  6. 6.

    A few substitutions have occurred inside poll by definition of \(C_c\). We omit them here not to clutter the proof.

  7. 7.

    Resp. \(\sigma _1(\ell _{threads})[f_2] = \mathbb {C}\left( \lambda () . ((\lambda x. C[x]) ~e)\right) \).

  8. 8.

    Resp. and \(e_2=\mathbb {C}\left( \lambda () . ((\lambda x. C[x]) ~e)\right) \).

  9. 9.

    Resp. with two steps of beta-reductions.

References

  1. Baker Jr., H.G., Hewitt, C.: The incremental garbage collection of processes. In: Proceedings Symposium on Artificial Intelligence and Programming Languages, New York, NY, USA, pp. 55–59 (1977)

    Google Scholar 

  2. Bauer, A., Pretnar, M.: Programming with algebraic effects and handlers. J. Log. Algebraic Methods Program. 84(1), 108–123 (2015). https://doi.org/10.1016/j.jlamp.2014.02.001

    Article  MathSciNet  Google Scholar 

  3. de Boer, F., et al.: A survey of active object languages. ACM Comput. Surv. 50(5), 76:1–76:39 (2017). Article 76

    Google Scholar 

  4. Caromel, D., Henrio, L., Serpette, B.: Asynchronous and deterministic objects. In: Proceedings of the 31st ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pp. 123–134. ACM Press (2004)

    Google Scholar 

  5. Chappe, N., Henrio, L., Maillé, A., Moy, M., Renaud, H.: An optimised flow for futures: from theory to practice. CoRR abs/2107.07298 (2021). https://arxiv.org/abs/2107.07298

  6. Fernandez-Reyes, K., Clarke, D., Castegren, E., Vo, H.P.: Forward to a promising future. In: Di Marzo Serugendo, G., Loreti, M. (eds.) COORDINATION 2018. LNCS, vol. 10852, pp. 162–180. Springer, Cham (2018). https://doi.org/10.1007/978-3-319-92408-3_7

    Chapter  Google Scholar 

  7. Fernandez-Reyes, K., Clarke, D., Henrio, L., Johnsen, E.B., Wrigstad, T.: Godot: all the benefits of implicit and explicit futures. In: Donaldson, A.F. (ed.) 33rd European Conference on Object-Oriented Programming (ECOOP 2019). Leibniz International Proceedings in Informatics (LIPIcs), vol. 134, pp. 2:1–2:28. Schloss Dagstuhl-Leibniz-Zentrum fuer Informatik, Dagstuhl (2019). https://drops.dagstuhl.de/opus/volltexte/2019/10794. Distinguished artefact

  8. Graf, S., Sifakis, J.: Readiness semantics for regular processes with silent actions. In: Ottmann, T. (ed.) ICALP 1987. LNCS, vol. 267, pp. 115–125. Springer, Heidelberg (1987). https://doi.org/10.1007/3-540-18088-5_10

    Chapter  Google Scholar 

  9. Halstead, R.H., Jr.: MULTILISP: a language for concurrent symbolic computation. ACM Trans. Program. Lang. Syst. (TOPLAS) 7(4), 501–538 (1985)

    Article  Google Scholar 

  10. Henrio, L.: Data-flow explicit futures. Research report, I3S, Université Côte d’Azur (2018). https://hal.archives-ouvertes.fr/hal-01758734

  11. Henrio, L., Johnsen, E.B., Pun, V.K.I.: Active objects with deterministic behaviour. In: Dongol, B., Troubitsyna, E. (eds.) IFM 2020. LNCS, vol. 12546, pp. 181–198. Springer, Cham (2020). https://doi.org/10.1007/978-3-030-63461-2_10

    Chapter  Google Scholar 

  12. Hillerström, D., Lindley, S.: Shallow effect handlers. In: Ryu, S. (ed.) APLAS 2018. LNCS, vol. 11275, pp. 415–435. Springer, Cham (2018). https://doi.org/10.1007/978-3-030-02768-1_22

    Chapter  Google Scholar 

  13. Johnsen, E.B., Blanchette, J.C., Kyas, M., Owe, O.: Intra-object versus inter-object: concurrency and reasoning in Creol. In: Proceedings of the 2nd International Workshop on Harnessing Theories for Tool Support in Software (TTSS 2008). Electronic Notes in Theoretical Computer Science, vol. 243, pp. 89–103. Elsevier (2009)

    Google Scholar 

  14. Johnsen, E.B., Hähnle, R., Schäfer, J., Schlatte, R., Steffen, M.: ABS: a core language for abstract behavioral specification. In: Aichernig, B.K., de Boer, F.S., Bonsangue, M.M. (eds.) FMCO 2010. LNCS, vol. 6957, pp. 142–164. Springer, Heidelberg (2011). https://doi.org/10.1007/978-3-642-25271-6_8

    Chapter  Google Scholar 

  15. Leonard, T., et al.: Eio 1.0 - effects-based IO for OCaml 5. OCaml Workshop (2023)

    Google Scholar 

  16. Leroy, X.: Formal certification of a compiler back-end, or: programming a compiler with a proof assistant. In: 33rd ACM Symposium on Principles of Programming Languages, pp. 42–54. ACM Press (2006). https://xavierleroy.org/publi/compiler-certif.pdf

  17. Liskov, B., Shrira, L.: Promises: linguistic support for efficient asynchronous procedure calls in distributed systems. In: PLDI 1988, pp. 260–267. Association for Computing Machinery, New York (1988). https://doi.org/10.1145/53990.54016

  18. Niehren, J., Schwinghammer, J., Smolka, G.: A concurrent lambda calculus with futures. Theor. Comput. Sci. 364(3), 338–356 (2006)

    Article  MathSciNet  Google Scholar 

  19. Sieczkowski, F., Pyzik, M., Biernacki, D.: A general fine-grained reduction theory for effect handlers. Proc. ACM Program. Lang. 7(ICFP) (2023). https://doi.org/10.1145/3607848

  20. Sivaramakrishnan, K.C.: https://github.com/kayceesrk/ocaml5-tutorial. Accessed 30 May 2023

  21. Sivaramakrishnan, K.C., et al.: Retrofitting parallelism onto OCaml. Proc. ACM Program. Lang. 4(ICFP), 113:1–113:30 (2020). https://doi.org/10.1145/3408995

  22. Sivaramakrishnan, K.C., Dolan, S., White, L., Kelly, T., Jaffer, S., Madhavapeddy, A.: Retrofitting effect handlers onto OCaml. In: Freund, S.N., Yahav, E. (eds.) PLDI 2021: 42nd ACM SIGPLAN International Conference on Programming Language Design and Implementation, Virtual Event, Canada, 20–25 June 2021, pp. 206–221. ACM (2021). https://doi.org/10.1145/3453483.3454039

  23. Taura, K., Matsuoka, S., Yonezawa, A.: ABCL/f: a future-based polymorphic typed concurrent object-oriented language - its design and implementation. In: Proceedings of the DIMACS Workshop on Specification of Parallel Algorithms, pp. 275–292. American Mathematical Society (1994)

    Google Scholar 

  24. Vouillon, J.: LWT: a cooperative thread library. In: Sumii, E. (ed.) Proceedings of the ACM Workshop on ML, 2008, Victoria, BC, Canada, 21 September 2008, pp. 3–12. ACM (2008). https://doi.org/10.1145/1411304.1411307

Download references

Author information

Authors and Affiliations

Authors

Corresponding author

Correspondence to Ludovic Henrio .

Editor information

Editors and Affiliations

A Proof of the Bisimulation Theorem (Theorem 2)

A Proof of the Bisimulation Theorem (Theorem 2)

A proof of bisimulation involves two simulation proofs for the same relation. We detail the proof for the first direction: the behaviour of the compiled program is one of the behaviours of the original one. This direction is more complex because of the middle-step semantics and is also more important as it states that the behaviour of the compiled program is a valid one. The other direction is done very similarly with the same arguments as the ones used in the first direction. It however has a different structure as the SOS semantics provides more different cases (but the proof below often needs to distinguish cases according to the current state of the configuration, leading to a similar set of cases overall). We omit the other direction.

Consider , and . Let i be the thread identifier of the thread involved in the reduction (in case of spawn i is the thread that performs the spawn).

We have and for some \(Q_1\) and \(Q'_1\). Additionally, and .

We do a case analysis on the rule used to prove the \(\text {R}_i\) relation; two cases are possible:

  • Continue:

    figure de

    In this case, the top level of continue is a handle thanks to the context \(C_c\). can result from three possible rules (modulo a seq rule at the configuration level and a \(\lambda \)-calculus context rule to reach the reducible statement):

    • HANDLE-RETURN must be of the form (and is inside a handle because of \(C_c\)).

      We have . Its first visible reduction rule must be:

      figure dj

      Where:

      figure dk

      The hidden rules then update the appropriate task in the store and start the run function. Overall, we obtain:

      figure dl

      Where

      figure dm

      Since \(e= C_{rec}[\texttt {handle}{(v)}\{h\}]\), by case analysis on the compilation rules, we must have the source expression \(e' = v'\) be a Fut value with . Then we have:

      figure do

      We then need to establish that the new future map and stores are in relation, i.e., \(\sigma _2, \ell _{threads} \text {R}_e \sigma '_1, F_1\!\left[ f\mapsto v'\right] \).

      We recall the env rule below:

      figure dp

      By inversion on , we obtain three maps \(T_{e,1} \uplus T_{e,2} \uplus T_v\) that ensure the relation. We extend \(T_v\) so that \(T_v[f]\mapsto \mathbb {V}(v)\) to obtain the relation.

      Recall that ; this is sufficient to conclude that

      figure ds
    • HANDLE-STEP must be of the form where can only be reduced by a \(\lambda \)-calculus reduction.

      We have . Its first visible reduction rule must be:

      figure dx

      Where:

      figure dy

      The translation leave \(\lambda \)-calculus terms unchanged, without any hiding, thus there are no follow up hidden rules.

      Overall, we obtain:

      figure dz

      We know that \(\sigma _1, \ell _{threads} ~\text {R}_e~ \sigma '_1, F_1\). By definition, this means that \(\sigma _1 = \sigma '_1 \cup \{ \ell _{threads} \mapsto T \}\) for some map T. By definition of the translation, \(\ell _{threads}\) is not accessible by user code, and thus left unchanged by the reduction on . As such, we have:

      figure eb

      By case analysis on the translation and the \(\lambda \)-calculus reduction rules, \(e'\) must be reduced by the same \(\lambda \)-calculus reduction rule than . Thus:

      figure ed

      This case analysis and by determinism of our \(\lambda \)-calculus, we have . We also have \(\sigma _2, \ell _{threads} \text {R}_e \sigma '_2, F_1\).

      This is sufficient to conclude that

      figure ef
    • HANDLE-EFFECT must be of the form (and is inside a handle because of \(C_c\)). We distinguish by the effect captured:

      • \({\boldsymbol{Async}}({\boldsymbol{job}},t')\). We have . Its first visible reduction rule must be:

        figure ej

        Where:

        figure ek

        By definition of the translation, and because the reduction is possible, the arguments of the Async effect must be a thunk task, and its second argument must be a thread identifier (it can be an expression but this one is entirely evaluated before triggering the effect). This as some consequences on the considered Fut configuration, e.g. \(e'\) is of the form \(\texttt {AsyncAt}(e_0,t)\). Additionally, t is the same on both side as thread identifiers are preserved by the translation (this can be proven by case analysis on the definition of \(\text {R}_i\)).

        The hidden rules apply then update the suspended tasks in the store and start the continue function. The last hidden reduction rule is the beta-reduction that de-thunks the continuation \( \lambda ().(\lambda y.C[y])(\textit{fut}')\) inside the handler of continue and puts \(\textit{fut}'\) back into the invocation context.

        Overall, we obtain:

        figure el

        Where

        figure em

        Since , by case analysis on the compilation rules, we must have the source expression where and by Lemma 1. Note also that the set of future identifiers are the same in the Fut program and in its translation, and thus \(\textit{fut}' = (t,\textit{fresh}())\) is a fresh future in the Fut configuration. Then we have:

        figure er

        We then need to establish that the new future map and stores are in relation, i.e., \(\sigma _2, \ell _{threads} \text {R}_e \sigma '_1, F_1\!\left[ \textit{fut}'\mapsto e'_1\right] \).

        We recall the env rule below:

        figure es

        By inversion on \(\sigma _1,\ell _{threads} ~\text {R}_{e}~ \sigma _1',F_1\), we obtain tree maps \(T_{e,1} \uplus T_{e,2} \uplus T_v\) that ensure the relation. We then extend \(T_{e,1}\) so that to obtain the relation.

        This is sufficient to conclude that

        figure eu
      • \({\boldsymbol{Get}}(f')\). We have . Its first visible reduction rule must be:

        figure ew

        WhereFootnote 6:

        figure ex

        The argument of the Get effect must be a future reference that is totally evaluated for the rule to succeed. If it is not a future the evaluation of poll fails. If it is not fully evaluated, the reduction should first occur inside the argument of the Get effect.

        Details on Poll Reductions. At this point, we look at hidden reductions, which must start in the body of poll. If the future is unresolved, poll loops forever and the medium step reduction diverges. This means either that the future never resolves, and this divergence in Eff simulates a deadlock in Fut; or that we could make reductions in other threads to resolve the deadlock. In the second case, the semantics for Eff would interleave loops in poll and reduction in other threads. Such interleaving is equivalent to triggering the Get event at the end, with a single loop in poll. The current theorem only consider this last interleaving. Overall, if there is a medium step reduction it means that the future is resolved.

        In this case, the future has been resolved, and, by bisimilarity on the stores (\(\text {R}_e\)) we have \(F_1(f')=v\) and \(\sigma _1(\ell _{threads})[f']=v\) for some v. We obtain after a couple of steps of beta-reduction:

        figure ey

        Since \(e= C_{rec}[\texttt {handle}{(C[\texttt {throw}({\textit{Get}(f'))}]}){h}]\), by case analysis on the compilation rules, we have where by Lemma 1. Then we have:

        figure fb

        This is sufficient to conclude that

        figure fc
      • Await\((f')\) . The case when the awaited future is resolved is similar to the case of the Get effect just above. We only detail the proof in case the future is still unresolved.

        We have . Its first visible reduction rule must be:

        figure fe

        Where:

        figure ff

        Like in the Get case, the argument of the Await effect must be a future reference that is totally evaluated for the rule to succeed.

        When the future is unresolved, \(\ell _{threads}[f']\) is not a value (it is not mapped or mapped to a \(\mathbb {C}{}\)). By definition of \(\texttt {R}_e\) we necessarily have: \(\not \exists v.\, (f' \mapsto v)\in F_1 \). Then a few hidden beta reduction steps lead to the following configuration:

        figure fg

        Where

        figure fh

        Since \(e= C_{rec}[\texttt {handle}{(C[\texttt {throw}({\textit{Await}(f'))}]}){h}]\), by case analysis on the compilation rules, we have where by Lemma 1. Thus on the Fut side, we have:

        figure fk

        We easily obtain that by expanding the environment \(T_{e,2}\) in the env rule.

        With the arguments above and the case run of we conclude:

        figure fn
      • \({\boldsymbol{Spawn}}()\). We have . Its first visible reduction rule must be:

        figure fp

        With: \(C_{rec}\) the “let ... rec” context of the continue handler inside \(C_c\), h the effect handlers defined in Continue, additionally:

        figure fq

        The first hidden rule applied is

        figure fr

        Where \(e_2= C_2[\texttt {spawn}({\textit{run}})]\). This is followed by steps of beta reduction to reduce the \(\texttt{let}\ t' =\ldots \) construct, trigger continue, pass the associated \(\textit{tid}\) and de-thunk the \(\lambda ().\lambda y.C[y](\textit{tid})\) inside continue. We obtain the following configuration

        figure fs

        Finally, by a step of beta reduction in the thread \(\textit{tid}\) we obtain the right evaluation context \(C_r\)

        figure ft

        This configuration is not reducible by a hidden transition. Thus

        figure fu

        By case analysis on the terms involved in we have where by Lemma 1. We then have:

        figure fy

        Note that by definition of the set of used thread identifiers is the same in both configurations, wo we can take the same fresh \(\textit{tid}\). Note also that the store and the future map are unchanged. Comparing thread by thread, we can directly apply rule run and rule cont for the two processes \(\textit{tid}\) and i, which leads to the conclusion:

        figure ga
  • Run:

    figure gb

    The only first applicable rule is the pop operation reduction that picks a new available thread:

    figure gc

    Note that pop ensures that \(f_2\) is of the form \(f_2=(i, \textit{lf})\). Using only reductions in the thread i and such that: Footnote 7 by definition of \(\text {R}_i\) and Footnote 8 by definition of pop. Note that the last step of reduction is inside continue and de-thunks the new task ( )Footnote 9. We additionally have:

    figure gh

    From the points above, we obtain (with \(f_2=(i, \textit{lf})\)):

    figure gi

    Note that by construction of the equivalence on stores (Fig. 16). Finally (the equivalence on the store can be trivially checked):

    figure gk

    This immediately concludes by adding the other threads (in \(Q_1\) and \(Q'_1\)) and obtaining the relation on the obtained configurations.    \(\square \)

Rights and permissions

Reprints and permissions

Copyright information

© 2024 The Author(s), under exclusive license to Springer Nature Switzerland AG

About this chapter

Check for updates. Verify currency and authenticity via CrossMark

Cite this chapter

Andrieux, M., Henrio, L., Radanne, G. (2024). Active Objects Based on Algebraic Effects. In: de Boer, F., Damiani, F., Hähnle, R., Broch Johnsen, E., Kamburjan, E. (eds) Active Object Languages: Current Research Trends. Lecture Notes in Computer Science, vol 14360. Springer, Cham. https://doi.org/10.1007/978-3-031-51060-1_1

Download citation

  • DOI: https://doi.org/10.1007/978-3-031-51060-1_1

  • Published:

  • Publisher Name: Springer, Cham

  • Print ISBN: 978-3-031-51059-5

  • Online ISBN: 978-3-031-51060-1

  • eBook Packages: Computer ScienceComputer Science (R0)

Publish with us

Policies and ethics