{"id":554,"date":"2018-05-23T03:41:15","date_gmt":"2018-05-23T03:41:15","guid":{"rendered":"http:\/\/www.onux.com\/jspp\/blog\/?p=554"},"modified":"2018-05-23T16:48:30","modified_gmt":"2018-05-23T16:48:30","slug":"js-0-8-4-advanced-generics-and-system-string-expansion","status":"publish","type":"post","link":"https:\/\/www.onux.com\/jspp\/blog\/js-0-8-4-advanced-generics-and-system-string-expansion\/","title":{"rendered":"JS++ 0.8.4: Advanced Generics and System.String Expansion"},"content":{"rendered":"<p>We have significantly expanded the Standard Library with this release. In particular, System.String has undergone significant expansion.<\/p>\n<h3>System.String Highlights<\/h3>\n<p><b>between<\/b><\/p>\n<pre class=\"brush:jspp\">\r\nstring quotedWords = '\"duck\" \"swan\" \"crab\"';\r\n\/\/ 'between' is smart enough to allow the same string to be used as a start and end delimiter\r\nstring[] words = quotedWords.between('\"', '\"');\r\nConsole.log(words); \/\/ [ \"duck\", \"swan\", \"crab\" ]\r\n<\/pre>\n<p>Documentation page: <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/String\/between\" rel=\"noopener\" target=\"_blank\">click here<\/a><\/p>\n<p><b>format: C-like printf<\/b><\/p>\n<pre class=\"brush:jspp\">\r\n\"%s is %d years old\".format(\"Joe\", 10) \/\/ Joe is 10 years old\r\n<\/pre>\n<p>Documentation page: <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/String\/format\" rel=\"noopener\" target=\"_blank\">click here<\/a><\/p>\n<p><b>escape<\/b><\/p>\n<pre class=\"brush:jspp\">\r\n\"a\\r\\nb\".escape() \/\/ a\\\\r\\\\nb\r\n<\/pre>\n<p>Documentation page: <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/String\/escape\" rel=\"noopener\" target=\"_blank\">click here<\/a><\/p>\n<p><b>truncate<\/b><\/p>\n<pre class=\"brush:jspp\">\r\nstring text = \"The quick brown fox jumped over the lazy dog.\";\r\n \r\nConsole.log(text.truncate(9)); \/\/ \"The quick...\"\r\n<\/pre>\n<p>Documentation page: <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/String\/truncate\" rel=\"noopener\" target=\"_blank\">click here<\/a><\/p>\n<p><b>repeat<\/b><\/p>\n<pre class=\"brush:jspp\">\r\n\"*\".repeat(5) \/\/ *****\r\n<\/pre>\n<p>Documentation page: <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/String\/repeat\" rel=\"noopener\" target=\"_blank\">click here<\/a><\/p>\n<p><b>count<\/b><\/p>\n<pre class=\"brush:jspp\">\r\n\"foobar\".count(\"foo\") \/\/ 1\r\n\"FOOBAR\".icount(\"foo\") \/\/ 1\r\n<\/pre>\n<p>Documentation (count): <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/String\/count\" rel=\"noopener\" target=\"_blank\">click here<\/a><br \/>\nDocumentation (icount): <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/String\/icount\" rel=\"noopener\" target=\"_blank\">click here<\/a><\/p>\n<p><b>contains<\/b><\/p>\n<pre class=\"brush:jspp\">\r\n\"abc\".contains(\"b\") \/\/ true\r\n\"ABC\".icontains(\"b\") \/\/ true\r\n<\/pre>\n<p>Documentation (contains): <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/String\/contains\" rel=\"noopener\" target=\"_blank\">click here<\/a><br \/>\nDocumentation (icontains): <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/String\/icontains\" rel=\"noopener\" target=\"_blank\">click here<\/a><\/p>\n<h3>New System.String Methods<\/h3>\n<p>Here are all the new methods available for strings in JS++:<\/p>\n<ul>\n<li>between &#8211; Gets substrings between two delimiters (does not use regex)<\/li>\n<li>compact &#8211; Removes whitespace globally<\/li>\n<li>contains\/icontains<\/li>\n<li>count\/icount<\/li>\n<li>countLines<\/li>\n<li>countNonEmptyLines<\/li>\n<li>startsWith\/endsWith<\/li>\n<li>escape\/unescape &#8211; Escape the escape sequence characters (e.g. \\n -> \\\\n)<\/li>\n<li>escapeQuotes\/unescapeQuotes<\/li>\n<li>format &#8211; Similar to C&#8217;s printf<\/li>\n<li>insert\/append\/prepend<\/li>\n<li>isEmpty &#8211; uses .length === 0 rather than str1 === &#8220;&#8221; for performance, not everyone has time to benchmark every detail<\/li>\n<li>isLowerCase<\/li>\n<li>isUpperCase<\/li>\n<li>isWhitespace<\/li>\n<li>joinLines &#8211; collapses a string composed of multiple lines into a single line<\/li>\n<li>joinNonEmptyLines<\/li>\n<li>padLeft\/padRight &#8211; remember the NPM debacle?<\/li>\n<li>quote\/quoteSingle &#8211; wraps the string in quotes<\/li>\n<li>unquote &#8211; removes quote pairs<\/li>\n<li>repeat &#8211; &#8220;*&#8221;.repeat(3) == &#8220;***&#8221;<\/li>\n<li>reverse<\/li>\n<li>splitLines &#8211; splits a string into a string[] (array) based on newlines<\/li>\n<li>trim, trimLeft, trimRight, trimMulti, trimMultiLeft, trimMultiRight<\/li>\n<li>truncate &#8211; Cuts off the string at the specified length (with support for custom ellipsis)<\/li>\n<\/ul>\n<p>There are close to 50 new string methods (48 including overloads, 39 otherwise), and these methods should cover most application-level usages. With documentation, this resulted in +1400 new lines of code to System.String. I&#8217;m happy to announce we actually still have <em>more<\/em> methods (for System.String and others) on the way.<\/p>\n<p>Every single method is documented. All documentation is online and available at the <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/String\" rel=\"noopener\" target=\"_blank\">System.String<\/a> index page.<\/p>\n<p>We avoided regular expressions as much as possible to avoid runtime FSM construction, which takes time and space. Therefore, prefer JS++ methods such as <code>\"abc\".endsWith(\"c\")<\/code> over the traditional regex\/JavaScript <code>\/c$\/.test(\"abc\")<\/code>.<\/p>\n<p>The best thing about JS++ is that it&#8217;s a compiled language. This gives you performance benefits that a JavaScript library with string utilities can never give you. For example:<\/p>\n<pre class=\"brush:jspp\">\r\nif (\"abc\".isEmpty());\r\n<\/pre>\n<p>becomes:<\/p>\n<pre class=\"brush:jspp\">\r\nif (\"abc\".length===0);\r\n<\/pre>\n<p>and<\/p>\n<pre class=\"brush:jspp\">\r\n\"abc\".quote()\r\n<\/pre>\n<p>becomes:<\/p>\n<pre class=\"brush:jspp\">\r\n'\"'+\"abc\"+'\"'\r\n<\/pre>\n<p>The astute observer will notice that both the above methods can be further optimized to reach &#8220;perfect&#8221; optimization. However, there is no optimizing compiler inside JS++ yet, and inserting branching logic into the code generator will result in technical debt.<\/p>\n<p>Our goal with the Standard Library is to make it easier than ever to write applications compared to JavaScript. Side effects of our work on the JS++ Standard Library are performance, size, and correctness. JS++ dead code elimination means we can add hundreds of methods to System.String, but you only pay for the methods you actually use. For performance, not every team can afford to hire a JavaScript performance expert. Even if you have the performance expert, he can&#8217;t be expected to micro-optimize and benchmark every method.<\/p>\n<p>Finally, with the JS++ Standard Library, we can fully avoid the <a href=\"https:\/\/www.theregister.co.uk\/2016\/03\/23\/npm_left_pad_chaos\/\" rel=\"noopener\" target=\"_blank\">NPM left-pad debacle<\/a>.<\/p>\n<pre class=\"brush:jspp\">\r\nimport System;\r\n\r\nConsole.log(\"1\".padLeft(4, \"0\")); \/\/ \"0001\"\r\n<\/pre>\n<h3>fromString<\/h3>\n<p>Previously, to convert a string to number in JS++, it was a little unintuitive. For example:<\/p>\n<pre class=\"brush:jspp\">\r\nint x = +\"1000\"; \/\/ use the unary + operator\r\n<\/pre>\n<p>For all numeric types, we&#8217;ve introduced the <code>fromString<\/code>, <code>fromStringOr<\/code>, and <code>fromStringOrThrow<\/code> static methods. The above example can be re-written to use <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/Integer32\/fromString\" rel=\"noopener\" target=\"_blank\">Integer32.fromString<\/a>:<\/p>\n<pre class=\"brush:jspp\">\r\nint x = Integer32.fromString(\"1000\");\r\n<\/pre>\n<h3>Advanced Generics<\/h3>\n<p>JS++ 0.8.4 introduces covariant and contravariant generic types (including upcasting and downcasting for types with variants). Covariance and contravariance are based on use-site variance. At this time, we are not introducing declaration-site variance at all; we have higher priorities. In addition, we&#8217;ve introduced generic constraints (subtype constraints, multiple constraints, wildcard constraints, and more).<\/p>\n<p>Finally, we have support for generic functions and generic static methods.<\/p>\n<p>Everything from basic to advanced generic programming in JS++ is covered in our <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Language-Guide\/generic-programming\" rel=\"noopener\" target=\"_blank\">generic programming documentation<\/a>.<\/p>\n<p>When we released version <a href=\"https:\/\/www.onux.com\/jspp\/blog\/js-0-8-0-altitude-mvc-generics-dictionary-and-more\/\" rel=\"noopener\" target=\"_blank\">0.8.0<\/a>, we introduced only basic generics. In today&#8217;s 0.8.4 release, you can consider generics fully implemented.<\/p>\n<p>I highly encourage reading the generic programming documentation. To put it all together, here&#8217;s generic covariance and contravariance together with use-site variance:<\/p>\n<pre class=\"brush:jspp\">\r\nimport System;\r\n \r\nabstract class Animal {}\r\nclass Tiger : Animal {}\r\n \r\nabstract class Pet : Animal {}\r\nclass Dog : Pet {}\r\nclass Cat : Pet {}\r\n \r\nclass PetCollection\r\n{\r\n    Pet[] data = [];\r\n \r\n    void insert(descend Pet[] pets) {\r\n        foreach(Pet pet in pets) {\r\n            this.data.push(pet);\r\n        }\r\n    }\r\n \r\n    ascend Pet[] get() {\r\n        return this.data;\r\n    }\r\n}\r\n \r\nauto myPets = new PetCollection();\r\n \r\n\/\/ Write operations (descend, covariance)\r\nmyPets.insert([ new Dog, new Cat ]);\r\n\/\/ myPets.insert([ new Tiger ]); \/\/ not allowed\r\n \r\n\/\/ Read operations (ascend, contravariance)\r\nPet[] getPets = [];\r\nAnimal[] getAnimals = [];\r\nascend Pet[] tmp = myPets.get(); \/\/ read here\r\nforeach(Pet pet in tmp) { \/\/ but we still need to put them back into our \"result\" arrays\r\n    getPets.push(pet);\r\n    getAnimals.push(pet);\r\n}\r\n \r\n\/\/ Now we can modify the arrays we read into above\r\ngetPets.push(new Dog);\r\ngetAnimals.push(new Dog);\r\ngetAnimals.push(new Tiger);\r\n\/\/ getPets.push(new Tiger); \/\/ ERROR\r\n<\/pre>\n<h3>Other Changes<\/h3>\n<ul>\n<li>Fix return types for <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/String\/charAt\" rel=\"noopener\" target=\"_blank\">System.String.charAt<\/a> and <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Standard-Library\/System\/String\/charCodeAt\" rel=\"noopener\" target=\"_blank\">System.String.charCodeAt<\/a><\/li>\n<li>Fix type promotion to &#8216;double&#8217;. We now handle this better than languages like Java and C#. Thanks to our lead engineer, Anton, for the idea.<\/li>\n<li>isEven() and isOdd(). You might think this is fizz buzz, but if you&#8217;re using the modulus operator, <a href=\"https:\/\/www.onux.com\/jspp\/blog\/standard-library-performance-iseven-and-isodd\/\" rel=\"noopener\" target=\"_blank\">it&#8217;ll be slower<\/a>. We use bitwise operations, and you might be interested in reading <a href=\"https:\/\/www.onux.com\/jspp\/blog\/leveraging-integer-overflow-to-improve-performance-while-preserving-correctness\/\" rel=\"noopener\" target=\"_blank\">this article on how we took advantage of overflow behavior<\/a> to improve performance while preserving correctness.<\/li>\n<li>Fix System.Array.map and System.Array.reduce to support wildcard generic types.<\/li>\n<li>Type inference of generic parameters for function calls. This is needed for System.Array.map and System.Array.reduce, but it&#8217;s also available for user-side code.<\/li>\n<li>Fix <code>System.Console.error<\/code> when no console is available<\/li>\n<li>Fixed error message with incorrect type for setters defined with no accompanying getters.<\/li>\n<li>Fixed <code>private<\/code> access modifier for modules in a multi-file setting.<\/li>\n<li>Fix callback types as generic arguments<\/li>\n<li>Fix enum bitwise operations to reduce explicit casting<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>We have significantly expanded the Standard Library with this release. In particular, System.String has undergone significant expansion. System.String Highlights between string quotedWords = &#8216;&#8221;duck&#8221; &#8220;swan&#8221; &#8220;crab&#8221;&#8216;; \/\/ &#8216;between&#8217; is smart enough to allow the same string to be used as a start and end delimiter string[] words = quotedWords.between(&#8216;&#8221;&#8216;, &#8216;&#8221;&#8216;); Console.log(words); \/\/ [ &#8220;duck&#8221;, &#8220;swan&#8221;, &hellip; <a href=\"https:\/\/www.onux.com\/jspp\/blog\/js-0-8-4-advanced-generics-and-system-string-expansion\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;JS++ 0.8.4: Advanced Generics and System.String Expansion&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[2,4],"tags":[],"_links":{"self":[{"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/posts\/554"}],"collection":[{"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/comments?post=554"}],"version-history":[{"count":40,"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/posts\/554\/revisions"}],"predecessor-version":[{"id":626,"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/posts\/554\/revisions\/626"}],"wp:attachment":[{"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/media?parent=554"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/categories?post=554"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/tags?post=554"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}