Skip to content
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

Refuse to derive NoThunks for single-constructor-single-field types #25

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

edsko
Copy link
Contributor

@edsko edsko commented Dec 14, 2022

See detailed discussion both in #24 and inline in the code in the discussion of GCheckEdgeCase. After this PR, trying to define NoThunks for a single-constructor-single-field type such as

 data UserDefA = UserDefA Int
  deriving (Generic)

will result in a custom error message like this:

test/Test/NoThunks/Class.hs:342:10: error:
    • Cannot derive NoThunks for UserDefA
      Due to a limitation of GHC.Generics, NoThunks cannot be
      derived for single-constructor-single-field types.
      Consider writing it by hand, perhaps like this: 
        instance NoThunks UserDefA where
          wNoThunks ctxt (UserDefA x) = noThunks ctxt x

It's somewhat frustrating that we cannot do better, but this is what we have for now (unless we switch to TH deriving instead of using generics).

Closes #24.

The default implementation of `wNoThunks` translates its argument to
a generic representation, _then forces that generic representation to
WHNF_, and then calls `gwNoThunks`. This is wrong; given a datatype with
a single constructor with a single field

```
data T = MkT Int
```

the generic representation of `MkT x` is `M1 (M1 (K1 x))`, where `M1`
and `K1` are both newtypes. This means that forcing the representation
to WHNF means we would force the `Int` to WHNF, which is incorrect:
calling `noThunks` should never force any values to WHNF that aren't
already.

Admittedly, this is an edge case, but I think the forcing to WHNF
is simply not required: the implementation of `gwNoThunks` does not rely
on it.

This commit does not fix the problem, only adds the test case that
illustrates it.
This doesn't change anything fundamentally, but it avoids giving the
impression that that forcing actually does anything useful, which it
does not.
@edsko
Copy link
Contributor Author

edsko commented Dec 14, 2022

It would be good if this could be checked against a larger code, just to verify that I didn't miss any instances for GCheckEdgeCase.

@edsko edsko changed the title Refuse to define NoThunks for single-constructor-single-field types Refuse to derive NoThunks for single-constructor-single-field types Dec 14, 2022
@coot
Copy link
Contributor

coot commented Mar 27, 2023

@edsko have you ever tested this against a larger code base?

@edsko
Copy link
Contributor Author

edsko commented Mar 27, 2023

@edsko have you ever tested this against a larger code base?

No, but you are in the perfect place to do so 😬

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

Generic instance does not work for single-constructor-single-argument types
2 participants