CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
+
references +
immutable objectsheap
)CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
A.__proto__ = B
links A
object to B
, if a field f
is not available in A
, then it is looked up in B
(which works recursively until finding undefined).
a = {"x": 10, "y": 20}b = {"x": 30, "z": 90, "__proto__": a}b {x: 30, z: 90, *y: 20}
If we call a function A
with new
, then A
is called as the constructor of a new object.
function C(x, y) { this.x = x; this.y = y }c = new C(10, 20)c {x: 10, y: 20}
If A
is a function, then A.prototype
becomes the __proto__
of every object created using A
with new
.
C.prototype = {"foo": true, "bar": 100}d = new C(10, 20)d {x: 10, y: 20, *foo: true, *bar: 100}
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
hw8-util.rkt
)CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
function Shape(x, y) { this.x = x; this.y = y;}let p = new Shape(10, 20);Shape.prototype.translate = function(x, y) { this.x = this.x + x; this.y = this.y + y; };p.translate(1,2);return p;
(let Shape (function (x y) (begin (set! this.x x) (set! this.y y))) (let p (new Shape 10 20) (let Shape-proto Shape.prototype (begin (set! Shape-proto.translate (function (x y) (begin (set! this.x (! + this.x x)) (set! this.y (! + this.y y))))) (p.translate 1 2) p))))
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
function Rectangle(width, height) { this.x = 0; this.y = 0; this.width = width; this.height = height;}Rectangle.prototype = Shape.prototype;let r1 = new Rectangle(10, 20);return r1;
(let Rectangle (function (width height) (begin (set! this.x 0) (set! this.y 0) (set! this.width width) (set! this.height height))) (set! Rectangle.prototype Shape.prototype) (let r1 (new Rectangle 10 20) r1))
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
function Rectangle(width, height) { this.x = 0; this.y = 0; this.width = width; this.height = height;}Rectangle.prototype = Shape.prototype;let r1 = new Rectangle(10, 20);return r1;
(let Rectangle (function (width height) (begin (set! this.x 0) (set! this.y 0) (set! this.width width) (set! this.height height))) (set! Rectangle.prototype Shape.prototype) (let r1 (new Rectangle 10 20) r1))
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
function Rectangle(width, height) { this.x = 0; this.y = 0; this.width = width; this.height = height;}Rectangle.prototype = Shape.prototype;let r1 = new Rectangle(10, 20);return r1;
(let Rectangle (function (width height) (begin (set! this.x 0) (set! this.y 0) (set! this.width width) (set! this.height height))) (set! Rectangle.prototype Shape.prototype) (let r1 (new Rectangle 10 20) r1))
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
With the highlighted pattern we can safely mutate
Rectangle.prototype
. This is the same asRectangle.prototype = {'__proto__': Shape.prototype }
, but we have no syntax for such a pattern in SimpleJS.
function Rectangle(width, height) { this.x = 0; this.y = 0; this.width = width; this.height = height;}let p = function () {}p.prototype = Shape.prototype;Rectangle.prototype = new p();let r1 = new Rectangle(10, 20);return r1;
(let Rectangle (function (width height) (begin (set! this.x 0) (set! this.y 0) (set! this.width width) (set! this.height height))) (let p (function () 0) (begin (set! p.prototype = Shape.prototype) (set! Rectangle.prototype (new p)) (let r1 (new Rectangle 10 20) r1))))
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
Think Racket without define
, without macros, with objects, and heap operations.
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
Formal syntax | S-expression |
---|---|
λx.e | (lambda (x) e) |
e1(e2) | (e1 e2) |
{"foo":1+2,"bar":x} | (object ["foo" (+ 1 2)] ["bar" x]) |
o["foo"] | (get-field o "foo") |
alloc {} | (alloc (object)) |
x:={} | (set! x (object)) |
x:=1;x | (begin (set! x 1) x) |
let x = 10 in x+4 | (let ([x 10]) (+ x 4)) |
In Racket you can actually allocate a reference with
(box e)
, which is equivalent to LambdaJS(alloc e)
, and update the contents of that reference with(set-box! b e)
, which is equivalent to LambdaJS(set! e)
.
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
prototype
field which points to an empty SimpleJS objectnew
expects a SimpleJS function as argument and must create a new object, initialize its prototype, and call the constructor function (see point 2)this
object to it (see 2)this
function
into an object+
lambdaCS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
function Shape(x, y) { this.x = x; this.y = y;};
Shape = { '$code': (obj, x, y) => { obj.x = x; obj.y = y; }, 'prototype' = {}};
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
function Shape(x, y) { this.x = x; this.y = y;};
Shape = { '$code': (obj, x, y) => { obj.x = x; obj.y = y; }, 'prototype' = {}};
Shape = alloc {'$code': (this, x, y) => { this = (deref this)["x"] <- x; // In LambdaJS we have to replace the whole object this = (deref this)["y"] <- y;}, 'prototype': alloc {}};
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
p1 = new Shape(0, 1);
p1 = {"__proto__": Shape.prototype};Shape["$code"](file:///home/tiago/Work/cs450-slides/p1, 0, 1);
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
p1 = new Shape(0, 1);
p1 = {"__proto__": Shape.prototype};Shape["$code"](file:///home/tiago/Work/cs450-slides/p1, 0, 1);
p1 = alloc {"__proto__": (deref Shape)["prototype"]}};(deref Shape)["$code"](file:///home/tiago/Work/cs450-slides/p1, 0, 1);
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
p1.translate(10, 20);
m = p1["translate"]; // get object methodm["$code"](file:///home/tiago/Work/cs450-slides/p1, 10, 20); // get code for method
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
p1.translate(10, 20);
m = p1["translate"]; // get object methodm["$code"](file:///home/tiago/Work/cs450-slides/p1, 10, 20); // get code for method
m = (deref p1)["translate"];(deref m)["$code"](file:///home/tiago/Work/cs450-slides/p1, 10, 20);
(let ([m (get-field (deref p1) "translate")]) ((get-field (deref m) "$code") p1 10 20))
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
Shape.prototype.translate = function(x, y) { this.x += x; this.y += y;};p1 = new Shape(0, 1);p1.translate(10, 20);
// 1. Function declarationShape = alloc { "$code": (this, x, y) => { ... }, "prototype" = alloc {}};p = (deref Shape)["prototype"];(deref p)["translate"] = alloc { "$code": (this, x, y) => { ... } "prototype": alloc {}};// 2. newp1 = alloc {"__proto__": (deref Shape)["prototype"]};(deref Shape)["$code"](file:///home/tiago/Work/cs450-slides/p1, 0, 1);// 3. method callf = (deref p1)["translate"];(deref f)["$code"](file:///home/tiago/Work/cs450-slides/p1, 10, 20);
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
this.x
(get-field (deref this) "x")
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
J[[x.y:=e]]= let data=J[[e]] inx:=(deref obj)["y"]←data;dataIn JavaScript, assigning an expression e into a field, returns the evaluation of e. However, in LambdaJS assignment returns the reference being mutated.
(set! this.x x)
(let [(data x)] (begin (set! this (update-field (deref this) "x" data)) data)))
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
(set! data.x 10)
(let [(data 10)] (begin (set! data (update-field (deref data) "x" data)) data)))
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
(set! data.x 10)
(let [(data 10)] (begin (set! data (update-field (deref data) "x" data)) data)))
data
is used in the generated codedata
is not captured (free) in the generated code!CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
J[[function(x⋯) {e}]]=xalloc {"$code":λ(this,x⋯).J[[e]],"prototype":alloc {}}Field
prototype
can be accessed by the user, so we declare it as a reference. Field$code
does not actually exist in JavaScript, so we prefix it with a dollar sign ($
) to visually distinguish artifacts of the translation.
(function (x y) (begin (set! this.x x) (set! this.y y)))
(let ([js-set! (lambda (o f d) (begin (set! o (update-field (deref o) f d)) d))]) (alloc (object ["$code" (lambda (this x y) (begin (js-set! this "x" x) (js-set! this "y" y)))] ["prototype" (alloc (object))])))
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
new
keywordCS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
new
keyword(new Shape 0 1)
(let [(ctor (deref Shape)) (o (alloc (object "$proto" (get-field ctor "prototype"))))] (begin ((get-field ctor "$code") o 0 1) o))
new
keyword (still incorrect)(new Shape 0 1)
(let [(ctor (deref Proto)) (o (alloc (object "$proto" (get-field ctor "prototype")))) (y1 0) (y2 1)] (begin ((get-field ctor "$code") o y1 y2) o))
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
(p1.translate 10 20)
((get-field (deref (get-field (deref p1) "translate")) "$code") p1 10 20);; In Racket pseudo code(define p1:obj (deref p1)) ; 1. get obj from ref(define translate:m (get-field p1-obj "translate")) ; 2. get field(define translate:o (deref translate-m)) ; 3. get object from ref(define translate:f (get-field translate-obj "$code") ; 4. get fun(translate-code p1 10 20) ; 5. call fun pass this (p1)
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
J[[ef(e⋯)]]=xlet obj=J[[eo]] in(deref obj)["$code"](file:///home/tiago/Work/cs450−slides/window,J[[e⋯]])We will not be implementing function calls in Homework Assignment 8.
class Foo { constructor() { this.x = 0; } bar() { this.x++; }}var foo = new Foo();foo["bar"](file:///home/tiago/Work/cs450-slides/); // foo.bar();// Caveat: foo.bar() != (foo.bar)()
class Foo { constructor() { this.x = 0; } bar() { this.x++; }}var foo = new Foo();var bar = foo["bar"];bar(); // TypeError: this is undefined
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
To allow dynamically dispatching to X's methods, the first four lines instantiate X without calling its constructor. This way, we can safely mutate the cls's prototype without affecting X and any changes to X are visible to cls via lookup.
CS450 ☽ SimpleJS; translating LambdaJS to SimpleJS ☽ Lecture 38 ☽ Tiago Cogumbreiro
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
Number + Return | Go to specific slide |
b / m / f | Toggle blackout / mirrored / fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
t | Restart the presentation timer |
?, h | Toggle this help |
Esc | Back to slideshow |