[Haskell-cafe] What is the right way to use unsafeCoerce?

Brandon Allbery allbery.b at gmail.com
Tue Aug 14 03:00:09 UTC 2018


unsafeCoerce just tells the typechecker to use a different type for that
value. Values of all types as stored in memory have pretty much the same
basic layout: constructor tag as an Int# counting upward from 0 per type,
followed by a pointer for each associated value (or the actual value if
it's unboxed; so an Int is stored as an 0# followed by an Int# representing
its value), each of these consuming a single basic word (64 bits on a
64-bit platform). So a Bool is the same as an Int# which is 0# or 1#, and
for an Either String Int you have a constructor tag 0# for Left or 1# for
Right, followed by a single pointer whose associated type is determined by
the constructor tag (here, either it points to a String or to an Int).

Unpacking and/or unboxing values can alter this and complicate things. See
the GHC manual with respect to the UNPACK pragma and -funbox-strict-fields;
you may under some circumstances need to disable optimization if you want
to (ab)use unsafeCoerce.

So in short, info tables don't usually come into play at this level. But
you can cause core dumps if you're not careful, especially if you do
something like coercing a value from a type with 2 constructors to a type
that has only 1. It is, however, safe if you ensure the runtime
representation of values of both types are the same (but as above, ensuring
this sometimes means compiling without optimization).

On Mon, Aug 13, 2018 at 10:47 PM Cosmia Fu <cosmiafu at gmail.com> wrote:

> Hi all,
>
> I have noticed that unsafeCoerce is able to
>
> > Prelude> import Unsafe.Coerce
> > Prelude Unsafe.Coerce> data P = P Int Double deriving Show
> > Prelude Unsafe.Coerce> data Q a b = Q a b deriving Show
> > Prelude Unsafe.Coerce> unsafeCoerce (P 23 2.33) :: Q Int Double
> > Q 23 2.33
>
> And it works even for sum type, and the first constructor always wins.
>
> > Prelude Unsafe.Coerce> data M a = J a deriving Show
> > Prelude Unsafe.Coerce> unsafeCoerce (J "qwe") :: Either String String
> > Left "qwe"
> > Prelude Unsafe.Coerce> unsafeCoerce (Just "qwe") :: M String
> > J "qwe"
>
> And the documenation for unsafeCoerce# says
>
> > Casting between two types that have the same runtime representation. One
> case is when the two types differ only in "phantom" type parameters, for
> example Ptr Int to Ptr Float, or [Int] to [Float] when the list is known to
> be empty. Also, a newtype of a type T has the same representation at
> runtime as T.
> >
> http://hackage.haskell.org/package/base-4.11.1.0/docs/GHC-Exts.html#v:unsafeCoerce-35-
>
> But info tables for different constructors are different. Why does the
> code above work?
>
> And is it safe to use unsafeCoerce like this?
>
> Thanks,
> Cosmia Fu
> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.



-- 
brandon s allbery kf8nh
allbery.b at gmail.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20180813/47974889/attachment.html>


More information about the Haskell-Cafe mailing list