atomicModifyMutVar2

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

atomicModifyMutVar2

GHC - devs mailing list

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

 

Thanks

Simon

 

primop  AtomicModifyMutVar2Op "atomicModifyMutVar2#" GenPrimOp

   MutVar# s a -> (a -> c) -> State# s -> (# State# s, a, c #)

   { Modify the contents of a {\tt MutVar\#}, returning the previous

     contents and the result of applying the given function to the

     previous contents. Note that this isn't strictly

     speaking the correct type for this function; it should really be

     {\tt MutVar\# s a -> (a -> (a,b)) -> State\# s -> (\# State\# s, a, (a, b) \#)},

     but we don't know about pairs here. }

   with

   out_of_line = True

   has_side_effects = True

   can_fail         = True


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: atomicModifyMutVar2

David Feuer
On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <[hidden email]> wrote:

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)


Close, but not quite. The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Yes, that sounds right.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Yes, it's somewhat significant. You actually can use Unit with the new primop (it's a tuple of arity 1), so that option is free. But using a pair gets you a bit more: you can build a thunk that's *shared* between the value installed in the MutVar and the one returned to the outside. Consider

atomicModifyMutVar2# mv $ \a ->

  let foo = expensive_computation a

  in ([3,foo], foo)

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

That whole regime came before my time, but since we win a bit by *not* fixing it, o wouldn't jump on it too quick.



_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

RE: atomicModifyMutVar2

GHC - devs mailing list

The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

I think that is 100.0% undocumented, in the code, or in the proposal.  Are you sure this is a settled consensus among the interested parties?

 

Adopting it would impose new invariants on the representation of values in GHC that I am deeply reluctant to impose.  I would much much prefer to stick with the pair that is (somewhat) documented.

 

About pair vs Unit, yes, I can see (just) your point about why a pair might be useful.  Here’s a better example:

 

Suppose mv :: MutVar# Int

 

atomicModifyMutVar2# mv $ \a ->

  let foo = f a

  in (g foo, foo)

 

Now, if f is expensive, and g is not invertible, then sharing foo might be useful.  It’s hard to think of a credible example, though.  Regardless, we should document it.

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 11 October 2019 17:03
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <[hidden email]> wrote:

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)

 

Close, but not quite. The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Yes, that sounds right.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Yes, it's somewhat significant. You actually can use Unit with the new primop (it's a tuple of arity 1), so that option is free. But using a pair gets you a bit more: you can build a thunk that's *shared* between the value installed in the MutVar and the one returned to the outside. Consider

 

atomicModifyMutVar2# mv $ \a ->

  let foo = expensive_computation a

  in ([3,foo], foo)

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

That whole regime came before my time, but since we win a bit by *not* fixing it, o wouldn't jump on it too quick.

 


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: atomicModifyMutVar2

Carter Schonwald
that additional representation invariant requirement is why i ultimately chose not to include the user space version of davids work in primitive 


theres some really clever ideas, but i couldnt tease apart a natural example of where i'd want to use it

On Fri, Oct 11, 2019 at 12:56 PM Simon Peyton Jones via ghc-devs <[hidden email]> wrote:

The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

I think that is 100.0% undocumented, in the code, or in the proposal.  Are you sure this is a settled consensus among the interested parties?

 

Adopting it would impose new invariants on the representation of values in GHC that I am deeply reluctant to impose.  I would much much prefer to stick with the pair that is (somewhat) documented.

 

About pair vs Unit, yes, I can see (just) your point about why a pair might be useful.  Here’s a better example:

 

Suppose mv :: MutVar# Int

 

atomicModifyMutVar2# mv $ \a ->

  let foo = f a

  in (g foo, foo)

 

Now, if f is expensive, and g is not invertible, then sharing foo might be useful.  It’s hard to think of a credible example, though.  Regardless, we should document it.

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 11 October 2019 17:03
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <[hidden email]> wrote:

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)

 

Close, but not quite. The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Yes, that sounds right.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Yes, it's somewhat significant. You actually can use Unit with the new primop (it's a tuple of arity 1), so that option is free. But using a pair gets you a bit more: you can build a thunk that's *shared* between the value installed in the MutVar and the one returned to the outside. Consider

 

atomicModifyMutVar2# mv $ \a ->

  let foo = expensive_computation a

  in ([3,foo], foo)

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

That whole regime came before my time, but since we win a bit by *not* fixing it, o wouldn't jump on it too quick.

 

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

RE: atomicModifyMutVar2

GHC - devs mailing list
In reply to this post by GHC - devs mailing list

David,

 

Wait!  It gets worse!

 

Question 4

 

As I understand it, the idea in the proposal is that you can force the pair that comes back from the primop, and that helps you cure a space leak.  Thus

 

case atomicModifyMutVar2# mv f s of

   (# s’, old, pr #) -> pr `seq`  (# s’, () #)

 

But it’s extremely easy to write calls that complete defeat such a strategy.  Your examples and mine below both have this property. Suppose f is

(\x. let v = expensive x in (v,v))

Well, forcing that pair will do nothing at all!  It certainly won’t force v!   You should probably write

(\x. let v = expensive x in v `seq` (v,v))

or something like that.

 

Is this right?   At least this should be documented super-clearly.

 

Simon

 

From: ghc-devs <[hidden email]> On Behalf Of Simon Peyton Jones via ghc-devs
Sent: 11 October 2019 17:56
To: David Feuer <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: RE: atomicModifyMutVar2

 

The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

I think that is 100.0% undocumented, in the code, or in the proposal.  Are you sure this is a settled consensus among the interested parties?

 

Adopting it would impose new invariants on the representation of values in GHC that I am deeply reluctant to impose.  I would much much prefer to stick with the pair that is (somewhat) documented.

 

About pair vs Unit, yes, I can see (just) your point about why a pair might be useful.  Here’s a better example:

 

Suppose mv :: MutVar# Int

 

atomicModifyMutVar2# mv $ \a ->

  let foo = f a

  in (g foo, foo)

 

Now, if f is expensive, and g is not invertible, then sharing foo might be useful.  It’s hard to think of a credible example, though.  Regardless, we should document it.

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 11 October 2019 17:03
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <[hidden email]> wrote:

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)

 

Close, but not quite. The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Yes, that sounds right.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Yes, it's somewhat significant. You actually can use Unit with the new primop (it's a tuple of arity 1), so that option is free. But using a pair gets you a bit more: you can build a thunk that's *shared* between the value installed in the MutVar and the one returned to the outside. Consider

 

atomicModifyMutVar2# mv $ \a ->

  let foo = expensive_computation a

  in ([3,foo], foo)

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

That whole regime came before my time, but since we win a bit by *not* fixing it, o wouldn't jump on it too quick.

 


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: atomicModifyMutVar2

David Feuer
In reply to this post by GHC - devs mailing list
I don't remember what documentation, if any, it has. You're right that taking advantage of it is potentially risky. Here's what I think we really want:

atomicModifyMutVarQ# :: MutVar# s a -> (q -> a) -> (a -> q)  -> State# s -> (# State# s, a, q #)

where there's a special rule that (q -> a) is "obviously" a selector that selects a pointer.

On Fri, Oct 11, 2019, 12:56 PM Simon Peyton Jones <[hidden email]> wrote:

The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

I think that is 100.0% undocumented, in the code, or in the proposal.  Are you sure this is a settled consensus among the interested parties?

 

Adopting it would impose new invariants on the representation of values in GHC that I am deeply reluctant to impose.  I would much much prefer to stick with the pair that is (somewhat) documented.

 

About pair vs Unit, yes, I can see (just) your point about why a pair might be useful.  Here’s a better example:

 

Suppose mv :: MutVar# Int

 

atomicModifyMutVar2# mv $ \a ->

  let foo = f a

  in (g foo, foo)

 

Now, if f is expensive, and g is not invertible, then sharing foo might be useful.  It’s hard to think of a credible example, though.  Regardless, we should document it.

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 11 October 2019 17:03
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <[hidden email]> wrote:

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)

 

Close, but not quite. The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Yes, that sounds right.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Yes, it's somewhat significant. You actually can use Unit with the new primop (it's a tuple of arity 1), so that option is free. But using a pair gets you a bit more: you can build a thunk that's *shared* between the value installed in the MutVar and the one returned to the outside. Consider

 

atomicModifyMutVar2# mv $ \a ->

  let foo = expensive_computation a

  in ([3,foo], foo)

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

That whole regime came before my time, but since we win a bit by *not* fixing it, o wouldn't jump on it too quick.

 


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: atomicModifyMutVar2

David Feuer
Actually, maybe we can do better! We don't inherently need the function to be a selector. But to make it more general, we'll need to take some care to make sure to produce good code when it *is* a selector.

On Fri, Oct 11, 2019, 6:59 PM David Feuer <[hidden email]> wrote:
I don't remember what documentation, if any, it has. You're right that taking advantage of it is potentially risky. Here's what I think we really want:

atomicModifyMutVarQ# :: MutVar# s a -> (q -> a) -> (a -> q)  -> State# s -> (# State# s, a, q #)

where there's a special rule that (q -> a) is "obviously" a selector that selects a pointer.

On Fri, Oct 11, 2019, 12:56 PM Simon Peyton Jones <[hidden email]> wrote:

The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

I think that is 100.0% undocumented, in the code, or in the proposal.  Are you sure this is a settled consensus among the interested parties?

 

Adopting it would impose new invariants on the representation of values in GHC that I am deeply reluctant to impose.  I would much much prefer to stick with the pair that is (somewhat) documented.

 

About pair vs Unit, yes, I can see (just) your point about why a pair might be useful.  Here’s a better example:

 

Suppose mv :: MutVar# Int

 

atomicModifyMutVar2# mv $ \a ->

  let foo = f a

  in (g foo, foo)

 

Now, if f is expensive, and g is not invertible, then sharing foo might be useful.  It’s hard to think of a credible example, though.  Regardless, we should document it.

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 11 October 2019 17:03
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <[hidden email]> wrote:

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)

 

Close, but not quite. The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Yes, that sounds right.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Yes, it's somewhat significant. You actually can use Unit with the new primop (it's a tuple of arity 1), so that option is free. But using a pair gets you a bit more: you can build a thunk that's *shared* between the value installed in the MutVar and the one returned to the outside. Consider

 

atomicModifyMutVar2# mv $ \a ->

  let foo = expensive_computation a

  in ([3,foo], foo)

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

That whole regime came before my time, but since we win a bit by *not* fixing it, o wouldn't jump on it too quick.

 


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

RE: atomicModifyMutVar2

GHC - devs mailing list
In reply to this post by David Feuer

OK.   I propose:

 

  • To give atomicModieyMutVarOf# its proper type, with a  pair, as in the proposal.
  • To do that I’ll fiddle with genprimopcode, to allow it to parse tuples as well as unboxed tuples; not hard.
  • This would disallow all this stuff about “any type that has a first field looking like a”, restricting to pairs alone.  This didn’t form part of the proposal, and was never documented.
  • Add a bit more clarity to the documentation, so it’d clear what must be forced.

 

Any objections?

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 12 October 2019 00:00
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

I don't remember what documentation, if any, it has. You're right that taking advantage of it is potentially risky. Here's what I think we really want:

 

atomicModifyMutVarQ# :: MutVar# s a -> (q -> a) -> (a -> q)  -> State# s -> (# State# s, a, q #)

 

where there's a special rule that (q -> a) is "obviously" a selector that selects a pointer.

On Fri, Oct 11, 2019, 12:56 PM Simon Peyton Jones <[hidden email]> wrote:

The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

I think that is 100.0% undocumented, in the code, or in the proposal.  Are you sure this is a settled consensus among the interested parties?

 

Adopting it would impose new invariants on the representation of values in GHC that I am deeply reluctant to impose.  I would much much prefer to stick with the pair that is (somewhat) documented.

 

About pair vs Unit, yes, I can see (just) your point about why a pair might be useful.  Here’s a better example:

 

Suppose mv :: MutVar# Int

 

atomicModifyMutVar2# mv $ \a ->

  let foo = f a

  in (g foo, foo)

 

Now, if f is expensive, and g is not invertible, then sharing foo might be useful.  It’s hard to think of a credible example, though.  Regardless, we should document it.

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 11 October 2019 17:03
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <[hidden email]> wrote:

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)

 

Close, but not quite. The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Yes, that sounds right.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Yes, it's somewhat significant. You actually can use Unit with the new primop (it's a tuple of arity 1), so that option is free. But using a pair gets you a bit more: you can build a thunk that's *shared* between the value installed in the MutVar and the one returned to the outside. Consider

 

atomicModifyMutVar2# mv $ \a ->

  let foo = expensive_computation a

  in ([3,foo], foo)

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

That whole regime came before my time, but since we win a bit by *not* fixing it, o wouldn't jump on it too quick.

 


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: atomicModifyMutVar2

Carter Schonwald
sounds lovely! (the current type is certainly strange and not very sound :) )

On Mon, Oct 14, 2019 at 6:35 PM Simon Peyton Jones via ghc-devs <[hidden email]> wrote:

OK.   I propose:

 

  • To give atomicModieyMutVarOf# its proper type, with a  pair, as in the proposal.
  • To do that I’ll fiddle with genprimopcode, to allow it to parse tuples as well as unboxed tuples; not hard.
  • This would disallow all this stuff about “any type that has a first field looking like a”, restricting to pairs alone.  This didn’t form part of the proposal, and was never documented.
  • Add a bit more clarity to the documentation, so it’d clear what must be forced.

 

Any objections?

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 12 October 2019 00:00
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

I don't remember what documentation, if any, it has. You're right that taking advantage of it is potentially risky. Here's what I think we really want:

 

atomicModifyMutVarQ# :: MutVar# s a -> (q -> a) -> (a -> q)  -> State# s -> (# State# s, a, q #)

 

where there's a special rule that (q -> a) is "obviously" a selector that selects a pointer.

On Fri, Oct 11, 2019, 12:56 PM Simon Peyton Jones <[hidden email]> wrote:

The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

I think that is 100.0% undocumented, in the code, or in the proposal.  Are you sure this is a settled consensus among the interested parties?

 

Adopting it would impose new invariants on the representation of values in GHC that I am deeply reluctant to impose.  I would much much prefer to stick with the pair that is (somewhat) documented.

 

About pair vs Unit, yes, I can see (just) your point about why a pair might be useful.  Here’s a better example:

 

Suppose mv :: MutVar# Int

 

atomicModifyMutVar2# mv $ \a ->

  let foo = f a

  in (g foo, foo)

 

Now, if f is expensive, and g is not invertible, then sharing foo might be useful.  It’s hard to think of a credible example, though.  Regardless, we should document it.

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 11 October 2019 17:03
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <[hidden email]> wrote:

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)

 

Close, but not quite. The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Yes, that sounds right.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Yes, it's somewhat significant. You actually can use Unit with the new primop (it's a tuple of arity 1), so that option is free. But using a pair gets you a bit more: you can build a thunk that's *shared* between the value installed in the MutVar and the one returned to the outside. Consider

 

atomicModifyMutVar2# mv $ \a ->

  let foo = expensive_computation a

  in ([3,foo], foo)

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

That whole regime came before my time, but since we win a bit by *not* fixing it, o wouldn't jump on it too quick.

 

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: atomicModifyMutVar2

David Feuer
In reply to this post by GHC - devs mailing list
What do you think about the version that takes a function as an argument, and is optimized for the case where that's a selector? That really feels like the platonic ideal here.

On Mon, Oct 14, 2019, 6:35 PM Simon Peyton Jones <[hidden email]> wrote:

OK.   I propose:

 

  • To give atomicModieyMutVarOf# its proper type, with a  pair, as in the proposal.
  • To do that I’ll fiddle with genprimopcode, to allow it to parse tuples as well as unboxed tuples; not hard.
  • This would disallow all this stuff about “any type that has a first field looking like a”, restricting to pairs alone.  This didn’t form part of the proposal, and was never documented.
  • Add a bit more clarity to the documentation, so it’d clear what must be forced.

 

Any objections?

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 12 October 2019 00:00
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

I don't remember what documentation, if any, it has. You're right that taking advantage of it is potentially risky. Here's what I think we really want:

 

atomicModifyMutVarQ# :: MutVar# s a -> (q -> a) -> (a -> q)  -> State# s -> (# State# s, a, q #)

 

where there's a special rule that (q -> a) is "obviously" a selector that selects a pointer.

On Fri, Oct 11, 2019, 12:56 PM Simon Peyton Jones <[hidden email]> wrote:

The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

I think that is 100.0% undocumented, in the code, or in the proposal.  Are you sure this is a settled consensus among the interested parties?

 

Adopting it would impose new invariants on the representation of values in GHC that I am deeply reluctant to impose.  I would much much prefer to stick with the pair that is (somewhat) documented.

 

About pair vs Unit, yes, I can see (just) your point about why a pair might be useful.  Here’s a better example:

 

Suppose mv :: MutVar# Int

 

atomicModifyMutVar2# mv $ \a ->

  let foo = f a

  in (g foo, foo)

 

Now, if f is expensive, and g is not invertible, then sharing foo might be useful.  It’s hard to think of a credible example, though.  Regardless, we should document it.

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 11 October 2019 17:03
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <[hidden email]> wrote:

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)

 

Close, but not quite. The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Yes, that sounds right.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Yes, it's somewhat significant. You actually can use Unit with the new primop (it's a tuple of arity 1), so that option is free. But using a pair gets you a bit more: you can build a thunk that's *shared* between the value installed in the MutVar and the one returned to the outside. Consider

 

atomicModifyMutVar2# mv $ \a ->

  let foo = expensive_computation a

  in ([3,foo], foo)

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

That whole regime came before my time, but since we win a bit by *not* fixing it, o wouldn't jump on it too quick.

 


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: atomicModifyMutVar2

Carter Schonwald
 how do you type check it / what type would you plausibly given it thats wired into very innards of ghc type system implementation? (by which i mean that most / all primops currently are pretty conservative in terms of the range of ghc type system features they use)


On Wed, Oct 16, 2019 at 1:51 PM David Feuer <[hidden email]> wrote:
What do you think about the version that takes a function as an argument, and is optimized for the case where that's a selector? That really feels like the platonic ideal here.

On Mon, Oct 14, 2019, 6:35 PM Simon Peyton Jones <[hidden email]> wrote:

OK.   I propose:

 

  • To give atomicModieyMutVarOf# its proper type, with a  pair, as in the proposal.
  • To do that I’ll fiddle with genprimopcode, to allow it to parse tuples as well as unboxed tuples; not hard.
  • This would disallow all this stuff about “any type that has a first field looking like a”, restricting to pairs alone.  This didn’t form part of the proposal, and was never documented.
  • Add a bit more clarity to the documentation, so it’d clear what must be forced.

 

Any objections?

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 12 October 2019 00:00
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

I don't remember what documentation, if any, it has. You're right that taking advantage of it is potentially risky. Here's what I think we really want:

 

atomicModifyMutVarQ# :: MutVar# s a -> (q -> a) -> (a -> q)  -> State# s -> (# State# s, a, q #)

 

where there's a special rule that (q -> a) is "obviously" a selector that selects a pointer.

On Fri, Oct 11, 2019, 12:56 PM Simon Peyton Jones <[hidden email]> wrote:

The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

I think that is 100.0% undocumented, in the code, or in the proposal.  Are you sure this is a settled consensus among the interested parties?

 

Adopting it would impose new invariants on the representation of values in GHC that I am deeply reluctant to impose.  I would much much prefer to stick with the pair that is (somewhat) documented.

 

About pair vs Unit, yes, I can see (just) your point about why a pair might be useful.  Here’s a better example:

 

Suppose mv :: MutVar# Int

 

atomicModifyMutVar2# mv $ \a ->

  let foo = f a

  in (g foo, foo)

 

Now, if f is expensive, and g is not invertible, then sharing foo might be useful.  It’s hard to think of a credible example, though.  Regardless, we should document it.

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 11 October 2019 17:03
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <[hidden email]> wrote:

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)

 

Close, but not quite. The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Yes, that sounds right.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Yes, it's somewhat significant. You actually can use Unit with the new primop (it's a tuple of arity 1), so that option is free. But using a pair gets you a bit more: you can build a thunk that's *shared* between the value installed in the MutVar and the one returned to the outside. Consider

 

atomicModifyMutVar2# mv $ \a ->

  let foo = expensive_computation a

  in ([3,foo], foo)

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

That whole regime came before my time, but since we win a bit by *not* fixing it, o wouldn't jump on it too quick.

 

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: atomicModifyMutVar2

David Feuer
Well, you basically need two primops. In approximate terms,

atomGen :: (a -> q) -> (q -> a) -> IORef a -> IO (a, q)
atomSel :: (a -> q) -> Int -> IORef a -> IO (a, q)

atomGen is rewritten to atomSel whenever the (q -> a) function is actually a selector function, in which case it is represented by the field position. Only atomGen would be considered "public", as the true type of atomSel can't be expressed.

On Wed, Oct 16, 2019, 9:07 PM Carter Schonwald <[hidden email]> wrote:
 how do you type check it / what type would you plausibly given it thats wired into very innards of ghc type system implementation? (by which i mean that most / all primops currently are pretty conservative in terms of the range of ghc type system features they use)


On Wed, Oct 16, 2019 at 1:51 PM David Feuer <[hidden email]> wrote:
What do you think about the version that takes a function as an argument, and is optimized for the case where that's a selector? That really feels like the platonic ideal here.

On Mon, Oct 14, 2019, 6:35 PM Simon Peyton Jones <[hidden email]> wrote:

OK.   I propose:

 

  • To give atomicModieyMutVarOf# its proper type, with a  pair, as in the proposal.
  • To do that I’ll fiddle with genprimopcode, to allow it to parse tuples as well as unboxed tuples; not hard.
  • This would disallow all this stuff about “any type that has a first field looking like a”, restricting to pairs alone.  This didn’t form part of the proposal, and was never documented.
  • Add a bit more clarity to the documentation, so it’d clear what must be forced.

 

Any objections?

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 12 October 2019 00:00
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

I don't remember what documentation, if any, it has. You're right that taking advantage of it is potentially risky. Here's what I think we really want:

 

atomicModifyMutVarQ# :: MutVar# s a -> (q -> a) -> (a -> q)  -> State# s -> (# State# s, a, q #)

 

where there's a special rule that (q -> a) is "obviously" a selector that selects a pointer.

On Fri, Oct 11, 2019, 12:56 PM Simon Peyton Jones <[hidden email]> wrote:

The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

I think that is 100.0% undocumented, in the code, or in the proposal.  Are you sure this is a settled consensus among the interested parties?

 

Adopting it would impose new invariants on the representation of values in GHC that I am deeply reluctant to impose.  I would much much prefer to stick with the pair that is (somewhat) documented.

 

About pair vs Unit, yes, I can see (just) your point about why a pair might be useful.  Here’s a better example:

 

Suppose mv :: MutVar# Int

 

atomicModifyMutVar2# mv $ \a ->

  let foo = f a

  in (g foo, foo)

 

Now, if f is expensive, and g is not invertible, then sharing foo might be useful.  It’s hard to think of a credible example, though.  Regardless, we should document it.

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 11 October 2019 17:03
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <[hidden email]> wrote:

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)

 

Close, but not quite. The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Yes, that sounds right.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Yes, it's somewhat significant. You actually can use Unit with the new primop (it's a tuple of arity 1), so that option is free. But using a pair gets you a bit more: you can build a thunk that's *shared* between the value installed in the MutVar and the one returned to the outside. Consider

 

atomicModifyMutVar2# mv $ \a ->

  let foo = expensive_computation a

  in ([3,foo], foo)

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

That whole regime came before my time, but since we win a bit by *not* fixing it, o wouldn't jump on it too quick.

 

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

RE: atomicModifyMutVar2

GHC - devs mailing list
In reply to this post by Carter Schonwald

What do you think about the version that takes a function as an argument, and is optimized for the case where that's a selector?

 

In any case that would change the API etc and I think that’s a bridge too far for a tidy-up.  Make a proposal if you like!

 

Simon

 

From: Carter Schonwald <[hidden email]>
Sent: 17 October 2019 02:08
To: David Feuer <[hidden email]>
Cc: Simon Peyton Jones <[hidden email]>; ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

 how do you type check it / what type would you plausibly given it thats wired into very innards of ghc type system implementation? (by which i mean that most / all primops currently are pretty conservative in terms of the range of ghc type system features they use)

 

 

On Wed, Oct 16, 2019 at 1:51 PM David Feuer <[hidden email]> wrote:

What do you think about the version that takes a function as an argument, and is optimized for the case where that's a selector? That really feels like the platonic ideal here.

 

On Mon, Oct 14, 2019, 6:35 PM Simon Peyton Jones <[hidden email]> wrote:

OK.   I propose:

 

  • To give atomicModieyMutVarOf# its proper type, with a  pair, as in the proposal.
  • To do that I’ll fiddle with genprimopcode, to allow it to parse tuples as well as unboxed tuples; not hard.
  • This would disallow all this stuff about “any type that has a first field looking like a”, restricting to pairs alone.  This didn’t form part of the proposal, and was never documented.
  • Add a bit more clarity to the documentation, so it’d clear what must be forced.

 

Any objections?

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 12 October 2019 00:00
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

I don't remember what documentation, if any, it has. You're right that taking advantage of it is potentially risky. Here's what I think we really want:

 

atomicModifyMutVarQ# :: MutVar# s a -> (q -> a) -> (a -> q)  -> State# s -> (# State# s, a, q #)

 

where there's a special rule that (q -> a) is "obviously" a selector that selects a pointer.

On Fri, Oct 11, 2019, 12:56 PM Simon Peyton Jones <[hidden email]> wrote:

The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

I think that is 100.0% undocumented, in the code, or in the proposal.  Are you sure this is a settled consensus among the interested parties?

 

Adopting it would impose new invariants on the representation of values in GHC that I am deeply reluctant to impose.  I would much much prefer to stick with the pair that is (somewhat) documented.

 

About pair vs Unit, yes, I can see (just) your point about why a pair might be useful.  Here’s a better example:

 

Suppose mv :: MutVar# Int

 

atomicModifyMutVar2# mv $ \a ->

  let foo = f a

  in (g foo, foo)

 

Now, if f is expensive, and g is not invertible, then sharing foo might be useful.  It’s hard to think of a credible example, though.  Regardless, we should document it.

 

Simon

 

From: David Feuer <[hidden email]>
Sent: 11 October 2019 17:03
To: Simon Peyton Jones <[hidden email]>
Cc: ghc-devs <[hidden email]>
Subject: Re: atomicModifyMutVar2

 

On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <[hidden email]> wrote:

David

I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal, and the comments in primops.txt.pp (reproduced below).

Question 1

I think the “real” type of atomicModifyMutVar2 is

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> (a,b))

                     -> State# s

                     -> (# State# s, a, (a, b) #)

 

Close, but not quite. The result doesn't have to be a pair. It can be a tuple of any size at all. Indeed, it can even be an arbitrary record type whose first pointer field has the appropriate type.

 

Nowhere is this explicitly stated, but I believe that the intended semantics of a call

case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah

Then, suppose the old value of the MutVar was ‘old’

  • The primop builds a thunk  t = f old
  • The new value of the mutable variable is (fst t)
  • The result r is t
  • The result x is old

Question: is that correct?   We should state it explicitly.

Yes, that sounds right.

Question 2

Next question: Why does f have to return a pair?  So far as I can tell, it’s only so that a client can force it.   The ‘b’ part never seems to play a useful role.   So we could equally well have had

atomicModifyMutVar2# :: MutVar# s a

                     -> (a -> Box a)

                     -> State# s

                     -> (# State# s, a, Unit a #)

where Unit is defined in Data.Tuple

    data Unit a = Unit a

Now you can force the result of (f old), just as with a pair.  But the ‘b’ would no longer complicate matters.

Question: is the ‘b’ in the pair significant?   Or could we use Unit?

Yes, it's somewhat significant. You actually can use Unit with the new primop (it's a tuple of arity 1), so that option is free. But using a pair gets you a bit more: you can build a thunk that's *shared* between the value installed in the MutVar and the one returned to the outside. Consider

 

atomicModifyMutVar2# mv $ \a ->

  let foo = expensive_computation a

  in ([3,foo], foo)

Question 3

In the comments below you say "but we don't know about pairs here”.   Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This fancy footwork is one more complication, if it could be avoided.

That whole regime came before my time, but since we win a bit by *not* fixing it, o wouldn't jump on it too quick.

 

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs