Implementation of "Dynamic" datatype

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Currently we have data Dynamic = Dynamic TypeRep Obj where Obj is {-in GHC up to 6.6-} type Obj = forall a . a {-in GHC 6.7.something-} type Obj = Any -- Use GHC's primitive 'Any' type to hold the dynamically typed value. {-in some other compilers (like Hugs)-} data Obj = Obj ( According to this comment, it is not data Obj = Obj in GHC now because: -- In GHC's new eval/apply execution model this type must not -- look like a data type. If it did, GHC would use the -- constructor convention when evaluating it, and this will go -- wrong if the object is really a function. Using Any [or, -- earlier comments said, a polymorphic type] forces GHC to use -- a fallback convention for evaluating it that works for all -- types. ) So, my question is: why doesn't it just use an existential? : data Dynamic = forall a. Dynamic TypeRep a According to http://hackage.haskell.org/trac/haskell-prime/wiki/HaskellExtensions , all important implementations support existentials (and it will probably go into Haskell'). It seems semantically the most accurate, doesn't require an unsafeCoerce when _constructing_ a Dynamic, and doesn't require unsafeCoercing between unequal types (which had caused problems in GHC as noted above), so it seems like it could be a portable implementation. A quick copy of Dynamic.hs with these modifications seemed to work fine in ghc6.4.2, ghc6.6, and hugs20050308 (which is all haskell implementations that are working for me at the moment (nhc98 is broken for me) and that have Data.Typeable (not yhc currently, it seems)). ( Also I wonder about the performance implications of changing it to data Dynamic = forall a. Typeable a => Dynamic a or making the TypeRep be a strict field (which shouldn't have any semantic impact since typeOf always succeeds(assuming no-one defines a horrible instance of Typeable) and typeOf's result is always what is put into that field. (Separately, should seq'ing a Dynamic seq the encapsulated object, or should Dynamic act as a box as it does now?)). ) Anyway, how would I go about seriously testing this in ghc, hugs... to see if it breaks anything (and also see how it affects Dynamic's performance)? (Since I am interested in the refactoring of the base/core libraries, a little something like this seems like a good place to start learning how to test what I have.) Isaac - - Was this a good mailing list to choose for this question? (And was it a good question? what about all the little question-ideas branching off of it? I can never be sure...) -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.3 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFF6LVSHgcxvIWYTTURAoeTAKCP8XIn4pVXnJsimEX8aAgIcXLb1ACbBOw2 elKn59TdPKiAJq8VA4MOd0o= =NF4R -----END PGP SIGNATURE-----

the current type: data Dynamic = Dynamic TypeRep Obj the new type, if lucky: data Dynamic = Dynamic !(a -> TypeRep) a if unlucky: data TypeableD a = TypeableD (a -> TypeRep) data Dynamic = Dynamic (TypeableD a) a either way, the typeclass approach gives a lot more boxing.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Stefan O'Rear wrote:
the current type:
data Dynamic = Dynamic TypeRep Obj
the new type, if lucky:
Meaning the one with "Typeable a =>" instead of TypeRep?
data Dynamic = Dynamic !(a -> TypeRep) a
if unlucky:
data TypeableD a = TypeableD (a -> TypeRep) data Dynamic = Dynamic (TypeableD a) a
either way, the typeclass approach gives a lot more boxing.
Yes, that's why I don't really propose that, because it's probably inefficient (for dictionary-passing-based implementations anyway), just that the "Obj" in Dynamic's constructor should be, type-system-wise, an existential instead (which I don't think will change the runtime representation, but I don't know how to test that). Isaac -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.3 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFF6Lz4HgcxvIWYTTURAggEAKCdexJu4irOk2CiIfLfyatJfzIrgACgzokb kTlzxONc+tL+i5IJIkShMqk= =H/tO -----END PGP SIGNATURE-----

On Fri, Mar 02, 2007 at 07:10:32PM -0500, Isaac Dupree wrote:
Stefan O'Rear wrote:
the current type:
data Dynamic = Dynamic TypeRep Obj
the new type, if lucky:
Meaning the one with "Typeable a =>" instead of TypeRep?
Yes
data Dynamic = Dynamic !(a -> TypeRep) a
if unlucky:
data TypeableD a = TypeableD (a -> TypeRep) data Dynamic = Dynamic (TypeableD a) a
either way, the typeclass approach gives a lot more boxing.
Yes, that's why I don't really propose that, because it's probably inefficient (for dictionary-passing-based implementations anyway), just that the "Obj" in Dynamic's constructor should be, type-system-wise, an existential instead (which I don't think will change the runtime representation, but I don't know how to test that).
-ddump-cmm, and a 10x magnifying glass. Stefan

Why would there be an extra function? The type data Dynamic = forall a . Dynamic TypeRep a is simply a pair. And so is data Dynamic = forall a . (Typeable a) => Dynamic a I think the latter is the most natural representation for Dynamic. -- Lennart On Mar 2, 2007, at 23:55 , Stefan O'Rear wrote:
the current type:
data Dynamic = Dynamic TypeRep Obj
the new type, if lucky:
data Dynamic = Dynamic !(a -> TypeRep) a
if unlucky:
data TypeableD a = TypeableD (a -> TypeRep) data Dynamic = Dynamic (TypeableD a) a
either way, the typeclass approach gives a lot more boxing. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Sat, Mar 03, 2007 at 09:18:00AM +0000, Lennart Augustsson wrote:
Why would there be an extra function?
The type data Dynamic = forall a . Dynamic TypeRep a is simply a pair. And so is data Dynamic = forall a . (Typeable a) => Dynamic a I think the latter is the most natural representation for Dynamic.
-- Lennart
On Mar 2, 2007, at 23:55 , Stefan O'Rear wrote:
the current type:
data Dynamic = Dynamic TypeRep Obj
the new type, if lucky:
data Dynamic = Dynamic !(a -> TypeRep) a
if unlucky:
data TypeableD a = TypeableD (a -> TypeRep) data Dynamic = Dynamic (TypeableD a) a
either way, the typeclass approach gives a lot more boxing.
Because the compiler can't statically prove that the typeRep field of the dictionary doesn't depend on its argument. Therefore, the function cannot be unpacked. (Or can it? Could hbc?) Stefan

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Stefan O'Rear wrote:
Why would there be an extra function? Because the compiler can't statically prove that the typeRep field of
On Sat, Mar 03, 2007 at 09:18:00AM +0000, Lennart Augustsson wrote: the dictionary doesn't depend on its argument. Therefore, the function cannot be unpacked. (Or can it? Could hbc?)
Unfortunately it would be difficult for the compiler to know that no-one is going to make an instance that does depend on its argument (as long as it does not do full-program analysis to determine the layout of data structures). Maybe there should be some sort of annotation on class method arguments that are supposed to be ignored, even if only a pragma, if it would help compilers figure this out. Isaac -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.3 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFF6Xa8HgcxvIWYTTURAlQsAKDEmR2J5nls66JQKV9DhN+p8lJPBwCgjvlD aHyhsMn/OWoO2hUT390L0AQ= =/RRh -----END PGP SIGNATURE-----

I have no idea what function you are talking about. I must be missing your point. Here's a version of Dynamic that seem to compile and work fine. {-# OPTIONS_GHC -fglasgow-exts #-} module Dyn(Dynamic, toDyn, fromDyn) where import GHC.Base(unsafeCoerce#) import Data.Typeable data Dynamic = forall a . Dynamic TypeRep a toDyn :: (Typeable a) => a -> Dynamic toDyn v = Dynamic (typeOf v) v fromDyn :: (Typeable a) => Dynamic -> a -> a fromDyn (Dynamic t v) def | typeOf def == t = unsafeCoerce# v | otherwise = def And here is another one {-# OPTIONS_GHC -fglasgow-exts #-} module Dyn1(Dynamic, toDyn, fromDyn) where import GHC.Base(unsafeCoerce#) import Data.Typeable data Dynamic = forall a . (Typeable a) => Dynamic a toDyn :: (Typeable a) => a -> Dynamic toDyn v = Dynamic v fromDyn :: (Typeable a) => Dynamic -> a -> a fromDyn (Dynamic v) def | typeOf def == typeOf v = unsafeCoerce# v | otherwise = def -- Lennart On Mar 3, 2007, at 09:29 , Stefan O'Rear wrote:
On Sat, Mar 03, 2007 at 09:18:00AM +0000, Lennart Augustsson wrote:
Why would there be an extra function?
The type data Dynamic = forall a . Dynamic TypeRep a is simply a pair. And so is data Dynamic = forall a . (Typeable a) => Dynamic a I think the latter is the most natural representation for Dynamic.
-- Lennart
On Mar 2, 2007, at 23:55 , Stefan O'Rear wrote:
the current type:
data Dynamic = Dynamic TypeRep Obj
the new type, if lucky:
data Dynamic = Dynamic !(a -> TypeRep) a
if unlucky:
data TypeableD a = TypeableD (a -> TypeRep) data Dynamic = Dynamic (TypeableD a) a
either way, the typeclass approach gives a lot more boxing.
Because the compiler can't statically prove that the typeRep field of the dictionary doesn't depend on its argument. Therefore, the function cannot be unpacked. (Or can it? Could hbc?)
Stefan

Yes, Dynamic preceded the Typeable class, I think. Were we to do it today, I think we'd have | data Dynamic = forall a . (Typeable a) => Dynamic a Whether it's worth changing, I'm not sure. It's a library so, if a change desirable, anyone could take a lead. Simon | -----Original Message----- | From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-bounces@haskell.org] On Behalf Of | Lennart Augustsson | Sent: 03 March 2007 21:04 | To: Stefan O'Rear | Cc: Haskell-cafe | Subject: Re: [Haskell-cafe] Implementation of "Dynamic" datatype | | I have no idea what function you are talking about. I must be | missing your point. | | Here's a version of Dynamic that seem to compile and work fine. | | {-# OPTIONS_GHC -fglasgow-exts #-} | module Dyn(Dynamic, toDyn, fromDyn) where | import GHC.Base(unsafeCoerce#) | import Data.Typeable | | data Dynamic = forall a . Dynamic TypeRep a | | toDyn :: (Typeable a) => a -> Dynamic | toDyn v = Dynamic (typeOf v) v | | fromDyn :: (Typeable a) => Dynamic -> a -> a | fromDyn (Dynamic t v) def | | typeOf def == t = unsafeCoerce# v | | otherwise = def | | And here is another one | | {-# OPTIONS_GHC -fglasgow-exts #-} | module Dyn1(Dynamic, toDyn, fromDyn) where | import GHC.Base(unsafeCoerce#) | import Data.Typeable | | data Dynamic = forall a . (Typeable a) => Dynamic a | | toDyn :: (Typeable a) => a -> Dynamic | toDyn v = Dynamic v | | fromDyn :: (Typeable a) => Dynamic -> a -> a | fromDyn (Dynamic v) def | | typeOf def == typeOf v = unsafeCoerce# v | | otherwise = def | | -- Lennart | | On Mar 3, 2007, at 09:29 , Stefan O'Rear wrote: | | > On Sat, Mar 03, 2007 at 09:18:00AM +0000, Lennart Augustsson wrote: | >> Why would there be an extra function? | >> | >> The type | >> data Dynamic = forall a . Dynamic TypeRep a | >> is simply a pair. And so is | >> data Dynamic = forall a . (Typeable a) => Dynamic a | >> I think the latter is the most natural representation for Dynamic. | >> | >> -- Lennart | >> | >> On Mar 2, 2007, at 23:55 , Stefan O'Rear wrote: | >> | >>> the current type: | >>> | >>> data Dynamic = Dynamic TypeRep Obj | >>> | >>> the new type, if lucky: | >>> | >>> data Dynamic = Dynamic !(a -> TypeRep) a | >>> | >>> if unlucky: | >>> | >>> data TypeableD a = TypeableD (a -> TypeRep) | >>> data Dynamic = Dynamic (TypeableD a) a | >>> | >>> either way, the typeclass approach gives a lot more boxing. | > | > Because the compiler can't statically prove that the typeRep field of | > the dictionary doesn't depend on its argument. Therefore, the | > function cannot be unpacked. (Or can it? Could hbc?) | > | > Stefan | | _______________________________________________ | Haskell-Cafe mailing list | Haskell-Cafe@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-cafe

On Fri, Mar 09, 2007 at 03:40:07PM +0000, Simon Peyton-Jones wrote:
Yes, Dynamic preceded the Typeable class, I think. Were we to do it today, I think we'd have
| data Dynamic = forall a . (Typeable a) => Dynamic a
Whether it's worth changing, I'm not sure. It's a library so, if a change desirable, anyone could take a lead.
I think data Dynamic where Dynamic :: a -> TypeRep -> Dynamic would be better, as it would cache the TypeRep for fast equality, while the 'Typeable' version would perhaps have to go through a dictionary lookup to get at it. John -- John Meacham - ⑆repetae.net⑆john⑈

| I think | | data Dynamic where | Dynamic :: a -> TypeRep -> Dynamic | | would be better, as it would cache the TypeRep for fast equality, while | the 'Typeable' version would perhaps have to go through a dictionary | lookup to get at it. But the dictionary would presumably contain a cached version, since the result is independent of the argument. So I doubt this is a big issue in practice. Simon
participants (5)
-
Isaac Dupree
-
John Meacham
-
Lennart Augustsson
-
Simon Peyton-Jones
-
Stefan O'Rear