{"id":563,"date":"2007-12-16T20:29:19","date_gmt":"2007-12-16T20:29:19","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/2007\/12\/16\/records-in-erlang\/"},"modified":"2007-12-16T20:29:19","modified_gmt":"2007-12-16T20:29:19","slug":"records-in-erlang","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2007\/12\/16\/records-in-erlang\/","title":{"rendered":"Records in Erlang"},"content":{"rendered":"<p> One of the things I discovered since writing part one of my Erlang introduction is that Erlang has grown a lot over the last few years. For example, the idiom of tagged tuple as a way of creating a record-like structure has been coded into the language. There is, unfortunately, a bit of a catch. They aren&#8217;t <em>really<\/em> added to the language. Instead, there&#8217;s a pre-processor in Erlang, and records<br \/>\nare defined by translation in the pre-processor. This to me typifies one of the less attractive<br \/>\nattributes of Erlang: much of Erlang has a very ad-hoc flavor to it. There are important high-level features &#8211; like record data and modules &#8211; which aren&#8217;t really entirely part of the language. Instead, they&#8217;re just sort of spliced in however it was easiest for the implementors to cram &#8217;em in. And there are other things that were added to later versions of the language that, while first class, are awkward &#8211; like the &#8220;fun&#8221; prefix for first-class functions.<\/p>\n<p> The effect of that kind of thing is mainly syntactic. The implementation is good enough that<br \/>\neven though things like records are really pre-processor constructs, they feel almost as<br \/>\nif they&#8217;re built-ins.<\/p>\n<p> Anyway &#8211; let&#8217;s take a look at records.<\/p>\n<p><!--more--><\/p>\n<p> As I mentioned in the first Erlang post, the basic data type idiom of Erlang is<br \/>\nbased on tuples. Typically, to represent a data type, you create a tuple whose first element<br \/>\nis an atom which identifies the type of the tuple.<\/p>\n<p> That&#8217;s exactly what the record facility does. You define a record type, and it&#8217;s built using<br \/>\na tuple whose first element is the atom which names the record type. The rest of the entries of a record tuples are the fields of the record, which are represented by alternating field names (as atoms) and field values. So, for example, if we<br \/>\nwanted to define a binary tree like the following Haskell:<\/p>\n<pre>\ndata Tree a = Node (Tree a) (Tree a) | Leaf a\nsample = Node (Node (Leaf 1) Leaf 2) (Leaf 3)\n<\/pre>\n<p> Would be implemented as something like the following in tuples in Erlang:<\/p>\n<pre>\nSample = {node,\nleft, {node,\nleft, {leaf, value, 1},\nright, {leaf, value, 2}},\nright, {leaf, value, 3}}\n<\/pre>\n<p> That&#8217;s obviously pretty ugly, and pretty laborious to code. The record-feature in the meta-language makes it much more convenient:<\/p>\n<pre>\n-record(node, {left,right})\n-record(leaf, {value})\nSample = #node{left=#node{left=#leaf{value=1},\nright=#leaf{value=2}},\nright=#leaf{value=3}}\n<\/pre>\n<p> A record is declared with a pre-processor form &#8220;-record&#8221;. The first parameter to the form is<br \/>\nthe atom naming the record type; the second parameter is a tuple of the record field names. Once a record type is defined, you can create an instance of it with &#8220;#&#8221; followed by the record type name, and a set of field assignments inside of curly braces.<\/p>\n<p> Like everything in Erlang, the way to manipulate records is by pattern matching:<\/p>\n<pre>\n#node{left=L,right=R} = Sample\n<\/pre>\n<p> will assign &#8220;L&#8221; to &#8220;#node{left=#leaf{value=1},right=#leaf{value=2}}&#8221;, and &#8220;R&#8221; to &#8220;#leaf{value=3}&#8221;.<\/p>\n<p> Aside from the weirdness of the meta-language division, the sequential part of Erlang is very<br \/>\nstraightforward. It&#8217;s a classic eager functional language. Programs in Erlang are quite similar to<br \/>\nprograms in a language like Scheme, except for syntax, and the syntax is OK; sort-of a bastard offspring<br \/>\nof Lisp and Prolog, which isn&#8217;t an awful thing. <\/p>\n<p> To give you a bit of flavor, here&#8217;s a simple bit of binary search tree code in<br \/>\nErlang:<\/p>\n<pre>\n-module(bt).\n-export([insert\/2]).\n-record(node,{value,left,right}).\ninsert(#node{value=N,left=L,right=R}, V)  when N &gt; V -&gt;\n#node{value=N, left=insert(L,V), right=R};\ninsert(#node{value=N,left=L,right=R}, V) -&gt;\n#node{value=N, left=L, right=insert(R,V)};\ninsert(none, V) -&gt;\n#node{value=V, left=none, right=none}.\nfetch(#node{key=K, value=V, left=L, right=R}, K) -&gt;\nV;\nfetch(#node{key=K, value=V, left=L, right=R}, Target) when K &gt; Target -&gt;\nfetch(L, Target);\nfetch(#node{key=K, value=V, left=L, right=R}, Target) -&gt;\nfetch(R, Target);\nfetch(none, Target) -&gt; none.\n<\/pre>\n<p> It&#8217;s very straightforward functional code. It&#8217;s almost exactly the same way that it would be written<br \/>\nin ML (my favorite eager functional languages), and very close to how it would be written in Haskell. It is a bit verbose &#8211; but that&#8217;s because I&#8217;m not using Erlang to its full advantage. The code can be<br \/>\nsimplified a bit by using record field access and update syntax.<\/p>\n<p> If you only want to access one field of a record, there&#8217;s a shorthand syntax that&#8217;s more convenient<br \/>\nthen writing out a full pattern match to get at one field: if <code>Sample<\/code> is a variable<br \/>\ncontaining a record, then <code>Sample#node.left<\/code> gets the value of the field named &#8220;left&#8221; of the<br \/>\nrecord type &#8220;node&#8221;. (If you use this syntax with the wrong record type, you&#8217;ll get a run-time error.)\n<\/p>\n<p> Similarly, there&#8217;s a syntax for updating a record &#8211; that is, creating a new record that&#8217;s the same<br \/>\nas an old record except for a couple of modified fields: <code>Sample#node{right=#leaf{4}}<\/code> will<br \/>\ncreate a new tuple of type &#8220;node&#8221;, with the same left value as Sample, but with a different right<br \/>\nvalue.<\/p>\n<p> So, using that, we can modify &#8220;insert&#8221;, so that we don&#8217;t need to write the full record<br \/>\nconstruction syntax. Instead, we could write insert the following way (called &#8220;sinsert&#8221; for &#8220;simpler insert&#8221;):<\/p>\n<pre>\nsinsert(none, Newkey, Newval) -&gt;\n#node{key=Newkey, value=Newval, left=none, right=none};\nsinsert(Node, Newkey, Newval) when Node#node.key &gt; Newkey -&gt;\nNode#node{left=sinsert(Node#node.left, Newkey, Newval)};\nsinsert(Node,Newkey, Newval) -&gt;\nNode#node{right=sinsert(Node#node.right, Newkey, Newval)}.\n<\/pre>\n<p> For this kind of straightforward data structure programming, Erlang is a really pleasant language.<br \/>\nThe record system is very nice, flexible, and easy to work with. The strong pattern matching facility of the language is flexible enough that for an impressively large number of functions, you don&#8217;t need to write any control structure code beyond patterns and &#8220;when&#8221; guards. I just wish it wasn&#8217;t in the<br \/>\nmeta-syntax &#8211; when I get around to explaining the way that a large Erlang program is broken into multiple files, you&#8217;ll see a bit of why I&#8217;m unhappy that it&#8217;s meta.<\/p>\n<p> In general, my impression thus far playing with Erlang (which I&#8217;ve used for a bit more complicated<br \/>\nstuff than I&#8217;ve included in this post) is that it&#8217;s very easy to read and write, and it behaves in a<br \/>\nvery intuitive fashion. I definitely find it easier to pick up as a beginner than I did Haskell, but I think that&#8217;s mainly because I find eager evaluation to be easier to predict than lazy. For this kind of basic data structure programming, I think it&#8217;s a toss-up with Haskell: I prefer Haskell&#8217;s<br \/>\nstrong types, but Erlang&#8217;s eager semantics make it a whole lot easier to understand the efficiency<br \/>\ntradeoffs between different implementation strategies. <\/p>\n<p> Before moving on, I&#8217;ll toss in some information on the bit of Erlang that I really hate.<br \/>\nAside from using a preprocessor for implementing meta-language features like records, Erlang&#8217;s<br \/>\npreprocessor also has a macro facility that&#8217;s modeled on the macro system from the C preprocessor.<br \/>\nLike cpp, it&#8217;s ugly as all get-out, and it&#8217;s bloody dangerous to use. It&#8217;s a ghastly<br \/>\nthing, but it&#8217;s there, and a fair bit of Erlang code uses it. (Gag.) One minor redeeming feature of the<br \/>\nmacro system is that at least uses of macros are clearly marked &#8211; unlike C or C++, you can clearly tell a macro invocation from a function invocation.<\/p>\n<p>To define a preprocessor macro, you use:<\/p>\n<p><pre>\n-define(name, replacement)\n<\/pre>\n<p> Or, for a macro with parameters:<\/p>\n<pre>\n-define(name(p1, p2, p3), replacement)\n<\/pre>\n<p> For example:<\/p>\n<pre>\n-define(TIMEOUT, 2500)\n-define(Double(X),2*X)\n<\/pre>\n<p> Then you can use the macros by prefixing the name with a &#8220;?&#8221;: <code>?Double(10)<\/code>.<\/p>\n<p> Naturally, if you&#8217;ve got a hideous preprocessor, you can&#8217;t escape using it for conditional compilation. So the Erlang preprocessor includes &#8220;-undef&#8221;, &#8220;-ifdef&#8221;, &#8220;-ifndef&#8221;, &#8220;-else&#8221;, &#8220;-endif&#8221;, each<br \/>\nof which means pretty much the same thing as the corresponding C preprocessor directive.<\/p>\n<p> Once again, gag.<\/p>\n<p> Anyway &#8211; next post, I&#8217;ll go into more depth about control structures in Erlang, and introduce one of the more unusual features of Erlang, called bit syntax. Bit syntax is an amazingly powerful and flexible pattern-matching syntax for data encoded in bit streams. Given Erlang&#8217;s origins, it&#8217;s fairly obvious why this is part of the language &#8211; and it&#8217;s one of the things that make it <em>so<\/em> suitable for high performance distributed systems: it&#8217;s got deep support for the kind of bit-tweaking that&#8217;s necessary for<br \/>\nmany communication protocols, and it&#8217;s done in a way that allows the compiler to optimize the living daylights out of it. But that&#8217;s the next post.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the things I discovered since writing part one of my Erlang introduction is that Erlang has grown a lot over the last few years. For example, the idiom of tagged tuple as a way of creating a record-like structure has been coded into the language. There is, unfortunately, a bit of a catch. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[85],"tags":[],"class_list":["post-563","post","type-post","status-publish","format-standard","hentry","category-erlang"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-95","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/563","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/comments?post=563"}],"version-history":[{"count":0,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/563\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=563"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=563"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=563"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}