17

Assume I created a type as follows:

data RequestAck = 
         RequestAck { ackOK :: Word32, ackMsgCode :: Word32 } 

I can see that it is 2 * 4 bytes big and make that a constant somewhere.

The only problems is that once I add a field to the type, I'd have to remember to update my constant.

Is there a function out there that will provide me with the size of a given type e.g., t -> Int?

The function that comes close to what I want is

gsize :: Data a => a -> Int

inside the Data.Generics.Schemes module, but I don't want to have to make my type an instance of Data.

Is there a more generic solution out there?

To be sure, I'm looking for a function that operates on the static type, e.g., I don't want to pass an instance, but the type itself.

Thorsten Lorenz
  • 11,293
  • 6
  • 48
  • 58
  • 3
    Hint: It isn't 2*4 bytes big. The fields are boxed. – Thomas M. DuBuisson Feb 29 '12 at 02:55
  • 1
    Good point. In my case I pull out the words and convert them to a bytestring which ends up being 2*4 bytes long. So in retrospect getting size of the type wouldn't make much sense for me because of that. – Thorsten Lorenz Feb 29 '12 at 03:48
  • 2
    "Memory footprint of Haskell data types": http://stackoverflow.com/questions/3254758/memory-footprint-of-haskell-data-types, also "How to find out GHC's memory representations of data types" http://stackoverflow.com/questions/6574444/how-to-find-out-ghcs-memory-representations-of-data-types – Simon Marlow Feb 29 '12 at 12:19
  • Thanks, I didn't find these questions previously since the wording is so different. – Thorsten Lorenz Feb 29 '12 at 16:01
  • Sounds to me like you want to make a [Bits](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Bits.html#t:Bits) instance: `bitSize :: a -> Int` "Return the number of bits in the type of the argument. The actual value of the argument is ignored." – Dan Burton Feb 29 '12 at 18:49
  • Can you use `sizeOf (undefined :: Word16)`? – CMCDragonkai Apr 06 '19 at 07:14

2 Answers2

15

This really depends on how you're turning this into bytes.

As a Word32, there is no fixed size. What you see as a Word32 could be an unapplied closure taking up hundreds of megabytes of space. Or it could be a simple boxed type (which would be larger than 4 bytes). Or it could be some kind of inline tagged type (in which case it depends on the platform). Or it could be elided (in which case it doesn't exist).

The only time when you can really say what size something like this is is when you convert to binary. If you're doing this to interface with the FFI, you can use the sizeOf member of Foreign.Storable. Of course, you need to write a Storable instance for your type if you want to just apply sizeOf directly to it. If you're serializing via Data.Binary... well, just serialize the thing, really. You usually don't need to know the actual size beforehand (and if you do for a size header, just serialize the body you're counting the size of into a temporary lazy bytestring, then take the size, then write the size and temp bytestring).

bdonlan
  • 205,037
  • 27
  • 244
  • 316
  • 2
    According to your suggestion to measure actual ByteString size, I changed my server/client protocol to prefix each binary message with a word that contains the size of the ByteString that follows (which I measure beforehand). Thanks for that insight. – Thorsten Lorenz Mar 01 '12 at 03:06
3

bitSizeMaybe and finiteBitSize from Data.Bits provide the size in bits. They supersede bitSize from the same module.

finiteBitSize :: b -> Int

Return the number of bits in the type of the argument. The actual value of the argument is ignored.

finiteBitSize = bitSize
bitSizeMaybe = Just . finiteBitSize

Example usage:

> import Data.Bits
> finiteBitSize (42 :: Int)
64
wsaleem
  • 554
  • 7
  • 25