TypeSafe DI in TypeScript

Yet Another Type Level Arithmetics

DI is getting more popularity in JavaScript. Though, those solution is far way beyond JSR-330 compatible libraries in terms of type safety and performance.

This snippet strives to dig more type-safety from TS’ type system. However, it can hardly achieve equivalent type safety like Java’s counterpart, e.g., Dagger, Guice.

Solution

This DI snippet can, ideally, ensure every binding is resolved in compile time, which is a hard task for other DI solution. The main idea is an Injector can statically know its current binding, and judge whether dependencies of a new added binding can be already resolved by itself. Since dependency graph is a DAG, there exists a topological sorting order that every binding’s dependency can be resolved solely by those of preceding bindings . So once the injector is created and bindings are attached to it, we can assert that the dependencies can be resolved.

Say, there is a minimal example to illustrate this:

1
2
3
4
5
6
7
8
9
10
@Inject
class Clerk {}
@Inject
class Shop {constructor(c: Clerk)}
var inj = Injector.create()
.bind(Shop).toClass(Shop) // compile error here, injector cannot resolve Clerk

var inj = Injector.create()
.bind(Clerk).toClass(Clerk)
.bind(Shop).toClass(Shop) // compiles. Clerk resolved before Shop

To implement this, Injector has a shadow type Base that indicates resolved bindings. When new binding is added to injector, compiler will verify the new coming constructor/function will only depend on classes the injector has already resolved. Concretely, every argument in newly added constructor must be a subtype of Base.

1
2
3
4
5
6
7
8
9
10
type Ctor = new (...args: Base[]): T

injector<Base>
.bind(NewClass)
.toClass(NewClass as Ctor)
/*
Make sure here `toClass` is defined like
type toClass = (Ctor) => Injector<Base | T>
the union type indicates resolved type, and `T extends Base|T` holds valid
*/

Base is a large union type storing all binding types, so every resolved type is a subtype of Base. And bind will return a binder that has toClass / toFactory method which further returns an injector whose resolved binding is a union of the previous binding type and the newly added binding type. Hence, after bind ... toClass, the injector has a new class appended to its resolved type list.

The implementation and test can be found at Github Gist.

Problem

But TS’ type system does not allow a full-fledged DI in this way.

  1. First, runtime types are erased. One must annotate dependency for function in toFactory method. toClass is better because TS supports emitDecoratorMetadata. (maybe resolved in TS2.0). TS’ specific metadata implementation is also problematic. For cyclic dependent classes, at least one class’ annotation is undefined(ES3/5), or the script is crashed before it can run (ES6). Because metadata is attached to class declaration, in cyclic case there must be one class is used before it’s declared.

  2. TypeScript has a double-edged sutructural type system. To fully exploit DI’s type check, user has to add a private brand field to every injectable class. This is not a good UI, though.

  3. But even metadata is not enough. Runtime type data is first-order (in type-system’s view), that is, every type is represented by its constructor, no generic information is emitted. To work around this, token is introduced.

Token alleviates runtime type-system’s weakness, and enables binding multiple implementations to one single type. It also introduces more problem this DI wants to resolve in the first place. To work around point 1, we attached runtime types to constructor. Binding token will make type system think a type has resolved, but a following binding may not resolve it in runtime because it depends on constructor to find resolution.

1
2
3
4
5
injector
.bind(clerkToken).toClass(Clerk)
.bind(Shop).toClass(Shop) // compiles. but runtime error
// toClass will analyze Shop's signature and extract the Clerk constructor
// it can be found in type-level because Token<Clerk> enable injector to resolve Clerk, but at runtime injector can only resolve clerkToken, not Clerk

Also, tokens with same types cannot avoid this.

The workaround is, well, abusing string literal type. So every token is different at type-level. This requires users to type more types, and casts string literal from string type to string literal type. (TS’s generic inference does not have something like T extends StringLiteral so that T is inferred as string literal type)

Also, the toClass and toFactory signature should differentiate what can be resolved by constructor and by token. This is technically possible, just override these signature to support distinguishing between token and constructor. But the number of resulting overriding is exponential to the number of argument. 2 ^ n, where n is the number of arguments.

Conclusion

To fully support type-safe DI and higher performance, a compiler extension or a code generator is needed. Java’s DI relies on annotations and code generation.

Maybe Babel can do this right now. But TypeScript still needs a long way to go for a customizable emitter.

Source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import 'reflect-metadata'

type _ = {}

type ClassN<N, T> = { new (...a: N[]): T }
type FN8<A, B, C, D, E, F, G, H, R> = (a?: A, b?: B, c?: C, d?: D, e?: E, f?: F, g?: G, h?: H) => R
type CLS8<A, B, C, D, E, F, G, H, R> = { new (a?: A, b?: B, c?: C, d?: D, e?: E, f?: F, g?: G, h?: H): R}

class Token<T> {
private _tokenBrand
constructor(public name: string) {}
}
type Bindable<T> = Token<T> | ClassN<_, T>

const PARAMTYPE = 'design:paramtypes'

function getSignature<T>(cls: ClassN<T, _>): Array<Bindable<T>> { return Reflect.getOwnMetadata(PARAMTYPE, cls).slice() || [] }

const enum BindType { CLASS, VALUE, FACTORY }
class Binder<T, Base> {
dependencies: Bindable<Base>[] = []
cacheable: boolean = false
private _type: BindType
private _cls: ClassN<any, T> = null
private _val: T
private _fn: Function

constructor(private _injector: Injector<Base>) {}

private _releaseInjector() {
let injector = this._injector
this._injector = null
return injector
}

toClass<A extends Base, B extends Base, C extends Base, D extends Base, E extends Base, F extends Base, G extends Base, H extends Base>(fn: CLS8<A, B, C, D, E, F, G, H, T>, a?: Bindable<A>, b?: Bindable<B>, c?: Bindable<C>, d?: Bindable<D>, e?: Bindable<E>, f?: Bindable<F>, g?: Bindable<G>, h?: Bindable<H>): Injector<Base | T>
toClass(cls: ClassN<Base, T>, ...deps: Bindable<Base>[]): Injector<Base | T> {
this._type = BindType.CLASS
this._cls = cls
this.dependencies = getSignature(cls)
deps.forEach((d, i) => {
if (d) this.dependencies[i] = d
})
return this._releaseInjector()
}

toValue(val: T): Injector<Base | T> {
this._type = BindType.VALUE
this._val = val
this.cacheable = true
return this._releaseInjector()
}

toFactory<A extends Base, B extends Base, C extends Base, D extends Base, E extends Base, F extends Base, G extends Base, H extends Base>(fn: FN8<A, B, C, D, E, F, G, H, T>, a?: Bindable<A>, b?: Bindable<B>, c?: Bindable<C>, d?: Bindable<D>, e?: Bindable<E>, f?: Bindable<F>, g?: Bindable<G>, h?: Bindable<H>): Injector<Base | T>
toFactory(fn: (...a: Base[]) => T, ...deps: Bindable<Base>[]): Injector<Base | T> {
this._type = BindType.FACTORY
this._fn = fn
this.dependencies = deps
return this._releaseInjector()
}

resolve(deps: any[]): Promise<T> {
switch (this._type) {
case BindType.CLASS:
let cls = this._cls
return Promise.resolve(new cls(...deps))
case BindType.VALUE:
return Promise.resolve(this._val)
case BindType.FACTORY:
return Promise.resolve(this._fn(...deps))
}
}
}

export class Injector<Base> {
private _resolving = new Set<Bindable<_>>()
private _typeBinderMap = new Map<Bindable<_>, Binder<_, Base>>()
private _cache = new Map<Bindable<_>, Promise<any>>()

get<T extends Base>(cls: Bindable<T>): Promise<T> {
let binder = this._typeBinderMap.get(cls)
if (!binder) throw new NoBinding(cls['name'])

let cache = binder.cacheable ? this._cache.get(cls) : null
if (cache) {
return cache
}

if (this._resolving.has(cls)) throw new CyclicDependency(cls['name'])

this._resolving.add(cls)
let depPromise = binder.dependencies.map(dep => this.get(dep))
this._resolving.delete(cls)

let ret = Promise.all(depPromise).then(args => binder.resolve(args))
if (binder.cacheable) this._cache.set(cls, ret)
return ret
}

bind<T>(cls: Bindable<T>): Binder<T, Base> {
let binder = new Binder<T, Base>(this)
this._typeBinderMap.set(cls, binder)
return binder
}

static create(): Injector<Injector<_>> {
let inj = new Injector<Injector<_>>()
inj.bind(Injector).toValue(inj)
return inj
}
}

Trouble Shooting NeoVim's rplugin not found

NeoVim is awesome. But after its 0.1 release, neovim is not that awesome, after all, in a old vimmer’s eye.

To support XDG configuration, NeoVim changed default config paths. After that patch, neovim search ~/.config/nvim/init.vim rather than our old friend ~/.nvimrc. So I changed my zshrc to alias v to nvim -u ~/.nvimrc. So I can use old configuration without relocating files.

It works fine, except Deoplete always complain about its remote plugin is not registered. When I execute UpdateRemotePlugins as Deoplete’s doc said, a new .-rplugin- file always spawn in my working directory. Without that weird file, Deoplete will never work.

I think this is configuration problem. But how can I figure out what happened? I start to resolving this by guess.

.-rplugin is the critical file on which Deoplete depends. So NeoVim should search for it when booting. I searched for NeoVim’s repository for its usage. Yes, it does appear in neovim’s source, in neovim/runtime/autoload/remote/host.vim.

It reads:

1
2
let s:remote_plugins_manifest = fnamemodify(expand($MYVIMRC, 1), ':h')
\.'/.'.fnamemodify($MYVIMRC, ':t').'-rplugin~'

Hmmm, NeoVim will find .-rplugin in the same directory of $MYVIMRC. But where does $MYVIMRC come from?

Searching neovim’s doc gives me the answer. In :h starting, it writes:

If Vim was started with “-u filename”, the file “filename” is used.
All following initializations until 4. are skipped. $MYVIMRC is not
set.

Oh, so I have to relocate my vimrc file. After that, every thing works :).

JavaScript Error tracking in browsers

Error tracking is one of the awful part of JavaScript. Server side error tracking requires several configuration, which is not hard because server is under developers’ full control, after all. For Android/iOS applications, error tracking is integrated into integrated into platform framework. Unfortunately, error tracking in browser is like survival in wild jungle.

Here are some common pitfalls.

Incompatible API

JavaScript errors in different browsers have different field names, as usual.

One should never bother to care about api incompatibility among browsers. Here is the snippet to normalize those quirks.
Curse the variable ieEvent.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function errorTracker (err) {
var ieEvent
if (typeof err !== 'object') {
ieEvent = {}
err = window.event
ieEvent.message = err.errorMessage
ieEvent.filename = err.errorUrl
ieEvent.lineno = err.errorLine
err = ieEvent
}

return {
message: err.message,
line: err.lineno || err.lineNumber,
file: err.filename || err.fileName
}
}

CORS Header

You will see a lot of Scritp error message in your CDN hosted javascript file. Browsers report this useless error intentially. Revealing error details to web page in different domain is a security issue. It can leak one’s privacy and helps phishing and social engineering. To quote the SO answer

This behavior is intentional, to prevent scripts from leaking information to external domains. For an example of why this is necessary, imagine accidentally visiting evilsite.com, that serves up a page with <script src="yourbank.com/index.html">. (yes, we’re pointing that script tag at html, not JS). This will result in a script error, but the error is interesting because it can tell us if you’re logged in or not. If you’re logged in, the error might be 'Welcome Fred...' is undefined, whereas if you’re not it might be 'Please Login ...' is undefined. Something along those lines.

And in Chromium’s source code, we can see error is sanitized, if the corsStatus does not satisify some condition.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
bool ExecutionContext::shouldSanitizeScriptError(const String& sourceURL, AccessControlStatus corsStatus)
{
if (corsStatus == OpaqueResource)
return true;
return !(securityOrigin()->canRequestNoSuborigin(completeURL(sourceURL)) || corsStatus == SharableCrossOrigin);
}

bool ExecutionContext::dispatchErrorEvent(PassRefPtrWillBeRawPtr<ErrorEvent> event, AccessControlStatus corsStatus)
{
EventTarget* target = errorEventTarget();
if (!target)
return false;

RefPtrWillBeRawPtr<ErrorEvent> errorEvent = event;
if (shouldSanitizeScriptError(errorEvent->filename(), corsStatus))
errorEvent = ErrorEvent::createSanitizedError(errorEvent->world());

ASSERT(!m_inDispatchErrorEvent);
m_inDispatchErrorEvent = true;
target->dispatchEvent(errorEvent);
m_inDispatchErrorEvent = false;
return errorEvent->defaultPrevented();
}

To enable SharableCrossOrigin scripts, one can add crossorigin attribute to script tags, and, add a Access-Control-Allow-Origin head in scripts’ server response, just like cross orgin XHR.

Like this.

1
<script src="http://somremotesite.example/script.js" crossorigin></script>

And in your server conf, say, nginx, add something like this

1
2
3
4
5
6
7
8
server {
server_name static.jscdn.com;
# blah blah blah

location ~ \.js {
add_header Access-Control-Allow-Origin "*";
}
}

More Browser Quirks and nasty ISP

Modern browser will protect users’ privacy and respect developers’ CORS setting. But IE may screw both. In some unpatched Internet Exploers, all script errors are accessible in onError handler, regardless of their origins. But some Internet Explorers, patched, just ignore the CORS head and swallow all crossorigin error messages.

To catch errors in certain IEs, developers must manually wrap their code in try {...} catch (e){report(e)} block. Alternatively, one can use build process to wrap function, like this.

Zone should also be a good candidate for error tracking, and does not require build process. Though I have not tried it.

Another issue in error tracking is ISP and browser extensions. onError callbacks will receive all error in the host page. It usually contains many ISP injected script and extension script which trigger false alarm errors. So wrapping code in try ... catch may be a better solution.

UPDATE:

It seems Zone like hijacking method has been used in error tracking product. Like BugSnag. The basic idea is: If code is executed synchronously, then it can be try ... catch ...ed in one single main function. If code is executed asynchronously, then, by wrapping all function that takes callback, one can wrap all callbacks in try ...catch ....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function wrap(func) {
// Ensure we only wrap the function once.
if (!func._wrapped) {
func._wrapped = function () {
try{
func.apply(this, arguments);
} catch(e) {
console.log(e.message, "from", e.stack);
throw e;
}
}
}
return func._wrapped;
};

The above code will wrap all func in try and catch. So when error occurs, it will be always logged. However, calling wrapper function in every async code usage is impractical. We can invert it! Not wrapping callbacks, but wrapping functions that consume callbacks, say, setTimeout, addEventListener, etc. Once these async code entries have been wrapped, all callbacks are on track.

And, because JavaScript is prototype based language, we can hijack the EventTarget prototype and automate our error tracking code.

1
2
3
4
var addEventListener = window.EventTarget.prototype.addEventListener;
window.EventTarget.prototype.addEventListener = function (event, callback, bubble) {
addEventListener.call(this, event, wrap(callback), bubble);
}

IE9 and friends

Sadly, IE does not give us stack on error. But we can hand-roll our call stack by traversing argument.callee.caller.

1
2
3
4
5
6
7
8
9
10
11
// IE <9
window.onerror = function (message, file, line, column) {
var column = column || (window.event && window.event.errorCharacter);
var stack = [];
var f = arguments.callee.caller;
while (f) {
stack.push(f.name);
f = f.caller;
}
console.log(message, "from", stack);
}

Garbage Collector Issue

Error reporting is usually done by inserting an Image of which the url is the address of logging server comprised of encoded error info in query string.

1
2
var url = 'xxx';
new Image().src = url;

But the Image has no reference to itself, and JS engine’s garbage collector will collect it before the request is sent. So one can assign the Image to a variable to hold its reference, and withdraw the reference in the onload/onerror callback.

1
2
3
4
5
6
7
var win = window;
var n = 'jsFeImage_' + _make_rnd(),
img = win[n] = new Image();
img.onload = img.onerror = function () {
win[n] = null;
};
img.src = url;

The Real Angular2 quick start

Angular2 official page wants you to make some dirty hack to get the fastest hellow world in Angular2. But it immediately requires to correct your first sin in the same 5-min quickstart page. Maybe it is possible for a newcomert to set up Angular2 properly in 5 minutes, but reverting previous dirty hack and then setting the correct thing up are annoying. So here is the REAL Angular2 quickstart that does not piss you off.

DISCLAIMER: Knowledge about npm, TypeScript and SystemJS is recommended.
This quickstart deliberately skips explanation on the config and shell code for real real speed.

Step 1: Create a new folder for our application project.

1
2
3
mkdir angular2-quickstart
cd angular2-quickstart
mkdir -p src/app

Step 2: Install npm packages

First step towards front end project as usual…

1
2
3
npm init -y
npm i angular2@2.0.0-alpha.44 systemjs@0.19.2 --save --save-exact
npm i typescript live-server --save-dev

Version number sucks, but it will be removed after Angular2’s public stable release.
We need to install angular2 and TypeScript as dependency, of course. SystemJS is used to load our app(alternatively one can use webpack or browserify).
Live-server gives us live-reloading in developement.

Step 4: Set up npm script tasks

Let’s define some useful command.
Find and replace the script section in package.json

1
2
3
4
5
6
...
"scripts": {
"tsc": "tsc -p src -w",
"start": "live-server --open=src"
}
...

npm run tsc compiles and watches file changes. npm start runs the live-reload server.

Step 5: Create our first Angular2 component

Add a new file called app.ts in src/app

1
2
3
4
5
6
7
import {Component, bootstrap} from 'angular2/angular2';
@Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1>'
})
class AppComponent { }
bootstrap(AppComponent);

Step 6: Create our entrance html

Create an index.html in src foler.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<html>
<head>
<title>Angular 2 QuickStart</title>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
<script>
System.config({
packages: {
'app': {defaultExtension: 'js'} // defaultExtension makes require `app/app` works without `.js`
// more packages config goes here
// ...
}
});
System.import('app/app');
</script>
</head>
<body>
<my-app>loading...</my-app>
</body>
</html>

Step 7: Compile TypeScript

Create tsconfig.json in the src folder.

1
2
3
4
5
6
7
8
9
10
11
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
}
}

And then, in a new terminal window.

1
npm run tsc

Step 8: Run the app!

And in yet another new terminal window.

1
npm start

You should see My First Angular2 App in your browser.

Hooray!

Now you can make some changes to your source file. tsc compiles file on the fly and live-server automatically refreshes the browser!

Hope you are not pissed off by this quickstart.

P.S. Final structure

1
2
3
4
5
6
7
8
angular2-quickstart
├── node_modules
├── src
│ ├── app
| │ └── app.ts
│ ├── index.html
│ └── tsconfig.json
└── package.json

Updated Ctags for TypeScript

TypeScript has a decent tooling chain. However, sometimes a simple ctags is more handy and efficient.

Here is a updated ctag configuration for TypeScript. It supports more features in TS 1.5+.

1
2
3
4
5
6
7
8
9
10
11
12
13
--langdef=typescript
--langmap=typescript:.ts
--regex-typescript=/^[ \t]*(export)?[ \t]*class[ \t]+([a-zA-Z0-9_]+)/\2/c,classes/
--regex-typescript=/^[ \t]*(export)?[ \t]*abstract class[ \t]+([a-zA-Z0-9_]+)/\2/a,abstract classes/
--regex-typescript=/^[ \t]*(export)?[ \t]*module[ \t]+([a-zA-Z0-9_]+)/\2/n,modules/
--regex-typescript=/^[ \t]*(export)?[ \t]*type[ \t]+([a-zA-Z0-9_]+)/\2/t,types/
--regex-typescript=/^[ \t]*(export)?[ \t]*namespace[ \t]+([a-zA-Z0-9_]+)/\2/n,modules/
--regex-typescript=/^[ \t]*(export)?[ \t]*function[ \t]+([a-zA-Z0-9_]+)/\2/f,functions/
--regex-typescript=/^[ \t]*export[ \t]+var[ \t]+([a-zA-Z0-9_]+)/\1/v,variables/
--regex-typescript=/^[ \t]*var[ \t]+([a-zA-Z0-9_]+)[ \t]*=[ \t]*function[ \t]*\(\)/\1/l,varlambdas/
--regex-typescript=/^[ \t]*(export)?[ \t]*(public|private)[ \t]+(static)?[ \t]*([a-zA-Z0-9_]+)/\4/m,members/
--regex-typescript=/^[ \t]*(export)?[ \t]*interface[ \t]+([a-zA-Z0-9_]+)/\2/i,interfaces/
--regex-typescript=/^[ \t]*(export)?[ \t]*enum[ \t]+([a-zA-Z0-9_]+)/\2/e,enums/

For more vim integration, you can give YATS a look

Paamayim Nekudota Operator in ES7

Source: ななろば華 - 雨上がりタペストリー

Recently Babel supports Function Bind Syntax in ES7. A.K.A Paamayim Nekudotayim Operator.(it should be Paamayim Nekudatayim, though)

It inherits the spirit of Golang’s method, Switf’s extension, Scala’s implicit class, Ruby’s instance_exec, Haskell’s typeclass. While ES6 normalizes, and thus constrains, inheritance in JavaScript, :: brings about ad-hoc virtual method to extends class’s behavior.

Thanks to JavaScript’s prototype based and dynamic typing nature, Paamayim Nekudata introduces least semantic complexity and grants best expressiveness. It is much more concise than method.call in previous JS or instance_exec in Ruby. Using double colon ::, other than dot . provides visual cue to the source and definition of virtual method, which is more clear and less confusing than Swift’s extension or Scala’s implicit class. Extension to native object is trivial if one uses this new syntax. We can easily write a underscore like itertool library and apply its API directly on native array. This cannot be done without hacking (or screwing up) Array.prototype in ES6-. Both proposal and implementation on Function Bind Syntax are easy and straightforward, again, thanks to JS’ nature.

However, Function Bind Syntax does not work well with type checking, for now. Current candidate proposals on ES type system does not cover this keyword in function body. TypeScript simply waives type checking or forbids referencing this in function body. Flow is the only type checker that open method which is aware of this context. However, the type checking on open method is implicit to code authors. One cannot explicitly annotate function’s this type and type checking on open method is a sole compiler’s matter.

Nontheless, it is great feature! I’m lovin it! Try it out!

Source: http://babeljs.io/blog/2015/05/14/function-bind/

Explaining Scala SAM type

source

For better syntax and user friendliness (and a lot more), Java 8 introduces SAM type, Single Abstract Method type, starting to embrace the functional programming world.

Previous to 1.8, Java already has somewhat a (bulky and leaky) type of closure: annonyous inner classes. For example, to start a working thread in Java usually requires following trivial but bloated statements, without a lexical this:

1
2
3
4
5
6
7
8
9
// from android developer guide
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap b = loadImageFromNetwork("http://www.example.org/image.gif");
mImageView.setImage(b);
}
}).start()
}

Two classes, one method. The introduction of SAM type greatly reduces the syntactical overhead of Java.

1
2
3
4
5
6

public void onClick(View v) {
new Thread(#{ ->
mImage.setImage(loadImageFromNetwork("/image.gif"));
}).start();
}

I’m not explaining Java8’s new features here, as a Scala user has already relished the conciseness and expressiveness of functional programming.

So, why would scala user cares about SAM type in Java? I would say that interoperation with Java and performance are the main concerns here.

Java8 introduces Function type, which is widely used in library like stream. Sadly, Function is not that of scala. Scala compiler just frowns at you using scala native function with Stream.

1
2
3
4
5
6
import java.util.Arrays
Arrays.asList(1,2,3).stream.map((i: Int) => i * 2)

// <console>: error: type mismatch;
// found : Int => Int
// required: java.util.function.Function[_ >: Int, _]

Side notes: because function parameter is in a contravariant position, Function[_ >: Int, _] has a lower bound Int rather than a upper bound.
That is, the function passed as argument must accept types that are super types of Int.

One can manually provide implicit conversion here to transform scala function types to java function types. However, implementing such implicit conversion is of no fun. The implementation is either not generic enough, or requires mechanical code duplication(another alternative is advanced macro generation). Compiler support is more ideal, not only because it generates more efficient byte code, but also because this precludes incompatibility across different implementations.

SAM type is enabled by -Xexperimental flag in scala 2.11.x flags. Specifically, in scala 2.11.5, SAM type is better supported.
SAM gets eta-expansion(one can use a method from another class as SAM), overloading(overloaded function/method can also accept functions as SAM) and existential type support in scala 2.11.5.

Basic usage os SAM is quite simple, if a trait/abstract class with exactly one abstract method, then a Function of the same parameter and return type of the abstract method can be converted into the trait/abstract class.

1
2
3
4
5
6
7
8
9
10
11
12
trait Flyable {
// exactly one abstracg method
def fly(miles: Int): Unit
// optional concrete object
val name = "Unidentified Flyable Object"
}

// to reference SAM type itself
// create a named self-referencing lambda expression
val ufo: Flyable = (m: Int) => println(s"${ufo.name} flies $m miles!")
ufo.fly(123)
// Unidentified Flyable Object flies 123 miles!

Easy Peasy. So for the stream example, if compiler has the -Xexperimental flag, scala will automatically change the function to java’s function, which grant scala user a seamless experience with the library.

Usually, you don’t need SAM in scala, as scala already has first class generic function type, eta-expansion and a lot more. SAM reduces the readability as implicit conversion does. One can always use type alias to give function a more understandable name, instead of using SAM. SAM type cannot be pattern matched, at least for now.

However, interoperating with Java requires SAM. And self-referencing SAM gives you additional flexibity in designing API. SAM also generates more efficient byte code since SAM has a native byte code counterpart. Using annonymous class for event handler or callback can be more pleasant in Scala just as in Java.

Anyway, adding a feature is easy, but adding a feature that couples with edge case is hard. Scala already has bunches of features(variance, higher kinded, type level, continuation), whether SAM will gain its popularity is still an open question.

Rant on TypeScript type guard

source: Ad: hisuitei

Recently TypeScript team has released TypeScript 1.4, adding a new feature called Union Type which is intended for better incorporation into native JavaScript.
Type guard, as a natural dyad of union type, also comes into TypeScript world. But sadly, Microsoft choose a bizzare way to introduce type guard as they said in the manual

TypeScript now understands these conditions and will change type inference accordingly when used in an if block.

It accepts and only accepts conditional statement like if (typeof x === 'string') as type guard.
TypeScript now creates new type like number | string meaning a type of either number or string.
Users can further refine the type by comparing the value typeof gives, like the example below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function createCustomer(name: { firstName: string; lastName: string } | string) {
if (typeof name === "string") {
// Because of the typeof check in the if, we know name has type string
return { fullName: name };
}
else {
// Since it's not a string, we know name has
// type { firstName: string; lastName: string }
return { fullName: name.firstName + " " + name.lastName };
}
}

// Both customers have type { fullName: string }
var customer = createCustomer("John Smith");
var customer2 = createCustomer({ firstName: "Samuel", lastName: "Jones" });

I would rather say this is a bad idea because:

  1. it intermixes type level constucts with value level constructs.
  2. for complex and flexible language like javascript, microsoft’s approach is unable to handle various expressions regarding types.

Value level contructs are expression or statements dealing with values, e.g. assignment, comparison. typeof and instanceof in JavaScript are value level constructs because they generate boolean value, and their values can be passed to other variable or compared with other variable. Value type constucts do imply types, say, creating a new object of specific type, but they do not explicitly manipulate the types of expressions. There is no type casting JavaScript can do. On the other hand, type level constructs deals with types, for example, type annotation and generics.

Doubling typeof as type guard blurs the demarcation between type level and value level, and naturally reduces program’s readability(somewhat subjective claim though). A variable can, without distinct syntax, change its type in a conditional block. if branching is ubiquitous typescript programs, from hello-world toys to cathedral-like projects. It’s quite hard to find the “type switch” for union type among other irrelevant ifs. Also, one has to pay attention to call correct method of a same variable in different branches. So TypeScript’s type guard introduces a new type scope different from both lexical scope and function scope. It also cripples the compiler because now compiler has to check whether the condition in a if parentheses is type guard.

What’s worse? Type guard is a value level constructs so it can interact with all other language constucts. But microsoft does not intend to support that. None of the following code compiles in TypeScript 1.4.1, but they ought to run correctly in plain javascript, if they can be compiled.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function testNot(x: string|number|Function) {
var isNonNum = typeof x !== 'number'
if (isNonNum) return x.length
}

function testReturn(x: string|number) {
if (typeof x === 'number') return;
return x.length
}

function testReturn(x: string|number) {
if (typeof x === 'number') throw new Error('error type')
return x.length
}

function testFor(xs: (string|number)[]) {
for(var i = 0, x = xs[i]; typeof x === 'string'; i++) {
console.log(x.length)
}
}

function testWhile(xs: [](string|number)) {
var i = 0;
while (typeof xs[i] === 'string') {
console.log(xs[i].length)
i++
}
}

function testFilter(xs: (string|number)[]) {
xs.filter((x) => typeof x === 'string').map((x) => x.length)
}

Indeed, TypeScript is not the first to mix type level and value level. Language constructs like Pattern Match also do that(and usually introduce bugs related to type inference, see scala bug track). But at least Pattern Match is a specialized syntax that does not interact much with other syntax. But Type guard is, well, too ubiquitous to be good.

大雅雅于俗

问君何能尔,心远地自偏。

我跟你讲,八神老师的LL本才是横跨氪金手游和同人薄本两界的旗舰之作。

不要看每本本子只有薄薄三十几页,但每一页都体现了老师对氪金手游业的大见识:一切氪金的本质,与“恶女榨金”无二。老师的本子虽薄,却为ACG产业,乃至现代文化消费形式,描绘了一张鸟瞰图。

如若看官仅仅以无鸟事为鸟找事的心态去看LL本, 看到的不过是人物单方面榨取主人公体液的画面。进入了贤者状态的上级读者,才能看到老师在本子中表达的良苦用心。八神老师的整个作品都是个隐喻,从注射器到温度计,无一不暗示了氪金手游的运营手段。它们都有一个简单明了的目的:尽一切奇技淫巧,榨出玩家钱包里最后一滴金。

本子中的主人公被描写为一个被动的体液机器,这和免费增值(Freemium)的商业模式中将消费者定位成消费机器的思路实际是异曲同工的。偶像不断用各色工具刺激玩家产生快感,玩家在这个过程中形成了氪金与成就的关联概念,在老师本子中,就是以受虐与快感关联的受虐情节所体现出来的。

运营在情节和宣传中构造出的“偶像”、“奋斗”等概念,实际上是对玩家消费欲望的一个“改装”(distortion),让消费欲能被玩家自身和玩家所在的社会环境所接受。在本子中刺激腺体的桥段,影射了游戏对玩家消费欲的刺激(生理层次上,对腹侧被盖区的刺激)。然而八神老师的文笔隽永之处就在于,他的笔触白虚伪的改装一一清除,入目三分地刻画了氪金手游的榨金本色。这一点在老师SC60的作品《 soldier money game》中展现无余。

称LL薄本为俗萌之物,恰恰是没有理解八神秋一老师的用心之处。视角从薄本本身放开,提升到一个“元薄本”(meta-usuihon)的高度,才能品读出LL本中的精妙之处。八神老师的作品看似大俗,但作品的旨味却是大雅。在大俗的故事中反思了现代人的消费行为,才是艺术家在当代社会中的应有作为。

作为人民艺术家,如果一味追求艺术形式上的“雅”,只会和观众拉开远非“一步之遥”的距离。所谓小雅雅于形,中雅雅于意,大雅雅于俗,八神老师的作品,不可不谓大俗大雅、雅俗共赏之作。

typelevel-html

Type level programming is a technique that exploits type system to represents information and logic, to the extent of language’s limit.

Since values are encoded by variable’s type, type level drives compiler to validate logic or even determine program’s output.
All validation and computation are conducted statically at compiling phase, so the greatest benefit of type-level programming is its safety and reliability.

As a rule of thumb, the more dynamic code is, the more flexible it can computes. Type level programming require all logic encoded into the source code. It is to hard to cram all logic into type system, as handling whimsical input from external source is either impossible or reduce source code to unwieldy state machine. So the niche of type level programming is usually encoding, pickling or parsing.

But there is field where code is statically written: GUI. HTML template is hard coded in source. Type level can be used as linting and validation in html edition, especially in authoring web components. A piece of HTML fragment can be encoded in ordinary object, with type denoting its structure. Once the structure of HTMl is fixed, the output of JavaScript and css can be determined as well.
This is more helpful when one wants to make component. A tab-container must have tab-pane as child, and a tab-pane must live within a tab-container. Current approach of constraining HTML structure is encoding requirements in JavaScript and checking it in runtime. For example, angular uses require: '^parentDirective' to express the constraints and enable directive communication. If the component is programmatically constructed, using type annotation is a natural way to express the constraints. (As in Angular 2.0, query<ChildDirective>). We can go further in a language with full-bloomed type system.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
trait Tag
class Concat[A <: Tag, B <: Tag](a: A, b: B) extends Tag
trait NestTag[A <: Tag] extends Tag {
type Child = A
}
trait Inline extends Tag
trait Block extends Tag
case class div[T <: Tag](t :T = null) extends NestTag[T] with Block
case class p[T <: Tag](t :T = null) extends NestTag[T] with Block
case class a[T <: Inline](t :T = null) extends NestTag[T] with Inline

implicit class PlusTag[A <: Tag](a: A) {
def +[B <: Tag](b: B) = new Concat(a, b)
}

class Contains[A <: Tag, C[_ <: Tag] <: NestTag[_], T[_ <: Tag] <: NestTag[_]]

case class jQ[A <: Tag, C[_ <: Tag] <: NestTag[_]](c: C[A]) {
def has[T[_ <: Tag] <: NestTag[_]](implicit ev: Contains[A, C, T]) = true
}

implicit def htmlEq[A <: Tag, C[_ <: Tag] <: NestTag[_], T[_ <: Tag] <: NestTag[_]](implicit ev: C[A] =:= T[A]) =
new Contains[A, C, T]
implicit def recurEq[A <: Tag, B[_ <: Tag] <: NestTag[_], C[_ <: Tag] <: NestTag[_], T[_ <: Tag] <: NestTag[_]]
(implicit ev: Contains[A, B, T]) = new Contains[B[A], C, T]

val ele = div(
p(
a()
)
)
val r = jQ(ele).has[p]
println(r)

The code above is just a demo. All html elements has type that denotes its structure. And one can tell whether a tag is in a html elemnt by calling jQ(ele).has[Tag]. (Note: ele is value level variable and Tag is a type level constructor.) And inline element cannot contains block element, because inline element’s child must be a subtype of inline.

Programmatical markup has several benefits:

  1. no switching between script and template
  2. static type checking
  3. component dependency requirements
  4. component communication
  5. subtyping, inheritance… Classical OOP features
  6. relatively clean layout (though not as concise as Jade/Slim)

The biggest problem is, well, type level templates is strongly constrained by host language. Dynamic languages simply cannot have it. Users of classical static typed language without type inference cannot afford the verbosity of deeply nested type. And languages capable of type level have different approaches and implementation towards Type Level Programming.

After all, type level is too crazy…, at least for daily business logic.

dark
sans