# Proposal: StricterLabelledFieldSyntax

 Ticket #132 Dependencies none Related none

## Compiler support

 GHC partial (test patch available) nhc98 none Hugs none UHC none JHC none LHC none

## Summary

Make the labelled field syntax stricter, so that unclear code is illegal.

```data A = A {x :: Int}

y :: Maybe A
y = Just A {x = 5}
```

you would need to write:

```data A = A {x :: Int}

y :: Maybe A
y = Just (A {x = 5})
```

## Description

Many people believe that the precedence of labelled fields creation, updates and pattern matching can lead to confusing code. For example, in  http://hackage.haskell.org/trac/ghc/ticket/2530 it was reported that this program:

```module Main where

data A = A {x :: Int} deriving (Show)

main :: IO ()
main = print \$ Just A {x = 5}
```

(correctly, according to Haskell 98) prints

```Just A {x = 5}
```

in hugs, but the more easily comprehendible

```Just (A {x = 5})
```

in ghci.

```A {x = 5}
```

is an atomic expression - but it doesn't look atomic! This violates the principle of least surprise.

Before coming across labelled fields, but having had "function application binds tightest" drummed into you to understand how to read expressions containing a mixture of applications and infix operators, of the following 2 functions:

```data A = A {x :: Bool} deriving (Show)

f = print \$ Just A {x = True}
g = print \$ A True {x = False}
```

I would expect g to be the correct one, while it is f that is correct according to Haskell 98.

However, once you remove the space before the curly brace:

```h = print \$ Just A{x = True}
i = print \$ A True{x = False}
```

it is h that looks more correct. Note that we have a similar problem with infix operators, and expressions like

```1+f x+2
```

I propose that all of f, g, h and i be made illegal, with parentheses being required to disambiguate these cases.

No additional programs are accepted by this change, and no programs have their behaviour changed. This change only rejects some programs that were previously accepted.

Here are some real-life examples of what I consider confusing code, from haskeline:

```metaKey :: Key -> Key
metaKey (Key m bc) = Key m {hasMeta = True} bc
```
```searchText :: SearchEntry -> [Grapheme]
searchText SearchEntry {entryState = IMode xs ys} = reverse xs ++ ys
```

and from Cabal:

```configure ... = do
...
(ghcPkgProg, ghcPkgVersion, conf'') <-
requireProgramVersion verbosity ghcPkgProgram {
programFindLocation = guessGhcPkgFromGhcPath ghcProg
}
anyVersion (userMaybeSpecifyPath "ghc-pkg" hcPkgPath conf')
...
```
```buildExe :: Verbosity -> PackageDescription -> LocalBuildInfo
-> Executable         -> ComponentLocalBuildInfo -> IO ()
buildExe verbosity _pkg_descr lbi
exe@Executable { exeName = exeName', modulePath = modPath } clbi = do
...
```
```      case PackageIndex.lookupPackageName index (PackageName "rts") of
[rts] -> PackageIndex.insert rts { Installed.ldOptions = [] } index
```
```register pkg@PackageDescription { library       = Just lib  }
lbi@LocalBuildInfo     { libraryConfig = Just clbi } regFlags
= ...
```

## Result

There was not a consensus to make this change.

## References

A patch to add support for the syntax to GHC, as well as patches needed to fix GHC and the libraries to follow the new syntax, are in the ticket (#132).

This darcs patch is an example of real-world confusion caused by the current parsing:

```Sun Feb 21 12:59:33 GMT 2010  Eric Kow <kowey@darcs.net>
* Resolve issue1750: uncover help text for darcs show pristine.
f r { foo = bar } means           f (r { foo = bar })
whereas what we really wanted was (f r) { foo = bar }
```

## Report Delta

In  Section 3 replace:

```exp10 -> ...
| fexp
```

with:

```exp10 -> ...
| recexp
recexp -> qcon { fbind1 , ... , fbindn }        (labeled construction, n >= 0)
| aexp<qcon> { fbind1 , ... , fbindn }  (labeled update, n >= 1)
| fexp
```

and remove:

```aexp -> ...
| qcon { fbind1 , ... , fbindn }        (labeled construction, n>=0)
| aexp<qcon> { fbind1 , ... , fbindn }  (labeled update, n >= 1)
```

In  Section 3.15.2 replace:

```aexp -> qcon { fbind1 , ... , fbindn }        (labeled construction, n>=0)
```

with:

```recexp -> qcon { fbind1 , ... , fbindn }        (labeled construction, n >= 0)
```

In  Section 3.15.3 replace:

```aexp -> aexp<qcon> { fbind1 , ... , fbindn }  (labeled update, n >= 1)
```

with:

```recexp -> aexp<qcon> { fbind1 , ... , fbindn }  (labeled update, n >= 1)
```

In  Section 3.17.1 replace:

```pat10 -> ...
```

with:

```pat10 -> ...
| qcon { fpat1 , ... , fpatk }    (labeled pattern, k >= 0)
```

and remove:

```apat -> ...
| qcon { fpat1 , ... , fpatk }    (labeled pattern, k>=0)
```

In  Section 9.5 replace:

```exp10 -> ...
| fexp
```

with:

```exp10 -> ...
| recexp
recexp -> qcon { fbind1 , ... , fbindn }        (labeled construction, n >= 0)
| aexp<qcon> { fbind1 , ... , fbindn }  (labeled update, n >= 1)
| fexp
```

and remove:

```aexp -> ...
| qcon { fbind1 , ... , fbindn }        (labeled construction, n>=0)
| aexp<qcon> { fbind1 , ... , fbindn }  (labeled update, n >= 1)
```

and replace

```pat10 -> ...
```

with:

```pat10 -> ...
| qcon { fpat1 , ... , fpatk }    (labeled pattern, k >= 0)
```

and remove:

```apat -> ...
| qcon { fpat1 , ... , fpatk }    (labeled pattern, k>=0)
```