<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    Ooh, that's decidedly nasty. I suppose I should have read the docs
    of the primop before drawing conclusions, but then, being lazy is
    part of the deal here... ;)<br>
    <br>
    Thanks for the explanation!<br>
    <br>
    - Tom<br>
    <br>
    <div class="moz-cite-prefix">On 10/03/2023 15:05, David Feuer wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CAMgWh9v7gaDmqJ+MaU3=qR-C5OoU7z7bP-3ju3TF7niXuku2aw@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <div dir="auto">
        <div>Unfortunately not. The type the type checker is told for
          the `atomicModifyMutVar2#` primop is a lie (too permissive).
          The type documented in its Haddocks is also a lie (too
          restrictive). Its most precise type, as I understand it, is
          (translating away the unboxed stuff and the internal I/O
          representation)
          <div dir="auto"><br>
          </div>
          <div dir="auto">atomicModifyMutVar2</div>
          <div dir="auto">  :: IORef a<br>
          </div>
          <div dir="auto">  -> (a -> t)</div>
          <div dir="auto">  -> IO (a, t)</div>
          <div dir="auto">-- with the condition that `t` is a record
            whose first field that is represented by a pointer (what we
            call BoxedRep) has a type with the same memory
            representation as `a`.</div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">While it would be possible to express that
            fairly precisely using the Generics approach, I think it's
            too hard to think about "the first pointer field", and the
            "same memory representation" bit mucks with type inference.
            So I restricted it a little to "the first field, which must
            be a pointer", and "with type `a`".</div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">There's a sort of "hidden unsafeCoerce" in the
            primop call, where we know that the "selector thunk" it
            builds (a thunk applying a record selector, in this case
            fst) will extract the field we want out of what we give it.
            The type checker is clueless and just accepts whatever.</div>
          <br>
          <br>
          <div class="gmail_quote">
            <div dir="ltr" class="gmail_attr">On Fri, Mar 10, 2023, 4:09
              AM Tom Smeding <<a href="mailto:x@tomsmeding.com"
                moz-do-not-send="true" class="moz-txt-link-freetext">x@tomsmeding.com</a>>
              wrote:<br>
            </div>
            <blockquote class="gmail_quote" style="margin:0 0 0
              .8ex;border-left:1px #ccc solid;padding-left:1ex">
              <div> I'm not the person to ask :) Maybe someone else on
                the list can chip in here.<br>
                <br>
                Another question if you don't mind (I'm learning here):
                you say below that in <a
                  id="m_-4214265619866510319v:atomicModifyIORef2Native"
                  rel="noreferrer" moz-do-not-send="true">atomicModifyIORef2Native,</a>
                you rely on heap object layout to unsafeCoerce between a
                pair and any object with an interesting value in the
                first field. But looking at the source [1], it seems you
                only do this for base < 4.13, i.e. GHC < 8.8.4.
                That's been a while.<br>
                <br>
                Is it true that for GHCs since 8.8.4 you can just use a
                primop to do what you want directly, without the magic
                Generic stuff? If so, perhaps you can even drop the
                Generic constraints for high enough GHC versions (by
                extending the scope of the CPP slightly)? 8.6.5 is still
                popular, but simultaneously a whole bunch of
                applications don't care about GHCs <9 anymore.<br>
                <br>
                - Tom<br>
                <br>
                [1]:
                <a
href="https://hackage.haskell.org/package/atomic-modify-general-0.1.0.0/docs/src/Data.IORef.AtomicModify.Generic.html#atomicModifyIORef2Native"
                  target="_blank" rel="noreferrer"
                  moz-do-not-send="true" class="moz-txt-link-freetext">https://hackage.haskell.org/package/atomic-modify-general-0.1.0.0/docs/src/Data.IORef.AtomicModify.Generic.html#atomicModifyIORef2Native</a><br>
                <br>
                <div>On 10/03/2023 09:45, David Feuer wrote:<br>
                </div>
                <blockquote type="cite">
                  <div dir="auto">Whoops! Thanks for pointing that out.
                    I'll fix it and push new docs. There's not much
                    magic in that part of the code itself; the nasty
                    magic is knowing that the first pointer in any
                    record is in the same position in its heap object as
                    the first component of a pair. Speaking of which, do
                    you have any idea if it'll work for non-record types
                    whose constructors all have the same first field?
                    I'm guessing yes, but I haven't experimented yet.</div>
                  <br>
                  <div class="gmail_quote">
                    <div dir="ltr" class="gmail_attr">On Fri, Mar 10,
                      2023, 3:27 AM Tom Smeding <<a
                        href="mailto:x@tomsmeding.com" target="_blank"
                        rel="noreferrer" moz-do-not-send="true"
                        class="moz-txt-link-freetext">x@tomsmeding.com</a>>
                      wrote:<br>
                    </div>
                    <blockquote class="gmail_quote" style="margin:0 0 0
                      .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi
                      David,<br>
                      <br>
                      Fancy stuffs!<br>
                      <br>
                      Wondering how much magic was going on in
                      implementing this, I saw that <br>
                      atomicModifyIORef2Native misses the haddock marker
                      '|' in the source; <br>
                      thus your extensive doc comment doesn't show up on
                      hackage.<br>
                      <br>
                      Cheers,<br>
                      Tom<br>
                      <br>
                      On 10/03/2023 03:01, David Feuer wrote:<br>
                      > I just put together a new package,
                      atomic-modify-general, for<br>
                      > generalizations of the `atomicModifyIORef`
                      operation. In particular:<br>
                      ><br>
                      > 1. Versions that allow a result of an
                      arbitrary type (not necessarily<br>
                      > a pair), where the caller passes in an
                      extraction function. These work<br>
                      > with `Array` and `SmallArray` from
                      `primitive` as well as `IORef`.<br>
                      > 2. A version that works with record types
                      (not just pairs) whose first<br>
                      > field is the new value to install in the
                      `IORef`. This uses<br>
                      > implementation details of the
                      `atomicModifyMutVar#` primop as well as<br>
                      > GHC's heap object layout to achieve better
                      performance.<br>
                      ><br>
                      > Please try it out and let me know how it
                      goes, and what extras you may want!<br>
                      ><br>
                      > Hackage: <a
                        href="https://hackage.haskell.org/package/atomic-modify-general-0.1.0.0"
                        rel="noreferrer noreferrer noreferrer"
                        target="_blank" moz-do-not-send="true"
                        class="moz-txt-link-freetext">https://hackage.haskell.org/package/atomic-modify-general-0.1.0.0</a><br>
                      >
                      _______________________________________________<br>
                      > Haskell-Cafe mailing list<br>
                      > To (un)subscribe, modify options or view
                      archives go to:<br>
                      > <a
                        href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe"
                        rel="noreferrer noreferrer noreferrer"
                        target="_blank" moz-do-not-send="true"
                        class="moz-txt-link-freetext">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
                      > Only members subscribed via the mailman list
                      are allowed to post.<br>
                      <br>
                      _______________________________________________<br>
                      Haskell-Cafe mailing list<br>
                      To (un)subscribe, modify options or view archives
                      go to:<br>
                      <a
                        href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe"
                        rel="noreferrer noreferrer noreferrer"
                        target="_blank" moz-do-not-send="true"
                        class="moz-txt-link-freetext">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
                      Only members subscribed via the mailman list are
                      allowed to post.</blockquote>
                  </div>
                </blockquote>
                <br>
              </div>
            </blockquote>
          </div>
        </div>
      </div>
    </blockquote>
    <br>
  </body>
</html>