| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <meta name="generator" content="Asciidoctor 2.0.15"> |
| <title>Generics</title> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> |
| <!-- ************* Meta ************* --> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> |
| |
| <!-- ************* OpenGraph ************--> |
| <meta name="description" content="The Eclipse N4JS language and its IDE enable high-quality JavaScript development for large Node.js projects."> |
| |
| <meta property="og:site_name" content="Eclipse N4JS"/> |
| <meta property="og:title" content="Eclipse N4JS Language and IDE"/> |
| <meta property="og:url" content="https://numberfour.github.io/n4js"/> |
| <meta property="og:description" content="The Eclipse N4JS language and its IDE enable high-quality JavaScript development for large Node.js projects."/> |
| <meta property="og:image" content="../images/n4js.png"> |
| |
| <!-- ************* Favicon ************--> |
| <link rel="icon" href="../images/favicon.ico" /> |
| <link rel="icon" type="image/png" href="../images/favicon-32x32.png" sizes="32x32" /> |
| <link rel="icon" type="image/png" href="../images/favicon-16x16.png" sizes="16x16" /> |
| |
| <!-- ************* Back-to-top JQuery ************* --> |
| <script src="https://code.jquery.com/jquery-1.12.4.js"></script> |
| <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script> |
| |
| <!-- ************* Prism.js Syntax Highlighter ******--> |
| <link href="../styles/prism.min.css" rel="stylesheet"/> |
| <script src="../scripts/prism.js"></script> |
| |
| <!-- ************* Styles ************* --> |
| |
| <link rel="stylesheet" type="text/css" href="../styles/n4js-adoc.css"> |
| |
| <!-- ****************** NavBar ****************** --> |
| <div id="menubar"> |
| <div class="banner"> |
| <a href="../index.html"><img id="logo" src="../images/n4js-logo.png" alt="Eclipse N4JS Language and IDE"></a> |
| </div> |
| <ul> |
| <li><a href="../downloads.html"></i>Download</a></li> |
| <li><a href="../community.html"></i>Community</a></li> |
| <li><a href="../userguides/index.html">Documentation</a></li> |
| </ul> |
| </div> |
| <button id="tocbutton">TOC</button> |
| </head> |
| <body class="book"> |
| <div id="header"> |
| </div> |
| <div id="content"> |
| <h1 id="_generics" class="sect0"><a class="link" href="#_generics">Generics</a></h1> |
| <div class="openblock partintro"> |
| <div class="title">Generics</div> |
| <div class="content"> |
| Generics in N4JS are a language feature that allows for generic programming. They enable |
| a function, class, interface, or method to operate on the values of various (possibly unknown) |
| types while preserving compile-time type safety. If you are familiar with Java’s generics, |
| then N4JS’s generics will look familiar as well. There are some differences, however, which we |
| shall describe below. |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_motivation"><a class="link" href="#_motivation">Motivation</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Several language elements may be declared in a generic form; we’ll start with focusing on classes, |
| generic methods will be discussed after that.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The standard case, of course, is a non-generic class. Take the following class, for example, that |
| bundles a pair of two strings:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">export public class PairOfString { |
| first: string; |
| second: string; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This implementation is fine as long as all we ever want to store are strings. As experience shows, |
| someone is soon to come up with the idea of storing two values of another type, such as…​ numbers! |
| Let’s add another class:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">export public class PairOfNumber { |
| first: number; |
| second: number; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Following this pattern of adding more classes for new types to be stored obviously has its limitations. |
| We would soon end up with a multitude of classes that are basically serving the same purpose, leading to |
| code duplication, terrible maintainability and many other problems.</p> |
| </div> |
| <div class="paragraph"> |
| <p>One solution could be having a class that stores two values of type <code>any</code> (in N4JS, |
| <code>any</code> is the so-called 'top type', the common supertype of all other types).</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">export public class PairOfWhatEver { |
| first: any; |
| second: any; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Now we’re worse off than before. We have lost the certainty that within a single pair, both values |
| will always be of the same type. When reading a value from a pair, we have no clue what its |
| type might be.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_generic_classes_and_interfaces"><a class="link" href="#_generic_classes_and_interfaces">Generic Classes (and Interfaces)</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The way to solve our previous conundrum using generics is to introduce a <strong>type variable</strong> for the class |
| We will then call such a class a <strong>generic class</strong>. |
| A type variable can then be used within the class declaration just as any other ordinary type.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">export public class Pair<T> { |
| first: T; |
| second: T; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The type variable <code>T</code>, declared after the class name in angle brackets, now represents |
| the type of the values stored in the <code>Pair</code> and can be used as the type of the two fields.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Now, whenever we refer to the class <code>Pair</code>, we will provide a <strong>type argument</strong>, in other words a |
| type that will be used wherever the type variable <code>T</code> is being used inside the class |
| declaration.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { Pair } from 'Pair'; |
| |
| let myPair = new Pair<string>(); |
| myPair.first = '1st value'; |
| myPair.second = '2nd value';</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>By using a type variable, we have not just allowed any given type to be used as value type, |
| we have also stated that both values, first and second, must always be of the same type. We |
| have also given the type system a chance to track the types of values stored in a <code>Pair</code>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { Pair } from 'Pair'; |
| |
| let myPair2 = new Pair<string>(); |
| myPair2.first = '1st value'; |
| myPair2.second = 42; // error: 'int is not a subtype of string.' |
| |
| console.log(myPair2.first.charAt(2)); |
| // type system will know myPair2.first is of type string</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The error in line 3 shows that the type checker will make sure we won’t put any value of incorrect |
| type into the pair. The fact that we can access method <code>charAt()</code> (available on strings) |
| in the last line indicates that when we read a value from the pair, the type system knows its type |
| and we can use it accordingly.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Generic interfaces can be declared in exactly the same way.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_generic_functions_and_methods"><a class="link" href="#_generic_functions_and_methods">Generic Functions (and Methods)</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>With the above, we can now avoid introducing a multitude of classes that are basically serving the |
| same purpose. It is still not possible, however, to write code that manipulates such pairs regardless of the type of |
| its values may have. For example, a function for swapping the two values of a pair and |
| then return the new first value would look like this:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { PairOfString } from 'PairOfString'; |
| |
| function swapStrings1(pair: PairOfString): string { |
| let backup = pair.first; // inferred type of 'backup' will be string |
| pair.first = pair.second; |
| pair.second = backup; |
| return pair.first; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The above function would have to be copied for every value type to be supported. Using the generic class |
| <code>Pair<T></code> does not help much:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { Pair } from 'Pair'; |
| |
| function swapStrings2(pair: Pair<string>): string { |
| let backup = pair.first; // inferred type of 'backup' will be string |
| pair.first = pair.second; |
| pair.second = backup; |
| return pair.first; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The solution is not only to make generic the type being manipulated generic (as we have done with class |
| <code>Pair<T></code> above) but to make the code performing the manipulation generic:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { Pair } from 'Pair'; |
| |
| function <T> swap(pair: Pair<T>): T { |
| let backup = pair.first; // inferred type of 'backup' will be T |
| pair.first = pair.second; |
| pair.second = backup; |
| return pair.first; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>We have introduced a type variable for function <code>swap()</code> in much the same way as |
| we have done for class <code>Pair</code> in the previous section (we then call such a function |
| a <strong>generic function</strong>). Similarly, we can use the type variable in this function’s signature |
| and body.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is possible to state in the declaration of the function <code>swap()</code> above that |
| it will return something of type <code>T</code> when having obtained a <code>Pair<T></code> without |
| even knowing what type that might be. This allows the type system to track the type of values passed |
| +between functions and methods or put into and taken out of containers and so on.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Generic methods</strong> can be declared just as generic functions. There is one caveat, however: |
| Only if a method introduces its own, new type variables is it called a generic method. If it is |
| merely using the type variables of its containing class or interface, it’s an ordinary method. |
| The following example illustrates the difference:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">export public class Pair<T> { |
| … |
| public foo(): T { … } |
| public <S> bar(pair: Pair2<S>): void { … } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The first method <code>foo</code> is a non generic method, while the second one <code>bar</code> is.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A very interesting application of static methods is when using in combination with function type arguments:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">class Pair<T> { |
| … |
| <R> merge(merger: {function(T,T): R}): R { |
| return merger(this.first, this.second); |
| } |
| } |
| |
| var p = new Pair<string>(); |
| … |
| var i = p.merge( (f,s)=> f.length+s.length )</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>You will notice that N4JS can infer the correct types for the arguments and the return type of the arrow expression. Also the type for <code>i</code> will be automatically computed.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_differences_to_java"><a class="link" href="#_differences_to_java">Differences to Java</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Important differences between generics in Java and N4JS include:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Primitive types can be used as type arguments in N4JS.</p> |
| </li> |
| <li> |
| <p>There are no raw types in N4JS. Whenever a generic class or interface is referenced, a type argument has to be provided - possibly in the form of a wildcard. For generic functions and methods, an |
| explicit definition of type arguments is optional if the type system can infer the type arguments |
| from the context.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div id="footer"> |
| <div id="footer-text"> |
| </div> |
| </div> |
| <div class="Grid social" style="color:#d5dfea"> |
| <div class="Cell Cell--2-12 m-Cell--withMargin"> |
| <h2>Quick Links</h2> |
| <ul> |
| <li><a href="../downloads.html">Download</a></li> |
| <li><a href="../userguides/index.html">Documentation</a></li> |
| <li><a href="https://github.com/eclipse/n4js/">Source</a></li> |
| <li><a href="https://github.com/eclipse/n4js/issues">Issues</a></li> |
| </ul> |
| </div> |
| <div class="Cell Cell--2-12 m-Cell--withMargin"> |
| <br/><br/> |
| <ul> |
| <li><a href="https://www.eclipse.org/forums/index.php/f/365/">Forum</a></li> |
| <li><a href="http://n4js.blogspot.de/">Blog</a></li> |
| <li><a href="https://dev.eclipse.org/mailman/listinfo/n4js-dev">Mailing List</a></li> |
| <li><a href="https://projects.eclipse.org/projects/technology.n4js">Eclipse Project Page</a></li> |
| <li><a href="https://twitter.com/n4jsdev">Tweets by n4jsdev</a></li> |
| </ul> |
| </div> |
| <div class="Cell Cell--2-12 m-Cell--withMargin"> |
| <br/><br/> |
| <ul> |
| <li><a href="http://www.eclipse.org/">Eclipse Home</a></li> |
| <li><a href="http://www.eclipse.org/legal/privacy.php">Privacy Policy</a></li> |
| <li><a href="http://www.eclipse.org/legal/termsofuse.php">Terms of Use</a></li> |
| <li><a href="http://www.eclipse.org/legal/copyright.php">Copyright Agent</a></li> |
| <li><a href="http://www.eclipse.org/legal/">Legal</a></li> |
| </ul> |
| </div> |
| <div style="clear: both; height: 0; overflow: hidden;"></div> |
| </div> |
| |
| <script> |
| // Toggle the table of contents |
| $( "button#tocbutton" ).click(function() { |
| if ($("#tocbutton").css('right') == '25px') { |
| $( "#tocbutton" ).animate({right: '215px'},"slow"); |
| $( "#toc.toc2" ).animate({right: '0'},"slow"); |
| } |
| else { |
| $( "#tocbutton" ).animate({right: '25px'},"slow"); |
| $( "#toc.toc2" ).animate({right: '-13rem'},"slow"); |
| } |
| }); |
| </script> |
| |
| <script type="text/javascript"> |
| // Create a back to top button |
| $('body').prepend('<a href="#" class="back-to-top">Back to Top</a>'); |
| var amountScrolled = 300; |
| $(window).scroll(function() { |
| if ( $(window).scrollTop() > amountScrolled ) { |
| $('a.back-to-top').fadeIn('slow'); |
| } else { |
| $('a.back-to-top').fadeOut('slow'); |
| } |
| }); |
| $('a.back-to-top, a.simple-back-to-top').click(function() { |
| $('html, body').animate({ |
| scrollTop: 0 |
| }, 700); |
| return false; |
| }); |
| </script> |
| </body> |
| </html> |