-
Notifications
You must be signed in to change notification settings - Fork 217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add labels to binary decoders for improved debugging #385
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The individual code changes look fine to me!
However, I can't help wondering if there isn't an approach we could use that doesn't involve repeating the name of each function (which is a kind of boilerplate).
For example, would it be enough to add HasCallStack
constraints to each of the functions we care about, instead of adding labels to them?
@@ -103,7 +104,8 @@ data SignedVote = SignedVote | |||
{-# ANN module ("HLint: ignore Use <$>" :: String) #-} | |||
|
|||
getBlockHeader :: Get BlockHeader | |||
getBlockHeader = (fromIntegral <$> getWord16be) >>= \s -> isolate s $ do | |||
getBlockHeader = label "getBlockHeader" | |||
$ (fromIntegral <$> getWord16be) >>= \s -> isolate s $ do | |||
version <- getWord16be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just nitpicking, but shouldn't this line (and the lines following it) be further indented by one block? Like this:
getBlockHeader = label "getBlockHeader" $
(fromIntegral <$> getWord16be) >>= \s -> isolate s $ do
version <- getWord16be
contentSize <- getWord32be
slotEpoch <- fromIntegral <$> getWord32be
slotId <- fromIntegral <$> getWord32be
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it?
I view this as
function = auxiliarySetup $ do
important
things
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would argue that this function is slightly different from the others though, as the first line is wrapped, which introduces an extra level of indentation.
Clearly, both of the variants below are valid Haskell syntax:
Variant 1:
getBlockHeader = label "getBlockHeader" $
(fromIntegral <$> getWord16be) >>= \s -> isolate s $ do
version <- getWord16be
contentSize <- getWord32be
slotEpoch <- fromIntegral <$> getWord32be
slotId <- fromIntegral <$> getWord32be
Variant 2:
getBlockHeader = label "getBlockHeader" $
(fromIntegral <$> getWord16be) >>= \s -> isolate s $ do
version <- getWord16be
contentSize <- getWord32be
slotEpoch <- fromIntegral <$> getWord32be
slotId <- fromIntegral <$> getWord32be
In my opinion, the extra indentation of variant 2 makes the code more readable, as it gives a visual indication of exactly where the do
block starts, i.e., that it is separate from the line starting (fromIntegral <$> getWord16be) >>= \s -> isolate s
.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes — I suppose 😄
I guess the extra indentation shattered my ability to ignore the (fromIntegral [...])
line, but that might have been 1) just because I was used to it, and 2) bad because it's obfuscating.
So I think this makes perfect sense. Thanks! 👍
352446a
to
cfef960
Compare
Thanks for the suggestion, @jonathanknowles!
I guessed we would have label' :: HasCallStack => Get a -> Get a
label' = Data.Binary.Get.label (someVariantOf prettyCallStack callStack)
getFoo :: HasCallStack => Get Foo
getFoo = label' $ do
... or am I missing some obvious use of it? And I kind of like the simplicity of Of course, it's possible to provide a misleading label… |
const' <- Quantity <$> getWord64be | ||
perByte <- Quantity <$> getWord64be | ||
perCert <- Quantity <$> getWord64be | ||
return $ LinearFee const' perByte perCert |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted to do-notation for consistency with the rest of the module, to show variable names, and separate order of the binary format with the order of the LinearFee
arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
separate order of the binary format with the order of the
LinearFee
arguments.
Fair enough!
cfef960
to
6cb662c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me.
As of discussion about making this more automatic with HasCallStack
and similar I would propose to add it to wiki Blackboard.
This already improves debugging information and we can make it more elegant if needed later
2189175
to
1543d98
Compare
1543d98
to
4fb7d9e
Compare
Overview
label
sComments
Previously:
Now: