UNPKG

cream-and-sugar

Version:

A deliciously functional syntax for JavaScript with native support for JSX

206 lines (189 loc) 14.8 kB
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Cream & Sugar: Data Types</title> <link rel="icon" type="image/x-icon" href="https://jgnewman.github.io/cream-and-sugar/assets/images/favicon.ico" /> <link href="https://fonts.googleapis.com/css?family=Bitter:400,700|Open+Sans:300,400,800" rel="stylesheet"> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css" /> <link rel="stylesheet" href="../../assets/css/app.css"> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.8.0/styles/default.min.css"> <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.8.0/highlight.min.js"></script> </head> <body class="docs"> <div class="branding"></div> <div class="content"> <div class="left-border"> <h1>Data Types</h1> <h2 class="subhead">With Just A Couple Upgrades</h2> </div> <p>Keeping in mind that C&amp;S is just a layer on top of JavaScript, all of its native data types are direct, one-to-one translations of JavaScript data types. And in fact, many of them look exactly the same as JavaScript&#39;s data types with only a few exceptions.</p> <p>In this section, we&#39;ll talk about each data type that deviates from the JavaScript spec in terms of how it works, whether or not there are any efficiency considerations, and how it translates to JavaScript.</p> <h2 id="strings">Strings</h2> <pre><code>`here is a number: ${2 + 2}` #=&gt; &#39;here is a number: 4&#39; &quot;here is a number: ${2 + 2}&quot; #=&gt; &#39;here is a number: ${2 + 2}&#39; </code></pre><p>C&amp;S strings function almost exactly like strings in ES6. In other words, you can create a string using single quotes, double quotes, or back ticks. Each of these techniques generates the exact same kind of string. In addition, you can use back tick strings to include interpolation.</p> <pre><code>&quot; This string opens and closes on different lines. &quot; </code></pre><p>The only other difference between C&amp;S strings and JS strings is that you can write all strings on multiple lines in C&amp;S. As such, the included example is <strong>not valid</strong> in JavaScript but is <strong>totally cool</strong> in Cream &amp; Sugar.</p> <h2 id="atoms-symbols-">Atoms (Symbols)</h2> <p>Lots of languages have things they call atoms or symbols. Typically, this type is constituted by some piece of data that represents nothing but itself. It&#39;s light-weight, is often used to identify other types of data, and is collected in a global repository of atoms/symbols, never to be garbage collected.</p> <pre><code># JavaScript symbol Symbol.for(&#39;foo&#39;); </code></pre><p>In ES6, JavaScript implemented its own version of symbols. True to form, they were implemented in the most verbose way possible. To create a named symbol, you have to call a method on the <code>Symbol</code> object.</p> <p>From then on, every time you reference <code>Symbol.for(&#39;foo&#39;)</code>, you&#39;ll be referencing the same, unique piece of data. In C&amp;S, you have these too, except we call them &quot;atoms&quot;, and all of them are named. To create or reference the <code>Symbol.for(&#39;foo&#39;)</code> in C&amp;S, you need only write a word in all caps.</p> <pre><code># C&amp;S atom FOO </code></pre><p>The rules for naming atoms are as follows:</p> <ul> <li>The name must contain at least 2 characters</li> <li>The first character must be a capital letter</li> <li>The name may only contain capital letters and underscores</li> </ul> <pre><code>{ FOO: &quot;foo&quot;, BAR: &quot;bar&quot; } #=&gt; { # [Symbol.for(&#39;FOO&#39;)]: &quot;foo&quot;, # [Symbol.for(&#39;BAR&#39;)]: &quot;bar&quot; # } {{ OK, &quot;Message text here&quot; }} #=&gt; CNS_.tuple( # [ Symbol.for(&#39;OK&#39;), # &quot;Message text here&quot; ] # ) </code></pre><p>Armed with this syntax, you can now much more easily stomach using atoms in all the ways JavaScript symbols allow. For example, you can use them as object keys.</p> <p>You can also use them in a sort of &quot;Erlang-y&quot; way to label data being passed back and forth between processes. If you aren&#39;t familiar with Erlang, that&#39;s fine. Read on to the section on tuples to get a better understanding of what&#39;s going on in that last example.</p> <h2 id="arrays">Arrays</h2> <p>Arrays translate one-to-one into JavaScript arrays. However, your options for working with arrays in C&amp;S have been augmented. While you are not prevented from using native JavaScript methods to work with arrays, you are encouraged to avoid mutative methods and stick with methods that produce new data instead.</p> <pre><code># Create an array arr = [2, 3, 4] # Create a NEW array with an extra item # &quot;consed&quot; on the front arr2 = 1 &gt;&gt; arr #=&gt; [1, 2, 3, 4] # Create a NEW array with an extra item # added to the back arr3 = arr2 &lt;&lt; 5 #=&gt; [1, 2, 3, 4, 5] </code></pre><p>Along those lines, you have a new piece of syntax called &quot;cons&quot; that you can use to add a new item to the front of an array, as shown in the example.</p> <p>You also have the option of doing a &quot;back cons&quot; that will create a new array with an extra item appended to the back. It looks a lot like the &quot;cons&quot; form, just backward.</p> <p>C&amp;S also gives you a few extra native functions for working with arrays, including...</p> <ul> <li><code>head</code> which retrieves the first item in a list,</li> <li><code>tail</code> which creates a new list containing all items of an original list except the first one,</li> <li><code>lead</code> which creates a new list containing all items of an original list except the last one,</li> <li><code>last</code> which retrieves the last item in a list.</li> <li><code>get</code> which retrieves an item by position in a list.</li> <li><code>update</code> which creates a new list where the value of one of the items has been updated.</li> <li><code>remove</code> which creates a new list where one of the items has been removed.</li> </ul> <p>Check out <a href="/reference/bifs/">Built-In Functions</a> for more info on these.</p> <h2 id="objects">Objects</h2> <p>C&amp;S objects are identical to JavaScript objects. However, working with them can be a little different. For example, because C&amp;S is a functional language, you don&#39;t have a good way to modify and existing object. There are, of course, built-in functions such as <code>update</code> and <code>remove</code> that create new objects with modified property sets. You even have a built-in function called <code>dangerouslyMutate</code> that allows you to mutate an existing object <em>if you really have to</em>, such as when setting <code>location.href</code>.</p> <pre><code>{foo: bar} &lt;- {baz: quux} #=&gt; {foo: bar, baz: quux} </code></pre><p>But once you&#39;ve gotten into the mindset that you can work with new copies of objects rather than mutating old ones, you&#39;ll quickly discover how nice it is to have a short syntax for merging objects together. Enter C&amp;S&#39; concept of the &quot;object cons&quot;. (We realize we&#39;re playing fast and loose with the term &quot;cons&quot; here). Object cons syntax is characterized by 2 object values with the <code>&lt;-</code> operator between them. This syntax will create a new object containing all the keys of both values. Properties of the object to the right of the operator will override properties on the object to the left.</p> <pre><code>a &lt;- b # is equivalent to... Object.assign({}, a, b); </code></pre><p>Using object cons syntax is essentially the same as using <code>Object.assign</code>, but with fallback support for environments that don&#39;t contain Object.assign.</p> <h2 id="tuples">Tuples</h2> <pre><code>tuple = {{ foo, bar }} </code></pre><p>Perhaps most exciting is C&amp;S&#39; brand new list type, the tuple. A tuple is essentially a special kind of array with a special syntax.</p> <pre><code>{{ OK, 200, &quot;This is the data&quot; }} </code></pre><p>Tuples are designed to imbue meaning to the placement of each item in the list. As such, tuples can not be empty and they can not be updated to change the amount of items they contain. You will most often use tuples when you want to label items. For example, an http library might want to return server responses in the form of tuples...</p> <pre><code># response is {{ OK, 200, &#39;message text&#39; }} mylib.post &#39;/api/mydata&#39;, fn response =&gt; caseof get 0, response OK -&gt; doSomethingWith (get 2, response) ERR -&gt; doSomethingElseWith (get 2, response) </code></pre><p>In this case, the first item in the tuple is an atom telling us that the request succeeded. The second item is a status code. The third item is the response message. We might use this data as shown. As previously stated, the positions of these items carry meaning. We expect the first item to always be a success indicator and the second item to always be a status code. If you were allowed to modify the length of tuples, it would destroy the ability to imbue this meaning and remove the tuple&#39;s usefulness altogether.</p> <h2 id="collection-notation">Collection Notation</h2> <pre><code>{foo: &#39;bar&#39;, baz: &#39;quux&#39;} </code></pre><p>In most cases, you&#39;ll want to notate collections like arrays, objects, and tuples the same way you would in JavaScript. That is, you&#39;ll include the collection&#39;s opening token (such as <code>{</code>), separate your collection items with commas, and then finish with the closing token (such as <code>}</code>).</p> <pre><code>{ foo: (some &#39;function call&#39;), bar: &#39;quux&#39; } { foo: some &#39;function call&#39; bar: &#39;quux&#39; } </code></pre><p>When you separate your collection items onto independent lines, however, you have the option of removing the commas. As such, the two examples shown here produce identical output. As you can see, omitting the commas also allows you to remove other extraneous decorators. In the first example, we have to surround our function call with parentheses so that the compiler doesn&#39;t interpret the comma as being part of the argument list. In the second example, because there is no comma, there is no need to put parentheses around the function call.</p> <h2 id="assessing-types">Assessing Types</h2> <p>C&amp;S abandons JavaScript&#39;s confusing <code>typeof</code> expression in favor of a built-in function called <code>dataType</code>. This function will provide more reasonable results such as &quot;regexp&quot; if handed a regular expression or &quot;date&quot; if handed a Date object. For more information on what to expect from the <code>dataType</code> function, check out <a href="/reference/bifs/">Built-In Functions</a>.</p> </div> <section id="docs-app"></section> <script> // Section for random JavaScript hacks just to get this out quickly. window.addEventListener('load', function () { // Fix indentation in code blocks the best we can since panini's // markdown compiler injects whitespace into pre tags. Array.prototype.slice.call(document.querySelectorAll('pre code')).forEach(function (code) { var lines = code.innerHTML.trim().split('\n'); var out = [lines[0]]; var sliceAmount; lines.slice(1).forEach(function (line, index) { if (index === 0) { var whitespace = line.match(/^\s+/); whitespace = whitespace ? whitespace[0] : ''; if (/([=-](\&gt;)?|\{|match|\&gt;|div|try|chain|default\s+[^\n])$/.test(lines[0])) { whitespace = whitespace.slice(2); } sliceAmount = whitespace; } out.push(line.replace(sliceAmount, '')); }); code.innerHTML = out.join('\n'); code.className = 'visible lang-coffeescript'; hljs.highlightBlock(code); }); // Attach id's to h4 tags so that we can link to specific bifs. Array.prototype.slice.call(document.querySelectorAll('h4')).forEach(function (h4) { var html = h4.innerHTML.split(/\s+/g); html[0] = '<span class="bif" id="' + html[0] + '">' + html[0] + '</span>'; h4.innerHTML = html.join(' '); h4.className = 'visible'; }); // Fix relative link issues with the github site living in a subdirectory Array.prototype.slice.call(document.querySelectorAll('.content a')).forEach(function (a) { if (/^\/cream-and-sugar\//.test(location.pathname)) { a.setAttribute('href', '/cream-and-sugar' + a.getAttribute('href')) } }); // Some script conflict is preventing us from linking to a certain // spot on the page so here we just wait until the next run loop // and if we have a hash in the location object, scroll to it. (function () { var hash = location.hash; if (hash) { var item = document.querySelector(hash); setTimeout(function () { item && window.scroll(0, item.offsetParent.offsetTop); },0); } }()); // Fixes a responsiveness issue where on large screens sometimes // the offgray sidebar isn't tall enough. Make sure its always // tall enough whenever the screen resizes. (function () { var branding = document.querySelector('.branding'); var content = document.querySelector('.content'); function resizerizer() { var brandingHeight = branding.offsetHeight; content.style.height = ''; if (content.offsetHeight < brandingHeight) { content.style.height = brandingHeight + 'px'; } } window.addEventListener('resize', resizerizer); resizerizer(); }()); }); </script> <script src="../../assets/js/app.js"></script> </body> </html>