haskell / haskell/core-libraries-committee

Remove `sizeOf (undefined :: a)` pattern from classes in base

Open
#435 36 comments 2 reactions 0 assignees View on GitHub
Dominant language
Haskell
Stars
109
Forks
20
PR merge metrics
No merged PRs in 30d

Description

# Motivation
The current pattern for figuring out a class-wide value is having a function in that class which takes an argument and ignores it, and passing it `undefined` set to that type. However, this is bad because it allows users to write instances which inspect their arguments and return different values for different inputs, and error on being passed `undefined`. We should make illegal states unrepresentable whenever possible.

# Proposal
Classes with these properties should have methods which visibly do not refer to their argument. This can be accomplished in several ways:

```haskell
-- proxy method
sizeOfP :: p a -> Int
-- Tagged value (requires bringing in the tagged package)
sizeOfT :: Tagged a Int
-- Const value
sizeOfC :: Const Int a
```

These have different benefits and drawbacks, and the choice should be decided on democratically. I prefer the `Const` method, because once the value in the dictionary is evaluated, it's evaluated forever.

# Process
Suppose we go with the `Const` method. This will cause these methods to be added to the class, the `MINIMAL` pragma updated, and they'll be given defaults like so:

```haskell
sizeOfC :: Const Int a
sizeOfC = Const (sizeOf (undefined :: a))

sizeOf :: a -> Int
sizeOf _ = getConst (sizeOfC :: Const Int a)
```

After a while (at least a major version number change), the versions which take `undefined` will be deprecated. After another while, they'll be moved out of the class and become normal methods:

```haskell
sizeOf :: forall a. Storable a => a -> Int
sizeOf _ = getConst (sizeOfC :: Const Int a)
```

I feel like eventually they should be eliminated.

# Impact
The following classes and methods that I've found are impacted:
* `Data.Bits.Bits`: `bitSizeMaybe`, `bitSize`, `isSigned`
* `Data.Bits.FiniteBits`: `finiteBitSize`
* `Foreign.Storable`: `sizeOf`, `alignment`
* `Prelude.RealFloat`: `floatRadix`, `floatDigits`, `floatRange`

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reading the class and method definitions in Data.Bits.Bits, Data.Bits.FiniteBits, Foreign.Storable, and Prelude.RealFloat. Compare the proxy, Tagged, and Const approaches against their defaults, MINIMAL pragmas, and compatibility implications. Done means the project has a decided approach and an agreed migration and deprecation plan for all listed methods.

Written by the indexing model from the issue text.

Assessment

Tech stack
haskell
Domain
backend-api-design
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.