|
Suggestion: ephemeron-case
Daphne Preston-Kendal
(04 Feb 2025 10:08 UTC)
|
||
|
Re: Suggestion: ephemeron-case
John Cowan
(04 Feb 2025 11:35 UTC)
|
||
|
Re: Suggestion: ephemeron-case
Vincent Manis (he/him)
(04 Feb 2025 19:38 UTC)
|
||
|
Re: Suggestion: ephemeron-case
Marc Nieper-Wißkirchen
(05 Feb 2025 15:12 UTC)
|
||
|
Re: Suggestion: ephemeron-case
Daphne Preston-Kendal
(05 Feb 2025 15:30 UTC)
|
||
|
Re: Suggestion: ephemeron-case
Marc Nieper-Wißkirchen
(05 Feb 2025 18:04 UTC)
|
||
|
Re: Suggestion: ephemeron-case
Daphne Preston-Kendal
(05 Feb 2025 18:16 UTC)
|
||
|
(missing)
|
||
|
Fwd: Suggestion: ephemeron-case
Marc Nieper-Wißkirchen
(16 Mar 2025 13:19 UTC)
|
||
|
Re: Suggestion: ephemeron-case
Marc Nieper-Wißkirchen
(12 May 2025 11:51 UTC)
|
||
|
Re: Suggestion: ephemeron-case
Arthur A. Gleckler
(10 Jun 2025 23:16 UTC)
|
||
|
Re: Suggestion: ephemeron-case
Daphne Preston-Kendal
(03 Aug 2025 09:38 UTC)
|
||
|
Re: Suggestion: ephemeron-case
Marc Nieper-Wißkirchen
(03 Aug 2025 15:29 UTC)
|
||
|
Re: Suggestion: ephemeron-case
Marc Nieper-Wißkirchen
(03 Aug 2025 15:30 UTC)
|
||
|
Re: Suggestion: ephemeron-case
Daphne Preston-Kendal
(09 Oct 2025 12:34 UTC)
|
||
|
Re: Suggestion: ephemeron-case
Marc Nieper-Wißkirchen
(09 Oct 2025 13:24 UTC)
|
||
|
Usefulness of reference-barrier
Daphne Preston-Kendal
(12 Oct 2025 20:16 UTC)
|
||
|
Re: Usefulness of reference-barrier
Marc Nieper-Wißkirchen
(13 Oct 2025 05:58 UTC)
|
||
|
Re: Usefulness of reference-barrier Marc Nieper-Wißkirchen (13 Oct 2025 07:21 UTC)
|
||
|
Re: Usefulness of reference-barrier
Marc Nieper-Wißkirchen
(13 Oct 2025 11:17 UTC)
|
||
|
Re: Usefulness of reference-barrier
Marc Nieper-Wißkirchen
(22 Oct 2025 07:18 UTC)
|
||
|
Re: Usefulness of reference-barrier
Daphne Preston-Kendal
(30 Oct 2025 22:46 UTC)
|
||
|
Re: Usefulness of reference-barrier
Marc Nieper-Wißkirchen
(31 Oct 2025 07:50 UTC)
|
||
|
Re: Usefulness of reference-barrier
Daphne Preston-Kendal
(30 Oct 2025 23:03 UTC)
|
||
|
Re: Usefulness of reference-barrier
Marc Nieper-Wißkirchen
(31 Oct 2025 08:02 UTC)
|
||
|
Re: Usefulness of reference-barrier
Marc Nieper-Wißkirchen
(04 Nov 2025 18:57 UTC)
|
||
PS Regarding Haskell, please see the following quote from the page you
gave the link to:
"WARNING: weak pointers to ordinary non-primitive Haskell types are
particularly fragile, because the compiler is free to optimise away or
duplicate the underlying data structure. Therefore attempting to place
a finalizer on an ordinary Haskell type may well result in the
finalizer running earlier than you expected. This is not a problem for
caches and memo tables where early finalization is benign.
Finalizers can be used reliably for types that are created explicitly
and have identity, such as IORef, MVar, and TVar. However, to place a
finalizer on one of these types, you should use the specific operation
provided for that type, e.g. mkWeakIORef, mkWeakMVar and mkWeakTVar
respectively. These operations attach the finalizer to the primitive
object inside the box (e.g. MutVar# in the case of IORef), because
attaching the finalizer to the box itself fails when the outer box is
optimised away by the compiler."
In other words, Haskell is very much in line with SRFI 254. If you use
ephemerons to implement caches or memo tables, you don't need SRFI
254's reference-barrier either because early broken ephemerons do not
affect the correctness of caches or memo tables.
Similar to ephemeron-ref from my previous post, one can add
convenience syntax that corresponds to the "reliable" set of types of
Haskell, similar to what you proposed with ephemeron-case:
(define-syntax define-synchronized
(lambda (stx)
(syntax-case stx ()
((_ name val)
(identifier? #'name)
#'(begin
(define var val)
(define-syntax name
(identifier-syntax
(_ (begin (reference-barrier var) var))
((set! _ expr) (begin (set! var expr)
(reference-barrier var))))))))))
(define-synchronized v (vector 1 2))
(vector? v) ; will keep V alive.
Am Mo., 13. Okt. 2025 um 07:58 Uhr schrieb Marc Nieper-Wißkirchen
<xxxxxx@gmail.com>:
>
> Can you state precisely what you mean by forbidden certain reorderings?
>
> Allowing or preventing reordering an expression makes only sense with
> respect to other expressions. For example, reordering of expressions
> that write to a port is forbidden with respect to other procedures
> writing to the same port. Now, if we declare that reads or writes to
> the store must not be reordered around some expression (like a call to
> ephemeron-key), this will be extremely costly (because, conceptually,
> every variable reference is a read or write to the store) and is not
> what compilers do in practice. The following example if for Chez:
>
> > (expand/optimize '
> (lambda (f g)
> (let ((v (vector 1 2)))
> (f v)
> (let ((w (g v)))
> (boolean=? (vector? v) (vector? w))))))
> (lambda (f g)
> (let ([v (#2%vector 1 2)])
> (f v)
> (#3%boolean=? #t (#2%vector? (g v)))))
>
> The argument F can be thought of as a procedure storing V as a key to
> some ephemeron (e.g., as part of some weak table). The argument G can
> be thought of as a procedure returning the previously stored key (if
> still stored) or #f, otherwise. In the source code, the location of V
> in the store is accessed after G is called, so with naive semantics
> "do not reorder anything", the value of V is still alive after the
> call to G, so G should return the key.
>
> In the optimized version, however, cp0 replaces the constant
> expression involving V with the constant (#t in this case). If a
> garbage collection is going on during the evaluation of the call to F
> or G, G will no longer return the previously stored key.
>
> This example also demonstrates that "reordering" is not some fancy
> optimisation pass that can easily be turned on or off, but the basis
> of a number of undisputed basic optimisations.
>
> The reason why code seems to work without "reference-barrier" is that
> failure due to leaving it out is even more sporadic and subtle than
> failure due to missing synchronisation in concurrent code (see C's
> <stdatomic.h>, for example).
>
> Now, ephemerons are supposed to be a relatively low-level interface on
> which library writers can build high-level data structures. Calls to
> reference-barrier will usually be hidden in the implementation. See
> the example code in the new draft, where the documentation for
> weakmap-contains? and weakmap-ref clearly says that the key will be
> kept alive.
>
> Likewise, convenience procedures like
>
> ephemeron-ref EPH KEY DEFAULT
>
> defined by
>
> (define (ephemeron-ref eph key default)
> (let ((val (if (eq? (ephemeron-key eph) key) (ephemeron-value eph) default)))
> (reference-barrier key)
> val))
>
> are possible (and should/could go into some convenience library built
> on top of the primitives in SRFI 254).
>
> Taylor Campbell posted more on the SRFI 124 mailing list; he also says
> that the low-level interface to ephemerons won't be reliable without
> reference-barrier, expressed by a simple "can't":
> https://srfi-email.schemers.org/srfi-124/msg/4182299/
>
> JavaScript has solved the problem differently (and thus does not need
> reference-barrier). Quoting from MDN:
>
> "If your code has just created a WeakRef for a target object, or has
> gotten a target object from a WeakRef's deref method, that target
> object will not be reclaimed until the end of the current JavaScript
> job (including any promise reaction jobs that run at the end of a
> script job). That is, you can only "see" an object get reclaimed
> between turns of the event loop. This is primarily to avoid making the
> behavior of any given JavaScript engine's garbage collector apparent
> in code — because if it were, people would write code relying on that
> behavior, which would break when the garbage collector's behavior
> changed. (Garbage collection is a hard problem; JavaScript engine
> implementers are constantly refining and improving how it works.)"
>
> In other words, there are implicit reference barriers at the end of
> each job, meaning that reclaiming weakly-held objects is coarse. This
> is less of a problem in JavaScript because jobs are supposed to be
> short-running. This does not apply to Scheme.
>
> Marc
>
> Am So., 12. Okt. 2025 um 22:16 Uhr schrieb Daphne Preston-Kendal
> <xxxxxx@nonceword.org>:
> >
> > On 9 Oct 2025, at 15:24, Marc Nieper-Wißkirchen <xxxxxx@gmail.com> wrote:
> >
> > > Thank you for the example code. Unfortunately, the suggested
> > > definition of "ephemeron-case" is useless.
> >
> > I’d like to take this conversation in a slightly different direction.
> >
> > Can you offer any demonstration at all – from any real language runtime you can think of, Scheme or non-Scheme – that reference-barrier is actually needed; that compilers without it would break things in the way you say they could when dereferencing weak pointers; that compilers which would do the ‘optimization’ you invented reference-barrier to productively frustrate would not be completely broken by design?
> >
> > I cannot find any.
> >
> > Chez Scheme added keep-live in version 10, but it had ephemerons and other weak references long before. Its documentation suggests the purpose of keep-live is related to the ‘immobile objects’ feature, not to the re-ordering optimization you are concerned about.
> >
> > MIT Scheme seems to have added reference-barrier purely because of SRFI 124. It also had ephemerons and weak pairs before. Riastradh suggested reference-barrier: his rationale appears to have been entirely different, to do with an implementation where broken ephemerons were replaced by #f. <https://srfi-email.schemers.org/srfi-124/msg/2905901/>
> >
> > Outside of the Scheme world, I am unable to find any language or implementation of any language which has anything like reference-barrier. JavaScript’s ephemeron tables (WeakMap) and weak sets (WeakSet) and weak boxes (WeakRef) all have no such concept. OCaml, in runtime semantics a close match to Scheme, doesn’t have it. <https://ocaml.org/manual/5.3/api/Ephemeron.html> Even Haskell, which due to its lazy evaluation is extremely reordering-happy in its implementation, does not appear to have an equivalent of the reference-barrier. <https://hackage.haskell.org/package/base-4.21.0.0/docs/System-Mem-Weak.html>
> >
> > I haven’t surveyed Scheme implementers (well, except Alex Shinn who made his feelings known well enough when it came up in another context), but I suspect this whole idea of yours is premature pessimization. Compilers are quite intelligent enough to realize that ephemeron-key and ephemeron-datum themselves are procedures that can’t safely be re-ordered around – and this is not a ‘sufficiently smart compiler’ argument, because a truly dumb compiler wouldn’t have an issue here either, since the problem is that you’re arguing a compiler might attempt to be smart but do something wrong. In reality, a compiler which tries to be smart in that way would simply be broken, and the way it would be broken would be the same as if it allowed re-ordering set! or write or any other side-effectual procedure so the side-effects happen in the wrong order. They already have mechanisms that tell them they can’t do that, and if they can apply those mechanisms to reference-barrier, they can just as well apply them to the actual source of the reference instead.
> >
> > [Not speaking as chair but as an individual WG2 member:] If reference-barrier stays in the SRFI up to finalization and thus remains a candidate for R7RS large, I will want a comprehensive survey of implementers on this question before we clutter the Scheme report with it.
> >
> > Best wishes
> >
> >
> > Daphne
> >