Skip to content
Merged
Changes from 13 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8527193
Record names as reserved_words/Variables and new record definition sy…
choptastic Oct 9, 2024
adb4ffd
Fix small typos
choptastic Oct 9, 2024
a87bc7e
Fixing more typos
choptastic Oct 9, 2024
964d971
Fix 'receive' typo
choptastic Oct 9, 2024
83ccc12
EEP-0072: Fix janky and busted phrasing
choptastic Oct 9, 2024
6d24820
eep-0072: Clarifying language and more examples
choptastic Oct 9, 2024
8e0e09c
Update eeps/eep-0072.md
choptastic Oct 9, 2024
f5d0d3f
eep-0072: phrasing
choptastic Oct 9, 2024
87a637b
EEP0072-Expand Motivations and specs for definition
choptastic Oct 9, 2024
8036769
EEP-0072: Remove excess hyphenation
choptastic Oct 9, 2024
3ddb0c6
EEP-0072: Add note about ASN1 and Corba
choptastic Oct 9, 2024
7c28c8a
EEP-0072: Attempt to fix spacing to alleviate linter errors
choptastic Oct 10, 2024
608739d
EEP-wq0072: Add a missed blank line around header
choptastic Oct 10, 2024
c838aa4
EEP-0072: Fix (hopefully) last markdown issue
choptastic Oct 12, 2024
d60191b
Update making the new define syntax more obvious
choptastic Oct 12, 2024
7cfbd6f
Apply suggestions from code review
choptastic Oct 12, 2024
467ce8a
Fix typo
choptastic Oct 13, 2024
6a9c62b
Fix some length
choptastic Oct 13, 2024
6543ec7
Add some notes about the type system
choptastic Oct 13, 2024
5250011
Update phrasing a bit
choptastic Oct 13, 2024
8ef3dca
Update eeps/eep-0072.md
choptastic Oct 18, 2024
4fc7d01
Update eeps/eep-0072.md
choptastic Oct 18, 2024
dbfb39e
Update variable name phrasing
choptastic Oct 18, 2024
3164da9
Fix some paraphraphs
choptastic Oct 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 227 additions & 0 deletions eeps/eep-0072.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
Author: Jesse Gumm <ja(at)gumm(dot)io>
Status: Draft
Type: Standards Track
Created: 08-Oct-2024
Post-History:
****
EEP 72: Reserved words and Variables as record names, and enhancement to definition syntax
----

Abstract
========

This EEP loosens some of the restrictions around record names to make it
no longer necessary to quote them when they are named with reserved
words (`#if` vs `#'if'`) or words with capitalized first characters (`#Hello`
vs `#'Hello'`).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
words (`#if` vs `#'if'`) or words with capitalized first characters (`#Hello`
vs `#'Hello'`).
words (`#if` vs `#'if'`) or words with capitalized first characters (variable
names, for example `#Hello`vs. `#'Hello'`).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do like that this indicates that an unquoted word with a capitalized first character would indicate a variable name, but I find the specific wording without any qualifiers may imply that a record name can itself be a variable, rather than an atom that happens to have variable-style capitalization. Perhaps the term "atom with variable capitalization" with acronym "AVC" or something (or if there's a better term)? I know this is a little bike-shedding, but I'm concerned folks might interpret the use of "Variable name" to actually think the record name can be a variable.

If you think I'm off my rocker with this and I'm overthinking it, feel free to let me know :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a point. Maybe just "like variable names". I interpret "atom with variable capitalization" as 'Hello' because quoting is how to create such an atom.
We should avoid inventing an acronym...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the phrasing here: dbfb39e

What do you think?


This EEP also proposes to add a new record-like syntax to the record
definitions (also adopting the above syntactical changes), so that the
following record definitions would all be valid and identical:

```erlang
-record('div', {a :: integer(), b :: integer()}).
-record #'div'{a :: integer(), b :: integer()}.
-record #div{a :: integer(), b :: integer()}.
```

The latter two are proposed new syntax. The following would also be valid
and identical since parentheses are optional in attributes:

```erlang
-record 'div', {a :: integer(), b :: integer()}.
-record(#'div'{a :: integer(), b :: integer()}).
-record(#div{a :: integer(), b :: integer()}).
```

Usage Syntax Motivation
=======================

Record names are atoms. As such, the current Erlang syntax requires the record
names to be consistent with the rest of the language's use of atoms.

All atoms in Erlang can be denoted with single quotes. Some examples:

For example:
```erlang
'foo'.
'FOO'.
'foo-bar'.
```

But, conveniently, simple atoms (all alphanumeric, underscores (`_`) or
at symbols (`@`) with the first character being a lowercase letter and not one
of the 20+ reserved words), in all contexts can be invoked without the
necessary wrapping quotes. Some examples:

```erlang
foo.
foo_Bar.
'foo-bar'. % still quoted since the term has a non-atomic character in it.
```

Conveniently, this also means that records named with simple atoms can be
invoked and used without having to quote the atoms. For example:

```erlang
-record(foo, {a, b}).

go() ->
X = #foo{a = 1, b = 2},
Y = X#foo{a = something_else},
Z = Y#foo.a,
...
```

Unfortunately, that also means that records named with anything that doesn't
fit the "simple atom" pattern must be wrapped in quotes in definition and
usage. For example:

```erlang
-record('div', {a, b}).

go() ->
X = #'div'{a = 1, b = 2},
Y = X#'div'{a = something_else},
Z = Y#'div'.a,
...
```

While this approach is consistent with atom usage in the language, for reserved
words, this makes the record syntax *feel* inconsistent if you have a need for
naming a record with a reserved word (or term with a capital first letter). In
this case, it almost guarantees a user won't use a record named 'if',
'receive', 'fun', etc even though there may very well be a valid use case for
such a name. The most common use case that comes to mind from the Nitrogen Web
Framework. Since HTML has a `div` tag, Nitrogen (which represents HTML tags
using Erlang records) should naturally have a `#div` record, however, due to
'div' being a reserved word (the integer division operator), the record `#panel`
is used instead to save the programmer from having to invoke `#'div'`,
which feels unnatural and awkward.

Further, applications such as ASN.1 and Corba both have naming conventions that
rely heavily on uppercase record names and as such, they currently must be
quoted as well. You can see this in modules in Erlang's
[`asn1`](https://github.com/erlang/otp/blob/OTP-27.1.1/lib/asn1/src/asn1_records.hrl#L35-L39)
application. (The previous link points to some record definitions in `asn1`,
but you can see the usage scattered across a number of modules in the `asn1`
application).

Usage Syntax Specification
==========================

This EEP simplifies the above example by

1. Allowing reserved words and variables to be used without quotes for record
names, and
2. Simplifying the definition such that the syntax between record definition
and record usage becomes more consistent.

With the changes from this EEP, the above code becomes:

```erlang
-record('div', {a, b}).

go() ->
X = #div{a = 1, b = 2},
Y = X#div{a = something_else},
Z = Y#div.a,
...
```

Definition Syntax Motivation
============================

While the updated example in the usage syntax specification makes the *using*
of records cleaner, there remains one more inconsistency that can also be
relatively easily solved. That is the record definition still also needing to
quote record name, as the example above demonstrates (repeated here for
convenience):

```erlang
-record('div', {a, b}).

go() ->
X = #div{a = 1, b = 2},
Y = X#div{a = something_else},
Z = Y#div.a,
...
```

So whereas the record definition needs to be thought of as `'div'`, the record
usage no longer requires the quoted term 'div', which could certainly lead an
Erlang beginner to wonder why 'div' needs to be quoted in the definition while
other atom-looking terms don't.

Definition Syntax Specification
===============================

Conveniently, there is a rather easy solution, and that's to
allow the record usage syntax to also be used as the record definition.

This EEP also then also adds a new record definition syntax, improving the
symmetry between general record usage and record definition.

The above example can fully then look like the following:

```erlang
-record #div{a, b}.

go() ->
X = #div{a = 1, b = 2},
Y = X#div{a = something_else},
Z = Y#div.a,
...
```

Implementation
==============

To update the syntax for using records, we can safely augment the parser to
change `# atom` to `# record_name` and define `record_name` to be either
`atom`, `var`, or `reserved_word`.

To update the record definition syntax, we can simply add a few new
modifications to the `attribute` Nonterminal.

Backwards Compatibility
=======================

As this EEP only adds new syntax, the vast majority existing codebases will
still work, with the possible exception of AST/code analysis tools that are
analyzing code using the new syntax.

Syntax highlighting and code completion tools may need to be updated to support
the new syntax if your code uses the new syntax rules.

Broader Concerns and Points of Discussion
=========================================

While the new definition syntax creates some degree of symmetry around record
usage, there do remain some concerns and inconsistencies:

1. Other functions that work with records like `is_record/2` or `record_info/1`
are not currently covered by any of the syntactical changes in this EEP, and
as such, it remains necessary to quote record names if they are not simple
atoms. For example: `is_record(X, div)` would still be a syntax error. So
there is still not true 100% symmetry.
2. This EEP introducing a new syntax for record definition could potentially
lead to some to wonder why the language has two rather different syntaxes
for defining records. Since usage of the syntax for getting, setting,
matching, etc (e.g. `#rec{a=x,y=b}`) occurs far more commonly than defining,
it only feels natural that the definition syntax would mirror usage. Thus, I
feel that the symmetry between the usage and the definition would likely
become the default/preferred way, and that the original syntax remain for
backwards compatibility.

Reference Implementation
========================

The reference implementation is provided in a form of pull request on GitHub

https://github.com/erlang/otp/pull/7873

Copyright
=========

This document has been placed in the public domain.