Proposal: record field puns

141 views
Skip to first unread message

Peter Minten

unread,
Nov 19, 2013, 12:38:56 PM11/19/13
to elixir-l...@googlegroups.com
Hi all,

This is a proposal to add record field puns to Elixir.

Currently we given a `defrecord Tree, value: nil, left: nil, right: nil`
we have to write things `Tree[value: value, left: left, right: right`.
With field puns you could write `Tree[value, left, right]`.

Field puns, as proposed here, can be understood as a fairly simple
convenience which expands to the current syntax:

Tree[value] -> Tree[value: value]
Tree[value, left: l, right: r] --> Tree[value: value, left: l, right: r]

Field puns would work both for construction of records and pattern
matching. They would work both for normal records and private records.

A limitation of the proposed form of field puns is that you can't write
`Tree[value: v, left, right]`. All puns go before the "field: value"
pairs as a consequence of the normal keyword list rules.

On the bright side no syntax expansion is required, only a few macro's
like Record.access need a bit more intelligence.

What do you all think of this?

Greetings,

Peter

Gustavo Brunoro

unread,
Nov 19, 2013, 12:58:41 PM11/19/13
to elixir-l...@googlegroups.com
Hi,

This is *very* nice. I find myself writing things like `Tree[value: value, left: left, right: right]` most of time.
The limitiation of having puns only before explicit attributes IMHO isn't a problem as long it's documented.

Cheers,
Gustavo


2013/11/19 Peter Minten <peter....@online.nl>

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

meh.

unread,
Nov 19, 2013, 2:41:53 PM11/19/13
to elixir-l...@googlegroups.com
On Tue, Nov 19, 2013 at 06:38:56PM +0100, Peter Minten wrote:
> What do you all think of this?

I like this a lot, since I write a lot of code like that, the only
doubt I have is in regard to the not-yet-implemented record update
syntax, which would work as Record[record, new: value] if I recall
correctly.

Saša Jurić

unread,
Nov 21, 2013, 1:31:57 PM11/21/13
to elixir-l...@googlegroups.com, peter....@online.nl
+1 on this

I also find myself constantly using value: value (though mostly with private record).
I find this increases the general noise a lot.

Vincent Siliakus

unread,
Nov 22, 2013, 5:42:50 AM11/22/13
to elixir-l...@googlegroups.com, peter....@online.nl
I'm not so sure about this. Records are compile-time constructs for making working with tuples easier and less error prone.

Field ordering is insignificant with records and IMHO that's a really good thing. Field puns would make field ordering significant again. Currently, adding fields to a records won't break any existing code that uses the record. When using field puns code will break if a new field is added between puns.

Furthermore, while not an issue with a simple record as the Tree example, I'm a bit afraid people would also start using the puns for complex records to save them self a few key strokes. I really wouldn't want to work with code like `ComplexRecord[42, :atom, "some text", [], nil, nil, 1000, 2]`

If you really feel that writing field names all the time clutters up your code, why not write a helper macro like:

defmacro v(value) do
  quote do
    Tree[value: unquote(value)]
  end
end

or if you like living on the edge, just directly work with the tuple:

{Tree, value, left, right}

Best,
Vincent

Op dinsdag 19 november 2013 18:38:56 UTC+1 schreef Peter Minten:

Peter Minten

unread,
Nov 22, 2013, 6:01:20 AM11/22/13
to Vincent Siliakus, elixir-l...@googlegroups.com
I think you've misunderstood the proposal. It's not about making the
order of fields significant. The only thing that happens is that an
expression `Record[field1, field2: val2]` gets translated to
`Record[field1: field1, field2: val2]`.

So given `defrecord Tree, value: nil, left: nil, right: nil` you could
write `Tree[left, right, value: 3]` where you could otherwise write
`Tree[left: left, right: right, value: 3]`. Note how the order of fields
is still completely insignificant.

Vincent Siliakus

unread,
Nov 22, 2013, 6:24:39 AM11/22/13
to elixir-l...@googlegroups.com, Vincent Siliakus, peter....@online.nl
I think I still don't understand :)

Please correct me if I'm wrong, but given a record `defrecord R, a: nil, b: nil, c: nil, d: nil`, what would R[42, a: 12, c: 0] expand to? I guess, R[b: 42, a: 12, c: 0], but that would mean I need to know that field :b is in between fields :a and :c. Also, if record R is exposed by some library and it's author decides to extend the record definition to `defrecord R, a: nil, aa: nil, b: nil, c: nil, d: nil`, my R[42, a: 12, c: 0] code would break, because I expect 42 to be expanded as the value of field :b.


Op vrijdag 22 november 2013 12:01:20 UTC+1 schreef Peter Minten:

Ryan Scheel

unread,
Nov 22, 2013, 6:39:48 AM11/22/13
to elixir-l...@googlegroups.com, Vincent Siliakus, peter....@online.nl
It wouldn't expand. It's when you have a binding with the same name as the record field that you are assigning to. If you had R[b, a: 12, c: 0], it would expand to R[b: b, a: 12, c: 0], but `42` isn't `b`.

Peter Minten

unread,
Nov 22, 2013, 6:55:17 AM11/22/13
to elixir-l...@googlegroups.com, Vincent Siliakus
It would expand to an exception at compile time.

R[42, a: 12, c: 0] is invalid because of the constraint that field names
are atoms.

Let's walk through the expansion for a moment. Consider that the [42, a:
12, c: 0] is interpreted as a list using the normal rules, so it's the
list [42, [a: 12, c: 0]], aka [42, [{:a, 12}, {:c, 0}]].

The expansion transforms any element that's not in the keyword list to a
separate keyword list and then concatenates the keyword lists. So [:b,
[{:a, 12}, {:c, 0}]] would become [[{:b, :b}], [{:a, 12}, {:c, 0}]] and
after concatenation [{:b, :b}, {:a, 12}, {:c, 0}] (pretty printed: [b:
b, a: 12, c: 0]).

This transformation would expand [42, [{:a, 12}, {:c, 0}]] to [{42, 42},
{:a, 12}, {:c, 0)]. But now there's a problem, the record field access
code requires a keyword list, which means a list of {atom, any} tuples.
The transformed code is not a keyword list so there would be some kind
of exception raised.

Most likely there would be a bit more intelligence to give more useful
error messages than simply throwing an exception, but the rules are the
same.

Vincent Siliakus

unread,
Nov 22, 2013, 6:56:09 AM11/22/13
to elixir-l...@googlegroups.com, Vincent Siliakus, peter....@online.nl
I see, thanks for clearing this up, I didn't get that from Peter's proposal. I guess you can ignore my previous objections in that case. Are there any examples of other languages that implement this?


Op vrijdag 22 november 2013 12:39:48 UTC+1 schreef Ryan Scheel:

Peter Minten

unread,
Nov 22, 2013, 7:00:27 AM11/22/13
to elixir-l...@googlegroups.com, Vincent Siliakus
OCaml and Haskell (with an extension turned on) both have field puns.
Reply all
Reply to author
Forward
0 new messages