#3480: Easily make Typeable keys  pure, so that Typeable can be handled
efficiently across communications
-------------------------------------+--------------------------------------
    Reporter:  guest                 |        Owner:                  
        Type:  task                  |       Status:  new             
    Priority:  normal                |    Milestone:  6.14.1          
   Component:  libraries/base        |      Version:                  
    Severity:  trivial               |   Resolution:                  
    Keywords:  Typeable, efficiency  |   Difficulty:  Unknown         
    Testcase:                        |           Os:  Unknown/Multiple
Architecture:  Unknown/Multiple      |  
-------------------------------------+--------------------------------------
Old description:

> Data.Typeable:  Easily make Typeable keys  pure(used in Eq), so that
> Typeable keys don´t vary from run to run. This permits an efficient
> storage of the keys in files and to be transmitted trough communications
> as well as processed without loss of efficiency. Actually gaining
> efficiency probably, since the keys caches are not necessary.
>
> Currently, whenever the user needs to communicate types, he must transmit
> the full string name for each type. Moreover, in the reception, the
> programmer  is forced to handle these full string keys for mapping types
> to handlers, in equality checks etc. if the type keys are pure, the
> efficiency of key handling can be keept across communications.
>
> short description of task:
> Istead of using a Hash( stringType, generatedKey) use  hashString
> (string-of-type)
>
> Long description:
>
> 1) drop the cache
> drop newKey
>
> 2) use instead  the expression:
>
>  Key $ hashString str
>
> whenever a new key is needed
>
> from the package Data.HashTable:
> hashString :: String -> Int
>
> the key obtained is pure so:
>
> 3) drop the "IO" in typeRepKey signature

New description:

 Data.Typeable:  Easily make Typeable keys  pure(used in Eq), so that
 Typeable keys don´t vary from run to run. This permits an efficient
 storage of the keys in files and to be transmitted trough communications
 as well as processed without loss of efficiency. Actually gaining
 efficiency probably, since the keys caches are not necessary.

 Currently, whenever the user needs to communicate types, he must transmit
 the full string name for each type. Moreover, in the reception, the
 programmer  is forced to handle these full string keys for mapping types
 to handlers, in equality checks etc. if the type keys are pure, the
 efficiency of key handling can be keept across communications.

 short description of task:
 Istead of using a Hash( stringType, generatedKey) use  hashString (string-
 of-type)

 Long description:

 1) drop the cache; drop newKey

 2) use instead  the expression:
 {{{
  Key $ hashString str
 }}}
 whenever a new key is needed from the package `Data.HashTable`:
 {{{
 hashString :: String -> Int
 }}}
 the key obtained is pure so:

 3) drop the "IO" in `typeRepKey` signature

Comment (by simonpj):

 Something that does a better job of `TypeRep` would certainly be welcome:

   1. Those `unsafePerformIO`s are embarrassing.  And indeed they lead to
 trouble if (as can happen in GHCi or Template Haskell) you get two
 instances of that hash table.

   2. If you were (naughtily) to serialise one of those keys into a file,
 they'd be wrong when you read them back in.  But this never happens (see
 the `Show` instance for `TypeRep`: what you serialise is the `TypeRep`
 data structure ''without'' the keys.  When it's read back in a new set of
 keys is constructed.  (Actually there is no `Read` instance but that is
 what would happen if there were.)

 The keys are ''solely'' used to speed up comparison.  Comparing the data
 structures and strings is the underlying ground truth.  So it's perfectly
 fine for keys to vary from run to run.

 However, it's vital that if two `TypeRep`s with the same key really are
 equal.  Hashing the string to an `Int` does not guarantee that.  To be
 sure, you'd need a lot more bits, something like the fingerprints we store
 in interface files.  See `compiler/utils/Fingerprint.hsc`.

 I'm not sure about the best approach.  The baseline is:
   * Compare `TypeRep` structures as one would any data structure.
   * At a `TyCon` compare the `String` representation of the type
 constructor.

 An alternative, that would do the fingerprint stuff once and for all at
 compile time, is:
   * Compare `TypeRep` structures as one would any data structure.
   * At a `TyCon` compare the fingerprint of the string representation of
 the `TyCon`

 Neither of these give constant-time comparison of `TypeRep`s, but I doubt
 that such comparisons are going to be in the inner loop of any program.
 And both fix (1) above

 Other things to think about:
   * Surely `TypeRep` should be in `Ord`!

   * We should check that the `String` used to make a `Typeable.TyCon`
 includes the full, versioned, package Id.

   * Even then I'm slightly worried.  The expection is that `foo-3.2:Foo.T`
 uniquely defines the entire structure of `T`. But what if you forget to
 bump the package version?

   * More subtly  what if `T` is defined thus:
 {{{
 data T = MkT S   -- S comes from package bar
 }}}
     Then if S's definition in package `bar` changes, but package `foo` is
 unchanged, the `TyCon` for `T` should really change too.  Otherwise you
 might serialise a value of type `T` into a file along with its `TypeRep`,
 and try to read it back in with the wrong deserialiser.  I'm not sure
 whether the package versioning rules force `foo`'s version to be bumped.
 Maybe we want `foo`'s new `PackageId`?

   * But in fact the `PackageId` is perhaps ''too'' fine-grained, becuase
 it changes whenever anything in package `foo` changes.  We really only
 want the `Typeable.TyCon` for `T` to change when the structure of `T`
 (transitively) changes.  Aha!  We already have fingerprints for that, used
 for versioning in interface files.  So perhpas, once we've calculated
 `T`'s fingerprint we can use that in the `Typeable.TyCon` for `T`.  That
 seems to me to be best story.

 We could do with someone who'd like to follow these things up.  Dynamic
 typing is important.

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/3480#comment:2>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
_______________________________________________
Glasgow-haskell-bugs mailing list
Glasgow-haskell-bugs@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to