[erlang-questions] Question/Alternative on Frames Proposal [Warning: Long]

Richard O'Keefe <>
Fri May 18 06:38:42 CEST 2012

On 18/05/2012, at 12:21 PM, Tom Parker wrote:
> But here is where I get stuck.  
> Why not use the record format?  ... (Bear with me, I believe the issues in that reuse can be addressed.)


It's that simple.  Back when Eiffel was undergoing major changes,
I proposed something I called the "diarthognathus principle".
When you want to evolve from supporting technique X to supporting
technique Y, you had *better* evolve through a stage where you
support *both* techniques.

And that means that there has to be a period when frames have begun
to work and record syntax still works *EXACTLY* the way it does now.

Frames and records are not inter-operable (records are just a
stylised use of tuples, while frames are a new completely distinct

> Issue #1 with the ~ syntax) Today's Erlang developer, if using records, has already provided a form of that information.  It already has a key->value mapping.

And it must continue to work *as is* without breaking anything.

But there is one thing more.
Suppose you go around mechanically translating

	#id0{id1=E1, ..., idn=En}
	<id0{id1~E1, ..., idn~En}>

which is a fairly straightforward task.

What happens?  The code immediately stops working.  Because the two forms

A frame construction says "here is ALL the information about this frame."

A record construction says "here is SOME information about this record,
pick up anything I've left out from the -record declaration."

Because these things have different semantics they MUST have different

> Issue #2 with the ~ syntax) The format proposed for extraction from a frame, with a tilde, is ~name(Frame).  (okay, a little bike shed paint :) ) This reverses the standard ordering of items from Major to minor.

I am tempted to use a very rude word here.


It may still be true that there are more lines of COBOL than any other language.
In COBOL, it's <field> of <record>.
In Algol 68, it's <field> of <record>.

	predecessor count OF node -:= 1

seems to me a perfectly natural way to decrement the number of predecessors of
some node.

For a functional language, note that
a field selector is semantically just an overloaded function.

In the Pop family of languages, record selectors are just functions (well,
technically doublets) and are called exactly like functions.
In Lisp, selectors are called exactly like functions.
In ML-family languages, if f is a field, #f is the function that extracts
that field (and yes, that's where I got the syntax).

Yes, in Smalltalk the analogue of field selection is "object field",
but that's how Smalltalk writes unary functions: "-42 abs".

The syntax is neither novel nor unnatural unless you take an
extremely parochial view of programming languages.

> We are all already familiar with the record format being a key:value mapping, and that's what a frame would look like:
> P = #point{x=4,y=5}.
> or as part of the frame proposal, if you prefer the anonymous definition vs. a declared format, we can use (from erlson):
> P = #{x = 4, y = 5}.

It's not a matter of preference, not having declarations is what frames are ABOUT.

> The big question:
> Q: How do I know this #point is a frame and not a record? 
> A: Well, we have 2 ways of knowing:
> (1) A language requirement would be imposed that #{ is always an "anonymous frame" since it is not a valid record.
> (2) The namespace defined for -record(ATOM, {...}) and -frame(ATOM,{...}) would be shared (compiler - well, technically the preprocessor - would halt with an error if a record and a frame with the same ATOM identifier were included in the module to be compiled.)  Since the preprocessor destroys records, the only #atom{ the compiler would ever see would be frames - it is never ambiguous to the compiler.

No no no no NO!  There can be *type* specifications that declare some type to be
implemented as a frame of a particular shape, but there are no frame declarations
as such.  NOT having them is one of the major design goals!  

> Comments on your questions from section 4 of your document in comparing solutions:
> Q1: Frames answer changes to Yes, this actually forces an increase in intelligence of the preprocessor.

That is utterly unacceptable.  The frame proposal *EXISTS* in order to have
something vaguely recordy that makes NO use of the preprocessor whatsoever.

> Q4: This would alleviate the impact on Dialyzer as it already understands record formats (should make it a less challenging change)

No, it wouldn't.  I keep coming back to the same key point:
frames and records have DIFFERENT SEMANTICS.
Syntactic processing is not a challenge.
The challenge in extending the Dialyzer to handle frames is
in handling the SEMANTICS.

> Q9: If the frame is a declared frame, then the frames answer is enhanced to be able to catch this issue at compile time, otherwise as before

Frame declarations do not exist.  By intent, there is no such animal
as "a declared frame".  Adding frame declarations is like adding
huge paddle wheels to a hot air balloon and still expecting it to fly.

One of the things that frames are meant for is to communicate
structured values from one context to another context WITHOUT
there being any declaration shared by both.

> Q10: If the frame is a declared frame, then the frames answer is enhanced to be able to catch this issue at compile time, otherwise as before

It is an important feature of the design that there are no
frame declarations and there is NO preprocessor involvement
in the processing of frames whatsoever.  

> Q11. Frames now take on the unnecessary recompile situation of records (if the record is a declared frame)

Isn't that a clue that there is something wrong with the idea of
-frame declarations?

> Q20: I believe this would change to make detection easier, but am not totally sure.

If you want records, you know where to find them.

Records are *not* going to go away.  They have their virtues
and their vices.  Frames are *different* virtues and vices.
Trying to make one look like the other is about as kind to
programmers as trying to make numbers and strings look the same.
It is seductively attractive, but causes more trouble than it's
worth in practice.  (Speaking as someone who maintains an AWK
implementation and tried to write an AWK compiler.)
> Additional Q&A:
> Q: So this forces declaration of a frame if I want an atom between # and {
> A: That is my thought.  It would look like:
> -frame(point, {x, y}).

But the frames proposal already allows <name{ fields }>.
Without any declaration.

We know what is the right way to catch type errors and typos.
That's what the Dialyzer does, and does very well.

Speaking as someone who has tried to maintain other people's
code, if I see #point{x = 1, y = 2} I want to *KNOW* that
that is a record, not anything else at all.  I don't want
it to maybe be a record or maybe something else, possibly
depending on a file that isn't open in my editor.

You are asking for a "feature" that I regard as active
malevolence towards the programmer.

> Q: How does extraction change?
> A: Extraction with the record-style format ... and is major to minor:
> Frame#format.member

Having to repeat the record name is one of the most hated aspects of
the present -record syntax.  I am having no success understanding
why anyone would *WANT* to imitate that abomination.

As for major to minor, I have never perceived anything major or minor
in field access.  Some languages put the field first, some put it second.
BIG DEAL.  Languages are different.  Get over it.  They don't all have
to look like Java.

I skipped the rest of the message.

The frame proposal exists precisely in order to have something that
can do the same job that records do but in a DIFFERENT way.  Because
the semantics is different, programmers need to know what they are
dealing with, so it is an incredibly bad idea to use the same syntax
for both.  It doesn't matter so very much what the syntax _is_ as
long as it is clearly _different_.  Frames "fit" into Erlang data
structures in a way that records never did; _all_ the information
that exists about a frame is right there in it without consulting
any declaration.  In particular, changing a declaration in one
field cannot change the meaning of a frame construction in another.
Adding -frame declarations isn't "raising" the proposal but "razing" it.

More information about the erlang-questions mailing list