Skip to content

Deprecate partial functions from the Prelude, giving them new quarantined homes #70

Closed
@Ericson2314

Description

@Ericson2314

Problem

Partial functions like head are too easy to use. The purpose of the Prelude is to guide the user, to make certain things very easy in order to encourage Haskell to be written in a certain way. The problem is that the partial functions are bad, as is widely agreed. It is unclear if there are any circumstances in which as they ought to be used, and yet Prelude makes them extremely easy to use at present, especially by new users that don't know what pattern matching is.

Many would-be solutions have been floated in the past, but I dislike them as tepid half-measures that skirt around the problem rather than confront it head on. The problem is that these partial functions are too readily available; the solution must be to make them less readily available. The solution is to make using those in the Prelude automatically raise red flags, and ideally to someday remove them from the Prelude altogether.

Solution

We want to move these functions with a very long deprecation cycle.

Prerequisite

https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0134-deprecating-exports-proposal.rst must be implemented first.

Steps

1. Relocate functions, with reexports

This we can do immediately!

  • Create Partial modules and move functions there:

    • Data.List.head -> Data.List.Partial.head
    • Data.List.tail -> Data.List.Partial.tail
    • Data.Maybe.fromJust -> Data.Maybe.Partial.fromJust
    • ...TODO fill out more
  • Create non-deprecated reexports (since we lack the ability to do anything better) in their current locations (Data.List, Data.Maybe, etc.).

The purpose of this is allowing one to switch sooner once the deprecation mechanism is ready without running afoul of the 3 release cycle.

2. Deprecate Reexports

This we can do once the GHC proposal is implemented.

  • Deprecate the reexports of these function in their Prelude reexports those and thus inherits the deprecation.

3. (Non-normative) After many releases, and good tooling, consider removing reexports

We're not sure what is needed to do this, so just including as an aspirational goal / food for thought.
At the very least, this could only happen after:

  • 3 release policy is met, so we must have both 3 past GHCs and bases which have these functions available from the the Partial modules. (probably would be far more than 3 releases.)

  • Tooling exists to automatically perform migration guide

  • Perhaps also some sort of "base shim" so code explicitly depending on the old standard library (as opposed to say Haskell just dropped in GHCi without metadata) never stops working.

It is important to remember that not everyone that signs up to publish open source wants to be stuck maintaining it for life. Some people want to make a thing, release it, and wash their hands of it ---- think e.g. artists aren't expected to accept "patches" against a finished painting! Any hard breakage, no matter the migration tooling around it is going to to result in people pestering those once and done authors who will rightly ask "why is stuff in the language report for crying out loud changing out from under on me?"

For that use-case, only something like the base-shim that requires no changes in existing code --- essentially making this not a breakage change but just changing the defaults for new projects --- is acceptable. Indeed a social contract that a) we can and will retroactively add more and more warnings to old standards b) we will never change the meaning of old standards, is probably a good way to navigate these competing concerns in general.

Migration Guide

Merely import and ...Migration module that provides an in-use function gotten from a legacy deprecated location.

Note these properties:

  • Qualification is not necessary. One may choose to do e.g. import qualified Data.List.Partial as Partial, but import Data.List.Partial is fine.
  • Manual Prelude import is not necessary. One may choose to do e.g. import Prelude hiding (head), but this line can be omitted entirely.
  • Import lists are not necessary. One may choose to do e.g. import Data.List.Partial (head), but import Data.List.Partial is fine.

These properties follow from the nice benefits deprecated reexports provide, benefits we do not have with today's means of doing a deprecation cycle.

Metadata

Metadata

Assignees

No one assigned

    Labels

    awaits-ghc-proposalBlocked on an unimplemented GHC proposal (https://github.com/ghc-proposals/ghc-proposals)dormantHibernated by proposer or committee

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions