[Proposal] Unify various specialized mkWeak functions in base?

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

[Proposal] Unify various specialized mkWeak functions in base?

Shao Cheng
Hi everyone,

In System.Mem.Weak we have an mkWeak function to create weak pointers. But we
also have a lot of specialized mkWeak* functions, e.g. mkWeakIORef,
mkWeakThreadId, etc, to ensure that we actually pass the unlifted closure
instead of the lifted one as the key to the underlying mkWeak# primop.

The various specialized mkWeak* functions' signatures don't have a coherent
style. Some functions like mkWeakIORef always take a Haskell finalizer argument,
while mkWeakThreadId doesn't take a finalizer argument at all. This is
troublesome for users since:

* Sometimes a user doesn't want to attach a finalizer at all. They could pass a
"pure ()" dummy finalizer, but that'll still come with a minor bit of extra
runtime overhead

* For mkWeakThreadId, they may want to attach a finalizer. The runtime supports
it, but the type signature doesn't say so.

Of course, they can always add a few extensions and call mkWeak# as they wish,
but it would be nicer if we have a uniform API to allow a Haskell finalizer to
be added optionally. The simplest API could be something like (forgive my
terrible naming):

class WeakKey k where
  mkWeakWithRealKey :: WeakKey k => k -> v -> Maybe (IO ()) -> IO (Weak v)

The WeakKey class is just a way of exposing the unlifted field from a single
datacon wrapper type, and I think this can be useful for other purposes as well,
so maybe we can do something like:

class Unlift a where
  type Unlifted a :: TYPE 'UnliftedRep
  unlift :: a -> Unlifted a

mkWeakWithRealKey :: Unlift k => k -> v -> Maybe (IO ()) -> IO (Weak v)

Thanks for reading so far, what are your thoughts on this? The proposed extended
interfaces can be easily implemented in 3rd-party packages, but it would be nice
to add to base.

Cheers,
Cheng Shao

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

Re: [Proposal] Unify various specialized mkWeak functions in base?

David Feuer
You should look at the primitive-unlifted package which offers a class for wrapping and unwrapping unlifted things and functions for making weak pointers from (and to) unlifted things.

On Wed, Nov 11, 2020, 4:34 PM Cheng Shao <[hidden email]> wrote:
Hi everyone,

In System.Mem.Weak we have an mkWeak function to create weak pointers. But we
also have a lot of specialized mkWeak* functions, e.g. mkWeakIORef,
mkWeakThreadId, etc, to ensure that we actually pass the unlifted closure
instead of the lifted one as the key to the underlying mkWeak# primop.

The various specialized mkWeak* functions' signatures don't have a coherent
style. Some functions like mkWeakIORef always take a Haskell finalizer argument,
while mkWeakThreadId doesn't take a finalizer argument at all. This is
troublesome for users since:

* Sometimes a user doesn't want to attach a finalizer at all. They could pass a
"pure ()" dummy finalizer, but that'll still come with a minor bit of extra
runtime overhead

* For mkWeakThreadId, they may want to attach a finalizer. The runtime supports
it, but the type signature doesn't say so.

Of course, they can always add a few extensions and call mkWeak# as they wish,
but it would be nicer if we have a uniform API to allow a Haskell finalizer to
be added optionally. The simplest API could be something like (forgive my
terrible naming):

class WeakKey k where
  mkWeakWithRealKey :: WeakKey k => k -> v -> Maybe (IO ()) -> IO (Weak v)

The WeakKey class is just a way of exposing the unlifted field from a single
datacon wrapper type, and I think this can be useful for other purposes as well,
so maybe we can do something like:

class Unlift a where
  type Unlifted a :: TYPE 'UnliftedRep
  unlift :: a -> Unlifted a

mkWeakWithRealKey :: Unlift k => k -> v -> Maybe (IO ()) -> IO (Weak v)

Thanks for reading so far, what are your thoughts on this? The proposed extended
interfaces can be easily implemented in 3rd-party packages, but it would be nice
to add to base.

Cheers,
Cheng Shao
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

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

Re: [Proposal] Unify various specialized mkWeak functions in base?

Shao Cheng
Thanks, David! That looks exactly like what I have in mind. Given its dependency on primitive and primitive not being a part of base (or a boot lib), I think I'd better give up upstreaming the idea and simply use that package when really needed.

On Wed, Nov 11, 2020 at 10:36 PM David Feuer <[hidden email]> wrote:
You should look at the primitive-unlifted package which offers a class for wrapping and unwrapping unlifted things and functions for making weak pointers from (and to) unlifted things.

On Wed, Nov 11, 2020, 4:34 PM Cheng Shao <[hidden email]> wrote:
Hi everyone,

In System.Mem.Weak we have an mkWeak function to create weak pointers. But we
also have a lot of specialized mkWeak* functions, e.g. mkWeakIORef,
mkWeakThreadId, etc, to ensure that we actually pass the unlifted closure
instead of the lifted one as the key to the underlying mkWeak# primop.

The various specialized mkWeak* functions' signatures don't have a coherent
style. Some functions like mkWeakIORef always take a Haskell finalizer argument,
while mkWeakThreadId doesn't take a finalizer argument at all. This is
troublesome for users since:

* Sometimes a user doesn't want to attach a finalizer at all. They could pass a
"pure ()" dummy finalizer, but that'll still come with a minor bit of extra
runtime overhead

* For mkWeakThreadId, they may want to attach a finalizer. The runtime supports
it, but the type signature doesn't say so.

Of course, they can always add a few extensions and call mkWeak# as they wish,
but it would be nicer if we have a uniform API to allow a Haskell finalizer to
be added optionally. The simplest API could be something like (forgive my
terrible naming):

class WeakKey k where
  mkWeakWithRealKey :: WeakKey k => k -> v -> Maybe (IO ()) -> IO (Weak v)

The WeakKey class is just a way of exposing the unlifted field from a single
datacon wrapper type, and I think this can be useful for other purposes as well,
so maybe we can do something like:

class Unlift a where
  type Unlifted a :: TYPE 'UnliftedRep
  unlift :: a -> Unlifted a

mkWeakWithRealKey :: Unlift k => k -> v -> Maybe (IO ()) -> IO (Weak v)

Thanks for reading so far, what are your thoughts on this? The proposed extended
interfaces can be easily implemented in 3rd-party packages, but it would be nice
to add to base.

Cheers,
Cheng Shao
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

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