Discussion:
Proposal: give Ptr a nominal role
David Feuer
2018-10-30 17:56:31 UTC
Permalink
Currently, we have

data Ptr a = Ptr Addr#
type role Ptr phantom

This is weird: accidentally coercing a pointer to a different type is very
bad. The only reason Ptr has this role is that without it, castPtr and such
may not be free or will involve unsafe coercions.

Thankfully, we have enough power to fix this now.

data Addr = Ptr_ Addr#

newtype Ptr a = Ptr_ Addr
type role Ptr nominal

pattern Ptr :: Addr# -> Ptr a
pattern Ptr a# = Ptr_ (Addr a#)

castPtr :: Ptr a -> Ptr b
castPtr (Ptr a) = Ptr a

ptrCoercible
:: ((forall a b. Coercible (Ptr a) (Ptr b)) => r)
-> r
ptrCoercible r = r

ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion

I propose that we do this.
Carter Schonwald
2018-10-30 18:06:28 UTC
Permalink
hey David, heres a simpler version (attached below), that I think
accomplishes the same goal.

One issue, that would need to be evaluated empirically: how many type class
instances would break from this change? Would any?

is it Storable instances that are an issue, or things that use storable?

what safety is gained vs what is impacted? (i guess i mostly just wanna
understand what would be broken by this change, a lot of code in the wild
uses pointers for systems integrations)


newtype Ptr a = Ptr Addr#
type role Ptr nominal


castPtr :: Ptr a -> Ptr b
castPtr = unsafeCoerce

ptrCoercible
:: ((forall a b. Coercible (Ptr a) (Ptr b)) => r)
-> r
ptrCoercible r = r

ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
Post by David Feuer
Currently, we have
data Ptr a = Ptr Addr#
type role Ptr phantom
This is weird: accidentally coercing a pointer to a different type is very
bad. The only reason Ptr has this role is that without it, castPtr and such
may not be free or will involve unsafe coercions.
Thankfully, we have enough power to fix this now.
data Addr = Ptr_ Addr#
newtype Ptr a = Ptr_ Addr
type role Ptr nominal
pattern Ptr :: Addr# -> Ptr a
pattern Ptr a# = Ptr_ (Addr a#)
castPtr :: Ptr a -> Ptr b
castPtr (Ptr a) = Ptr a
ptrCoercible
:: ((forall a b. Coercible (Ptr a) (Ptr b)) => r)
-> r
ptrCoercible r = r
ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
I propose that we do this.
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
David Feuer
2018-10-30 18:18:03 UTC
Permalink
Your simpler version won't even compile, and it gives Ptr the wrong kind.

I don't *think* anything breaks at all, unless it's using coerce on Ptr
types (the fix is easy). Note in particular that Ptr doesn't have a Generic
instance.

The extra safety is at the Storable use sites. If you have some type that
has a Ptr buried in it somewhere, coerce it to something else, and then
call a function that uses a (different) Storable instance for that field,
you're in trouble. With this change, the compiler will let you know that
there's a buried Ptr in there and (after verifying that it's okay) you can
introduce the coercibility explicitly to explain that it's fine.
Post by Carter Schonwald
hey David, heres a simpler version (attached below), that I think
accomplishes the same goal.
One issue, that would need to be evaluated empirically: how many type
class instances would break from this change? Would any?
is it Storable instances that are an issue, or things that use storable?
what safety is gained vs what is impacted? (i guess i mostly just wanna
understand what would be broken by this change, a lot of code in the wild
uses pointers for systems integrations)
newtype Ptr a = Ptr Addr#
type role Ptr nominal
castPtr :: Ptr a -> Ptr b
castPtr = unsafeCoerce
ptrCoercible
:: ((forall a b. Coercible (Ptr a) (Ptr b)) => r)
-> r
ptrCoercible r = r
ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
Post by David Feuer
Currently, we have
data Ptr a = Ptr Addr#
type role Ptr phantom
This is weird: accidentally coercing a pointer to a different type is
very bad. The only reason Ptr has this role is that without it, castPtr and
such may not be free or will involve unsafe coercions.
Thankfully, we have enough power to fix this now.
data Addr = Ptr_ Addr#
newtype Ptr a = Ptr_ Addr
type role Ptr nominal
pattern Ptr :: Addr# -> Ptr a
pattern Ptr a# = Ptr_ (Addr a#)
castPtr :: Ptr a -> Ptr b
castPtr (Ptr a) = Ptr a
ptrCoercible
:: ((forall a b. Coercible (Ptr a) (Ptr b)) => r)
-> r
ptrCoercible r = r
ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
I propose that we do this.
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Eric Mertens
2018-10-30 18:19:56 UTC
Permalink
Post by David Feuer
Your simpler version won't even compile,
Here are the two versions edited so that both can compile (they needed some tweaks) for those playing along at home:

{-# Language PatternSynonyms, FlexibleContexts, RoleAnnotations, RankNTypes, MagicHash #-}
module Help where

import GHC.Exts hiding (Ptr)
import Data.Type.Coercion
import Unsafe.Coerce

{- Carter's version
data Ptr a = Ptr Addr#
type role Ptr nominal


castPtr :: Ptr a -> Ptr b
castPtr = unsafeCoerce

ptrCoercible
:: (forall a b. Coercible (Ptr a) (Ptr b) => r)
-> r
ptrCoercible r = r

ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
-}

data Addr = Addr_ Addr#

newtype Ptr a = Ptr_ Addr
type role Ptr nominal

pattern Ptr :: Addr# -> Ptr a
pattern Ptr a# = Ptr_ (Addr_ a#)

castPtr :: Ptr a -> Ptr b
castPtr (Ptr a) = Ptr a

ptrCoercible
:: (forall a b. Coercible (Ptr a) (Ptr b) => r)
-> r
ptrCoercible r = r

ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
David Feuer
2018-10-30 18:22:50 UTC
Permalink
Are you sure that modification of Carter's will compile?
Post by David Feuer
Your simpler version won't even compile,
Here are the two versions edited so that both can compile (they needed
{-# Language PatternSynonyms, FlexibleContexts, RoleAnnotations, RankNTypes, MagicHash #-}
module Help where
import GHC.Exts hiding (Ptr)
import Data.Type.Coercion
import Unsafe.Coerce
{- Carter's version
data Ptr a = Ptr Addr#
type role Ptr nominal
castPtr :: Ptr a -> Ptr b
castPtr = unsafeCoerce
ptrCoercible
:: (forall a b. Coercible (Ptr a) (Ptr b) => r)
-> r
ptrCoercible r = r
ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
-}
data Addr = Addr_ Addr#
newtype Ptr a = Ptr_ Addr
type role Ptr nominal
pattern Ptr :: Addr# -> Ptr a
pattern Ptr a# = Ptr_ (Addr_ a#)
castPtr :: Ptr a -> Ptr b
castPtr (Ptr a) = Ptr a
ptrCoercible
:: (forall a b. Coercible (Ptr a) (Ptr b) => r)
-> r
ptrCoercible r = r
ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
Eric Mertens
2018-10-30 18:24:22 UTC
Permalink
No, it won’t compile, but it at least loads far enough to generate the right error that you can’t coerce data like that. I thought about sending a clarifying email afterward but I didn’t want to spam the list with a second message. The point is that all the syntactic errors are cleaned up to the point that one can actually play with the code now.
Post by David Feuer
Are you sure that modification of Carter's will compile?
Carter Schonwald
2018-11-01 17:46:47 UTC
Permalink
so i'm taking a look at the current docs / definition in base (and i'm
testing testing out seeing what happens if we changed the role and just
build ghc and base as is)
https://github.com/ghc/ghc/blob/82a716431cc680392e332bc2b1a1fd0d7faa4cd8/libraries/base/GHC/Ptr.hs#L37-L57

i'm replicating the docs below:

but the important detail is the phantom role in the current code is
deliberate ...
because no guarantees are made about the relationship between the choice in
type parameter ( which putatively will always have the same heap rep in
haskell land)
and the representation at the other side of the pointer.

a good example might be Ptr Char. Is this a single location of a 32bit /
utf32 code point, or an array of utf8 code points or utf32 code points?
is it null terminated vs there being an extra sequence length? These are
all valid things that can be happening. And

-- Data pointers.
-- The role of Ptr's parameter is phantom, as there is no relation between
-- the Haskell representation and whathever the user puts at the end of the
-- pointer. And phantom is useful to implement castPtr (see #9163)
-- redundant role annotation checks that this doesn't change
type role Ptr phantom
data Ptr a = Ptr Addr#
deriving ( Eq -- ^ @since 2.01
, Ord -- ^ @since 2.01
)
-- ^ A value of type @'Ptr' a@ represents a pointer to an object, or an
-- array of objects, which may be marshalled to or from Haskell values
-- of type @***@.
--
-- The type @a@ will often be an instance of class
-- 'Foreign.Storable.Storable' which provides the marshalling operations.
-- However this is not essential, and you can provide your own operations
-- to access the pointer. For example you might write small foreign
-- functions to get or set the fields of a C @***@.

unrelatedly, while i'm not familiar with how to use modern coercible bits,
the folllowing subset of what i mentioned earlier seems to work fine

{-# Language PatternSynonyms, FlexibleContexts, RoleAnnotations,
RankNTypes, MagicHash #-}

module Ptr where


import GHC.Exts hiding (Ptr)
import Data.Type.Coercion
import Unsafe.Coerce


data Ptr a = Ptr Addr#
type role Ptr nominal


castPtr :: Ptr a -> Ptr b
castPtr = unsafeCoerce

ptrCoercible
:: (forall a b. Coercible (Ptr a) (Ptr b) => r)
-> r
ptrCoercible r = r
No, it won’t compile, but it at least loads far enough to generate the
right error that you can’t coerce data like that. I thought about sending a
clarifying email afterward but I didn’t want to spam the list with a second
message. The point is that all the syntactic errors are cleaned up to the
point that one can actually play with the code now.
Post by David Feuer
Are you sure that modification of Carter's will compile?
Evan Laforge
2018-11-01 18:13:06 UTC
Permalink
On Thu, Nov 1, 2018 at 10:47 AM Carter Schonwald
a good example might be Ptr Char. Is this a single location of a 32bit / utf32 code point, or an array of utf8 code points or utf32 code points?
is it null terminated vs there being an extra sequence length? These are all valid things that can be happening. And
I'm not sure if it affects your point, but I sure hope a 'Ptr Char'
points to a 4 byte haskell Char as it claims, and 'Ptr CChar' points
to a 1 byte C char, as it claims. Otherwise, sizeOf will be wrong and
array indexing will go out of bounds.

Of course, in the C case, whether or not there are further chars after
that and if they are terminated and what is the encoding is all
ambiguous, as it always is for C.
David Feuer
2018-11-01 18:16:36 UTC
Permalink
Indeed. I think the point is that Ptr should be thought of as tied to
Storable. If you want to use an Addr# for something else, then you
shouldn't be using Ptr!
Post by Evan Laforge
On Thu, Nov 1, 2018 at 10:47 AM Carter Schonwald
Post by Carter Schonwald
a good example might be Ptr Char. Is this a single location of a 32bit
/ utf32 code point, or an array of utf8 code points or utf32 code points?
Post by Carter Schonwald
is it null terminated vs there being an extra sequence length? These are
all valid things that can be happening. And
I'm not sure if it affects your point, but I sure hope a 'Ptr Char'
points to a 4 byte haskell Char as it claims, and 'Ptr CChar' points
to a 1 byte C char, as it claims. Otherwise, sizeOf will be wrong and
array indexing will go out of bounds.
Of course, in the C case, whether or not there are further chars after
that and if they are terminated and what is the encoding is all
ambiguous, as it always is for C.
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Carter Schonwald
2018-11-01 18:23:56 UTC
Permalink
... Ptr *is not* tied to storable, Storable is a convenience for FFI
integration .. storable is tied to ptr

there are whole MOUNTAINS of haskell code that underly this, and we can't
lawyer it away with some opinions
Post by David Feuer
Indeed. I think the point is that Ptr should be thought of as tied to
Storable. If you want to use an Addr# for something else, then you
shouldn't be using Ptr!
Post by Evan Laforge
On Thu, Nov 1, 2018 at 10:47 AM Carter Schonwald
Post by Carter Schonwald
a good example might be Ptr Char. Is this a single location of a 32bit
/ utf32 code point, or an array of utf8 code points or utf32 code points?
Post by Carter Schonwald
is it null terminated vs there being an extra sequence length? These
are all valid things that can be happening. And
I'm not sure if it affects your point, but I sure hope a 'Ptr Char'
points to a 4 byte haskell Char as it claims, and 'Ptr CChar' points
to a 1 byte C char, as it claims. Otherwise, sizeOf will be wrong and
array indexing will go out of bounds.
Of course, in the C case, whether or not there are further chars after
that and if they are terminated and what is the encoding is all
ambiguous, as it always is for C.
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Carter Schonwald
2018-11-01 18:25:37 UTC
Permalink
phrased differnetly: storable provides one (c compatible) isomorphism
between fixed size values in haskell and c

the moment you want to talk about something that isn't fixed sized, like a
unicode character (which is a sequence of one or more code points, which we
call Char in haskell), storable doesn't apply.
Post by Carter Schonwald
... Ptr *is not* tied to storable, Storable is a convenience for FFI
integration .. storable is tied to ptr
there are whole MOUNTAINS of haskell code that underly this, and we can't
lawyer it away with some opinions
Post by David Feuer
Indeed. I think the point is that Ptr should be thought of as tied to
Storable. If you want to use an Addr# for something else, then you
shouldn't be using Ptr!
Post by Evan Laforge
On Thu, Nov 1, 2018 at 10:47 AM Carter Schonwald
Post by Carter Schonwald
a good example might be Ptr Char. Is this a single location of a
32bit / utf32 code point, or an array of utf8 code points or utf32 code
points?
Post by Carter Schonwald
is it null terminated vs there being an extra sequence length? These
are all valid things that can be happening. And
I'm not sure if it affects your point, but I sure hope a 'Ptr Char'
points to a 4 byte haskell Char as it claims, and 'Ptr CChar' points
to a 1 byte C char, as it claims. Otherwise, sizeOf will be wrong and
array indexing will go out of bounds.
Of course, in the C case, whether or not there are further chars after
that and if they are terminated and what is the encoding is all
ambiguous, as it always is for C.
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Daniel Cartwright
2018-11-01 19:33:53 UTC
Permalink
i agree with carter regarding the Storable-Ptr relationship. It seems to me
that Storable is tied to Ptr. Some concrete evidence of this is in the
Data.Primitive.Ptr API
Post by Carter Schonwald
phrased differnetly: storable provides one (c compatible) isomorphism
between fixed size values in haskell and c
the moment you want to talk about something that isn't fixed sized, like a
unicode character (which is a sequence of one or more code points, which we
call Char in haskell), storable doesn't apply.
On Thu, Nov 1, 2018 at 2:23 PM Carter Schonwald <
Post by Carter Schonwald
... Ptr *is not* tied to storable, Storable is a convenience for FFI
integration .. storable is tied to ptr
there are whole MOUNTAINS of haskell code that underly this, and we can't
lawyer it away with some opinions
Post by David Feuer
Indeed. I think the point is that Ptr should be thought of as tied to
Storable. If you want to use an Addr# for something else, then you
shouldn't be using Ptr!
Post by Evan Laforge
On Thu, Nov 1, 2018 at 10:47 AM Carter Schonwald
Post by Carter Schonwald
a good example might be Ptr Char. Is this a single location of a
32bit / utf32 code point, or an array of utf8 code points or utf32 code
points?
Post by Carter Schonwald
is it null terminated vs there being an extra sequence length? These
are all valid things that can be happening. And
I'm not sure if it affects your point, but I sure hope a 'Ptr Char'
points to a 4 byte haskell Char as it claims, and 'Ptr CChar' points
to a 1 byte C char, as it claims. Otherwise, sizeOf will be wrong and
array indexing will go out of bounds.
Of course, in the C case, whether or not there are further chars after
that and if they are terminated and what is the encoding is all
ambiguous, as it always is for C.
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Daniel Cartwright
2018-11-01 19:37:24 UTC
Permalink
I am +1 on this change.
Post by Daniel Cartwright
i agree with carter regarding the Storable-Ptr relationship. It seems to
me that Storable is tied to Ptr. Some concrete evidence of this is in the
Data.Primitive.Ptr API
On Thu, Nov 1, 2018 at 2:26 PM Carter Schonwald <
Post by Carter Schonwald
phrased differnetly: storable provides one (c compatible) isomorphism
between fixed size values in haskell and c
the moment you want to talk about something that isn't fixed sized, like
a unicode character (which is a sequence of one or more code points, which
we call Char in haskell), storable doesn't apply.
On Thu, Nov 1, 2018 at 2:23 PM Carter Schonwald <
Post by Carter Schonwald
... Ptr *is not* tied to storable, Storable is a convenience for FFI
integration .. storable is tied to ptr
there are whole MOUNTAINS of haskell code that underly this, and we
can't lawyer it away with some opinions
Post by David Feuer
Indeed. I think the point is that Ptr should be thought of as tied to
Storable. If you want to use an Addr# for something else, then you
shouldn't be using Ptr!
Post by Evan Laforge
On Thu, Nov 1, 2018 at 10:47 AM Carter Schonwald
Post by Carter Schonwald
a good example might be Ptr Char. Is this a single location of a
32bit / utf32 code point, or an array of utf8 code points or utf32 code
points?
Post by Carter Schonwald
is it null terminated vs there being an extra sequence length? These
are all valid things that can be happening. And
I'm not sure if it affects your point, but I sure hope a 'Ptr Char'
points to a 4 byte haskell Char as it claims, and 'Ptr CChar' points
to a 1 byte C char, as it claims. Otherwise, sizeOf will be wrong and
array indexing will go out of bounds.
Of course, in the C case, whether or not there are further chars after
that and if they are terminated and what is the encoding is all
ambiguous, as it always is for C.
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Matthew Pickering
2018-11-02 10:34:05 UTC
Permalink
Making `Ptr` (and ForeignPtr) have a nominal role would have prevented
recent bugs where it was possible to coerce Vectors between any types.

See: https://github.com/haskell/vector/pull/224
and: https://phabricator.haskell.org/D4941
Post by David Feuer
Currently, we have
data Ptr a = Ptr Addr#
type role Ptr phantom
This is weird: accidentally coercing a pointer to a different type is very bad. The only reason Ptr has this role is that without it, castPtr and such may not be free or will involve unsafe coercions.
Thankfully, we have enough power to fix this now.
data Addr = Ptr_ Addr#
newtype Ptr a = Ptr_ Addr
type role Ptr nominal
pattern Ptr :: Addr# -> Ptr a
pattern Ptr a# = Ptr_ (Addr a#)
castPtr :: Ptr a -> Ptr b
castPtr (Ptr a) = Ptr a
ptrCoercible
:: ((forall a b. Coercible (Ptr a) (Ptr b)) => r)
-> r
ptrCoercible r = r
ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
I propose that we do this.
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Carter Schonwald
2018-11-02 23:25:24 UTC
Permalink
my understanding is ANY non phantom role suffices in this case ..

i dont use the coercible class in this context, my main concern is how role
selection will impact client type classes / GND / etc

On Fri, Nov 2, 2018 at 6:34 AM Matthew Pickering <
Post by Matthew Pickering
Making `Ptr` (and ForeignPtr) have a nominal role would have prevented
recent bugs where it was possible to coerce Vectors between any types.
See: https://github.com/haskell/vector/pull/224
and: https://phabricator.haskell.org/D4941
Post by David Feuer
Currently, we have
data Ptr a = Ptr Addr#
type role Ptr phantom
This is weird: accidentally coercing a pointer to a different type is
very bad. The only reason Ptr has this role is that without it, castPtr and
such may not be free or will involve unsafe coercions.
Post by David Feuer
Thankfully, we have enough power to fix this now.
data Addr = Ptr_ Addr#
newtype Ptr a = Ptr_ Addr
type role Ptr nominal
pattern Ptr :: Addr# -> Ptr a
pattern Ptr a# = Ptr_ (Addr a#)
castPtr :: Ptr a -> Ptr b
castPtr (Ptr a) = Ptr a
ptrCoercible
:: ((forall a b. Coercible (Ptr a) (Ptr b)) => r)
-> r
ptrCoercible r = r
ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
I propose that we do this.
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Carter Schonwald
2018-11-02 23:27:29 UTC
Permalink
woops:

i mis stated my previous email, misread some stuff, please ignore it :)
Post by Carter Schonwald
my understanding is ANY non phantom role suffices in this case ..
i dont use the coercible class in this context, my main concern is how
role selection will impact client type classes / GND / etc
On Fri, Nov 2, 2018 at 6:34 AM Matthew Pickering <
Post by Matthew Pickering
Making `Ptr` (and ForeignPtr) have a nominal role would have prevented
recent bugs where it was possible to coerce Vectors between any types.
See: https://github.com/haskell/vector/pull/224
and: https://phabricator.haskell.org/D4941
Post by David Feuer
Currently, we have
data Ptr a = Ptr Addr#
type role Ptr phantom
This is weird: accidentally coercing a pointer to a different type is
very bad. The only reason Ptr has this role is that without it, castPtr and
such may not be free or will involve unsafe coercions.
Post by David Feuer
Thankfully, we have enough power to fix this now.
data Addr = Ptr_ Addr#
newtype Ptr a = Ptr_ Addr
type role Ptr nominal
pattern Ptr :: Addr# -> Ptr a
pattern Ptr a# = Ptr_ (Addr a#)
castPtr :: Ptr a -> Ptr b
castPtr (Ptr a) = Ptr a
ptrCoercible
:: ((forall a b. Coercible (Ptr a) (Ptr b)) => r)
-> r
ptrCoercible r = r
ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
I propose that we do this.
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Carter Schonwald
2018-11-02 23:29:17 UTC
Permalink
https://ghc.haskell.org/trac/ghc/ticket/9163 seems to talk about *why* Ptr
being phantom actually has a pretty measurable impact on code. (cast ptr
becomes a noop and this has a measurable impact on a number of application
measures)
Post by Carter Schonwald
i mis stated my previous email, misread some stuff, please ignore it :)
On Fri, Nov 2, 2018 at 7:25 PM Carter Schonwald <
Post by Carter Schonwald
my understanding is ANY non phantom role suffices in this case ..
i dont use the coercible class in this context, my main concern is how
role selection will impact client type classes / GND / etc
On Fri, Nov 2, 2018 at 6:34 AM Matthew Pickering <
Post by Matthew Pickering
Making `Ptr` (and ForeignPtr) have a nominal role would have prevented
recent bugs where it was possible to coerce Vectors between any types.
See: https://github.com/haskell/vector/pull/224
and: https://phabricator.haskell.org/D4941
Post by David Feuer
Currently, we have
data Ptr a = Ptr Addr#
type role Ptr phantom
This is weird: accidentally coercing a pointer to a different type is
very bad. The only reason Ptr has this role is that without it, castPtr and
such may not be free or will involve unsafe coercions.
Post by David Feuer
Thankfully, we have enough power to fix this now.
data Addr = Ptr_ Addr#
newtype Ptr a = Ptr_ Addr
type role Ptr nominal
pattern Ptr :: Addr# -> Ptr a
pattern Ptr a# = Ptr_ (Addr a#)
castPtr :: Ptr a -> Ptr b
castPtr (Ptr a) = Ptr a
ptrCoercible
:: ((forall a b. Coercible (Ptr a) (Ptr b)) => r)
-> r
ptrCoercible r = r
ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
I propose that we do this.
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
David Feuer
2018-11-04 13:28:17 UTC
Permalink
Pattern synonyms can be bundled with type constructors these days.

On Sun, Nov 4, 2018, 7:01 AM Bertram Felgenhauer via Libraries <
Post by Carter Schonwald
Post by Carter Schonwald
https://ghc.haskell.org/trac/ghc/ticket/9163 seems to talk about *why*
Ptr
Post by Carter Schonwald
being phantom actually has a pretty measurable impact on code. (cast ptr
becomes a noop and this has a measurable impact on a number of
application
Post by Carter Schonwald
measures)
David's point, I believe, is that the same performance problem could
have been solved by turning Ptr into a newtype, without giving up the
representational that it had before. In fact he brought this up in the
same trac ticket,
https://ghc.haskell.org/trac/ghc/ticket/9163#comment:38
Post by Carter Schonwald
Post by David Feuer
Thankfully, we have enough power to fix this now.
data Addr = Ptr_ Addr#
newtype Ptr a = Ptr_ Addr
type role Ptr nominal
pattern Ptr :: Addr# -> Ptr a
pattern Ptr a# = Ptr_ (Addr a#)
castPtr :: Ptr a -> Ptr b
castPtr (Ptr a) = Ptr a
ptrCoercible
:: ((forall a b. Coercible (Ptr a) (Ptr b)) => r)
-> r
ptrCoercible r = r
ptrCoercion :: Coercion (Ptr a) (Ptr b)
ptrCoercion = Coercion
I propose that we do this.
This will break some imports, since
import GHC.Ptr (Ptr (..))
will not import the pattern synonym. This is how Ptr is imported in
both bytestring and vector. But it's not a big deal, I suppose.
Cheers,
Bertram
_______________________________________________
Libraries mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Loading...