Lazy vs Strict ByteStrings

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

Lazy vs Strict ByteStrings

Dimitri DeFigueiredo
I just noticed that I avoid using ByteStrings because I tend to spend a
huge amount of time reading GHC output and trying to figure out if I
am/should be using the strict or the lazy version. I have to use both
lazy/strict because different libraries use different versions. Maybe
having different names would have helped.

Am I doing something wrong or is the interface to ByteStrings a poor design?

Cheers,

Dimitri

--
2E45 D376 A744 C671 5100 A261 210B 8461 0FB0 CA1F


_______________________________________________
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.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Lazy vs Strict ByteStrings

Dimitri DeFigueiredo
I think I need to be more specific here.

My gripe with ByteString is that there are two distinct ByteString types
disguised as one. There are “disguised” simply by having the same name.
This leads me to think the use of ByteString will be simpler than it
usually turns out to be. I fear Backpack may soon make this worse.

Obviously, this is not exclusive to ByteString. Using the same name for
strict and lazy versions is all over the place. Here is another example:

https://hackage.haskell.org/package/unordered-containers/docs/Data-HashMap-Lazy.html
https://hackage.haskell.org/package/unordered-containers/docs/Data-HashMap-Strict.html

But the problem is specially insidious with BytStrings because of their
usage patterns and also because the process of finding out which version
is which through GHC error messages is very inefficient.

Here is a very ugly example where I believe I was misled by both
ByteString types having the same name.

I needed to make a “random looking but secretly not random” number and
package it up in a 128-bit UUID. In other words, I wanted to mark the
random numbers I create, but in a way that nobody else knows they are mine.

The `hash` function from the cryptonite library accepts ByteString and
its output can be converted to ByteString.
The UUID type also has a function `fromByteString`.
What could be easier?

Here’s what I ended up with:

import           System.Random
import           Data.Maybe
import           Data.Word

import           Data.UUID
import           Crypto.Hash
import           Crypto.Hash.Algorithms

import           Data.ByteArray
import           Data.ByteString.Builder
import qualified Data.ByteString            as BS
import           Data.ByteString.Lazy       as BSL

-- Ugly! Step-by-step
markAsSelf :: Word64 -> Word64 -> UUID
markAsSelf selfDetectKey rand =
  let selfKeyAsLazyBS   = toLazyByteString (word64BE selfDetectKey)
      randAsLazyBS      = toLazyByteString (word64BE rand)
      hashInput         = BSL.concat [randAsLazyBS, selfKeyAsLazyBS]
      digest            = hash (toStrict hashInput) :: Digest SHA256
      hashBitsStrict    = BS.take 8  (convert digest)
      halfAndHalf       = BSL.concat [randAsLazyBS, fromStrict
hashBitsStrict]
   in fromJust (fromByteString halfAndHalf)


secret :: Word64
secret = 12345

main = do
  r <- randomIO
  print (markAsSelf secret r)

--------- end ---------

in Data.ByteString.Builder

toLazyByteString   :: Builder -> ByteString -- exists
toStrictByteString :: Builder -> ByteString -- was not found

Similarly, in Data.UUID

fromByteString :: ByteString -> Maybe UUID  — only exists for lazy

I think this lack of a common interface makes the code above a type
conversion disaster and the process of debugging it painfully
inefficient. Is there a better approach to go about doing this?


Cheers,


Dimitri


--
2E45 D376 A744 C671 5100 A261 210B 8461 0FB0 CA1F


_______________________________________________
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.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Lazy vs Strict ByteStrings

ALeX Kazik
Hi,

> Obviously, this is not exclusive to ByteString. Using the same name for
> strict and lazy versions is all over the place. Here is another example:
>
> https://hackage.haskell.org/package/unordered-containers/docs/Data-HashMap-Lazy.html
> https://hackage.haskell.org/package/unordered-containers/docs/Data-HashMap-Strict.html

HashMaps and Maps lazy and strict do have the same type! Only the
function which work on them are different.
Yes, you can use a Data.HashMap.Lazy.HashMap with the
Data.HashMap.Strict functions.

Text however has a different type for lazy and strict (like ByteString).

And yes, I agree that it's confusing.

ALeX.
_______________________________________________
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.
Loading...