James Earl Douglas
August 14, 2015
What JavaScript taught me about programming in Scala
A series of lessons that take ideas from JavaScript and use them to improve Scala development.
What JavaScript taught me about programming in Scala
These are subjective and biased, and I only recommend them to an audience of me.
8ball, acorn, ADsafe, Agda, Alasql, Amber, ANTLR 3, asm.js, AtScript, Babel, Bck2Brwsr, bdParse, Bennu, BicaJVM, BiwaScheme, Blade, Blockly, Blue Storm, Bonsai-C, Bridge.NET, browserl, Brozula, Brython, Bulbul, burrito, Caffeine, Caja, Canopy, Ceylon, Cheerp, Chlorinejs, CirruScript, Clamato, ClojureJS, ClojureScript, Closure Compiler, Closure Compiler AST Documentation, Clue, CobolScript, Coco, CoffeeScript, CoffeeScript II: The Wrath of Khan, CokeScript, ColaScript, ColdRuby, ContextJS, Continuation.js, Contracts.coffee, Ć Programming Language, Cruiser.Parse, Daonode, Dart, defrac, Dogescript, Dojo Secure, Doppio, DotNetWebToolkit, Dragome SDK, DuoCode, E, Earl Grey, ecma-ast, EcmaScript 5 Parser (es-lab), EcmaScript 5 Parser (qfox), EdgeLisp, Elevate Web Builder, Elm, EmberScript, Emscripten, ErlyJS, escodegen, esmangle, Esprima, Este.js, estraverse, ESTree Specification, falafel, Fantom, Fargo, fay, FBJS, Flapjax, Flow, forml, Fun, FunScript, Gatekeeper, ghcjs, Gnusto, Go2js, GopherJS, GorillaScript, GrooScript, GWT, Ham, haste, Haxe, heap.coffee, Hodor, Hot Cocoa Lisp, Hot Cocoa Lisp, HotRuby, IcedCoffeeScript, Idris, Illumination, j2js, Jacaranda, Jack, jangaroo, Java2Script, JavaScript++, JavaScript Shaper, JavaScript types, JEnglish, jison, jisp, jisp, jLang, jmacro, Jotlin, js--, jsc, JScala, JS/CC, JScriptSuite, jsForth, JSGLR, jshaskell, JSIL, js.js, JsMaker, Js_of_ocaml, JsonML AST, jsparse, JSPipe, js-scala, JSX, JSX, jwacs, Kaffeine, Kal, Khepri, ki, ki, Kotlin, lambdascript, languagejs, Latte JS, LispyScript, LispyScript, LiteScript, Little Smallscript, Lively Kernel, LLJS, Local.js, Logo Interpreter, lua.js, LuvvieScript, LZX (Laszlo XML), Maeda Block, maja, Mandreel, Mascara, Meemoo, MetaCoffee, Microsoft Web Sandbox, MileScript, mobl, mobl, Moby Scheme, Mochiscript, Moescript, Monkey, MoonScript, move, Narcissus, NarrativeJS, nconc, nearley, NemerleWeb, Netjs, NGN APL, Nim, node-jvm, NoFlo, NS Basic/App Studio, Objective-J, O'Browser, Ocamljs, Oia, oj, OMeta/JS, Opa, Opal, Oppo, Outlet, p2js, p4js, Parenscript, Parsec CoffeeScript, parse-js, PEG.js, Perlito, php.js, phype, Pit, Plaid, pogoscript, Prefix, Processing, promiseLand, PureScript, PyCow, Pygmy, Pyjaco, Pyjamas, Pyjs, PyPyJS, pythonscript, PythonScript, PyvaScript, PYXC-PJ, qb.js, Quby, Quixe, QWT, Ralph, RapydScript, rb2js, Reb2Static, Red, RedScript, reflect.js, ReParse, Restrict Mode, rocambole, Roy, RPN, Ruby2JS, RubyJS, Rusthon, Saltarelle, scalagwt, Scala.js, scheme2js, Script#, ScriptBlocks, Scriptjure, SharpKit, Shen, Shift JavaScript AST Specification, Sibilant, Sibilant, Silver Smalltalk, Six, Skulpt, Smart Mobile Studio, SMLtoJs, Snap, SourceMap, Spider, Spiderbasic, SpiderMonkey Parser API, Spock, sqld3, sql-parser, SqueakJS, STIP.js, StratifiedJS, Streamline.js, Stripes, Strongly-Typed JavaScript (STJS), Sugar, sweet.js, Swym, Taijilang, TameJS, TARDISgo, TeaVM, TeJaS, TIScript, TLC, ToffeeScript, Topaz, Traceur, treehugger, Typecast.js, TypeScript, Uberscript, UglifyJS, UHC, uilang, uniter, Ur, Waterbear, WebAssembly, WebSharper, wForth, Whalesong, Wind.js, wisp, wisp, WootzJs, Wortel, XLCC, YHC, Zeon, ZeParser
Hey, this looks just like Java/Haskell/ML/BASIC!
-- Java/Haskell/ML/BASIC developer
SIP-18 imposes language modularization via imports, which influence coding style.
Consensus is unlikely to happen on its own.
Again, consensus is unlikely to happen on its own.
// package mathz {
// trait Mathz {
// abstract class Mathz {
// class Mathz {
object Mathz {
def square(x: Int): Int = x * x
}
Module layout depends on environmental pressures:
JSHint catches the typo:
One undefined variable
16helloworld
One unused variable
12helloWorld
~compile
,
~test
)What does this function do?
¯\_(ツ)_/¯
What about this one?
Maybe it doubles
x
.
Perhaps it returns 42.
How about now?
foo(x)
can only possibly returnx
.
JavaScript projects rely heavily on testing to assert correctness.
Even with the compiler, tests are crucial in Scala.
Given a version number MAJOR.MINOR.PATCH, increment the:
- MAJOR version when you change existing tests
- MINOR version when you add new tests
- PATCH version when you don't change the tests
Unexpected things can happen.
function nextYear(date) {
return {
day: date.day,
month: date.month,
year: date.year++,
};
}
var d = { day: 14, month: 8, year: 2015 };
nextYear(d) === nextYear(d) // false
nextYear(x)
is not referentially transparent.
case class Date(day: Int, month: Int, year: Int)
def nextYear(date: Date): Date = {
date.copy(year = date.year + 1)
}
val d = Date(day = 14, month = 8, year = 2015)
nextYear(d) == nextYear(d) // true
nextYear(x)
can't change the value of
x
.
Single-threadedness makes things easy.
This would be unsafe with multiple threads.
State
in Scalacase class State[A,S](run: S => (A,S)) {
def map[B](g: A => B): State[B,S] =
State({ s =>
val (a,s2) = run(s)
(g(a),s2)
})
def flatMap[B](g: A => State[B,S]): State[B,S] =
State({ s =>
val (a,s2) = run(s)
g(a).run(s2)
})
}
You could do this in JavaScript too, but holy type system, Batman.
def
or val
to var
var
s to threadsafe codeimport
This could be done similarly with a YAML configuration file.
Eval
Node.js projects automatically include the source code of their dependencies.
node_modules/mocha/lib/test.js:
$ time node hello.js
Hello, world!
real 0m0.075s
user 0m0.061s
sys 0m0.014s
$ time sbt run
Hello, world!
real 0m6.488s
user 0m10.225s
sys 0m0.980s
Source: githut.info
99% of all Web users can run JavaScript code.
Source: YDN
First-time users will npm adduser
or
npm login
.
After that, deployment is roughly one step.
$ npm publish
For new and existing users, deployment is roughly eleventy billion steps.