<div dir="auto"><div>Saying "you don't need this if you follow my personal way of doing things" isn't helpful at all. Especially when these views are <i>controversial</i>. </div><div dir="auto"><div class="gmail_extra" dir="auto"><br><div class="gmail_quote">On 5 Nov 2017 4:27 pm, "kai zhu" <<a href="mailto:kaizhu256@gmail.com">kaizhu256@gmail.com</a>> wrote:<br type="attribution"><blockquote class="quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">the problem is that you chose to write the chess program in<br>
javascript, instead of say, python or c#.<br>
<br>
why did you choose javascript?  probably because you intend the chess<br>
program to be an online webapp.  mixins, like classes, are inferior to<br>
plain json-objects for webapps.  how do you intend to serialize the<br>
mixin board-state so you can sync it with a friend in an online match?<br>
 the i/o part of a webapp is typically as challenging as the<br>
business-logic of the game itself.<br>
<br>
it would be more efficient if you represented the board-state as a<br>
json-object, so it can be easily serailized and shared with other<br>
online players, and use static functions to manipulate the json-data.<br>
<br>
here's a functional web-demo of a simple connect4 game using only<br>
json-objects and static functions (in 400 lines of code).<br>
<br>
-kai<br>
<br>
<a href="https://github.com/kaizhu256/node-connect4" rel="noreferrer" target="_blank">https://github.com/kaizhu256/<wbr>node-connect4</a><br>
<br>
```js<br>
/*<br>
 * test.js<br>
 *<br>
 * this file contains the standalone connect-4 game<br>
 *<br>
 * setup instructions<br>
 * 1. save this file as test.js<br>
 * 2. install nodejs<br>
 * 3. run the shell command<br>
 *    $ PORT=8081 node test.js<br>
 * 4. open browser to url <a href="http://localhost:8081" rel="noreferrer" target="_blank">http://localhost:8081</a><br>
 * 5. play the connect4 game!<br>
 */<br>
<br>
<br>
<br>
/*jslint<br>
    bitwise: true,<br>
    browser: true,<br>
    maxerr: 8,<br>
    maxlen: 96,<br>
    node: true,<br>
    nomen: true,<br>
    regexp: true,<br>
    stupid: true<br>
*/<br>
(function () {<br>
    'use strict';<br>
    var local;<br>
<br>
<br>
<br>
    // run shared js-env code - pre-init<br>
    (function () {<br>
        // init local<br>
        local = {};<br>
        // init modeJs<br>
        local.modeJs = (function () {<br>
            try {<br>
                return typeof navigator.userAgent === 'string' &&<br>
                    typeof document.querySelector('body') === 'object' &&<br>
                    typeof XMLHttpRequest.prototype.open === 'function' &&<br>
                    'browser';<br>
            } catch (errorCaughtBrowser) {<br>
                return module.exports &&<br>
                    typeof process.versions.node === 'string' &&<br>
                    typeof require('http').createServer === 'function' &&<br>
                    'node';<br>
            }<br>
        }());<br>
        // init global<br>
        local.global = local.modeJs === 'browser'<br>
            ? window<br>
            : global;<br>
        local.nop = function () {<br>
        /*<br>
         * this function will do nothing<br>
         */<br>
            return;<br>
        };<br>
        // export local<br>
        local.global.local = local;<br>
    }());<br>
<br>
<br>
<br>
    // run shared js-env code - function<br>
    (function () {<br>
        local.gameStateCreate = function () {<br>
        /*<br>
         * this function will create a new game state<br>
         */<br>
            var state;<br>
            state = {};<br>
            state.board = [<br>
                // -> rows<br>
                [0, 0, 0, 0, 0, 0], // |<br>
                [0, 0, 0, 0, 0, 0], // v<br>
                [0, 0, 0, 0, 0, 0], //<br>
                [0, 0, 0, 0, 0, 0], // c<br>
                [0, 0, 0, 0, 0, 0], // o<br>
                [0, 0, 0, 0, 0, 0], // l<br>
                [0, 0, 0, 0, 0, 0]  // s<br>
            ];<br>
            state.playerCurrent = 1;<br>
            state.streakToWin = 4;<br>
            return state;<br>
        };<br>
<br>
        local.playerMove = function (state, positionCol) {<br>
        /*<br>
         * this function will perform a move<br>
         * by dropping the state.playerCurrent's disc in the given positionCol,<br>
         * and then checks to see if it wins the game<br>
         */<br>
            var colList, ii, positionRow, streak;<br>
            if (state.ended) {<br>
                state.error = new Error('game ended');<br>
            }<br>
            if (state.error) {<br>
                // debug error<br>
                console.error(state.error.<wbr>stack);<br>
                return;<br>
            }<br>
            if (positionCol === 'random') {<br>
                while (true) {<br>
                    positionCol = Math.floor(Math.random() *<br>
state.board.length);<br>
                    colList = state.board[positionCol] || [];<br>
                    if (colList[colList.length - 1] === 0) {<br>
                        break;<br>
                    }<br>
                }<br>
            }<br>
            state.positionCol = positionCol;<br>
            colList = state.board[positionCol] || [];<br>
            // naive algorithm to deposit disc in the last unfilled<br>
positionRow in colList<br>
            for (ii = 0; ii < colList.length; ii += 1) {<br>
                if (colList[ii] === 0) {<br>
                    positionRow = ii;<br>
                    colList[positionRow] = state.playerCurrent;<br>
                    // debug board<br>
                    console.log(state.board.join('<wbr>\n'));<br>
                    break;<br>
                }<br>
            }<br>
            if (positionRow === undefined) {<br>
                state.error = new Error('invalid move');<br>
                // debug error<br>
                console.error(state.error.<wbr>stack);<br>
                return;<br>
            }<br>
            // naive algorithm to check for win condition in the column<br>
            // e.g.<br>
            // [<br>
            // -> rows<br>
            // [1, 1, 1, 1, 0, 0], // |<br>
            // [2, 2, 2, 0, 0, 0], // v<br>
            // [0, 0, 0, 0, 0, 0], //<br>
            // [0, 0, 0, 0, 0, 0], // c<br>
            // [0, 0, 0, 0, 0, 0], // o<br>
            // [0, 0, 0, 0, 0, 0], // l<br>
            // [0, 0, 0, 0, 0, 0]  // s<br>
            // ]<br>
            streak = 0;<br>
            // iterate through the column<br>
            for (ii = 0; ii < colList.length; ii += 1) {<br>
                if (colList[ii] === state.playerCurrent) {<br>
                    streak += 1;<br>
                    if (streak >= 4) {<br>
                        state.ended = state.playerCurrent;<br>
                        return;<br>
                    }<br>
                } else {<br>
                    streak = 0;<br>
                }<br>
            }<br>
            // naive algorithm to check for win condition in the row<br>
            // e.g.<br>
            // [<br>
            // -> rows<br>
            // [1, 2, 0, 0, 0, 0], // |<br>
            // [1, 2, 0, 0, 0, 0], // v<br>
            // [1, 2, 0, 0, 0, 0], //<br>
            // [1, 0, 0, 0, 0, 0], // c<br>
            // [0, 0, 0, 0, 0, 0], // o<br>
            // [0, 0, 0, 0, 0, 0], // l<br>
            // [0, 0, 0, 0, 0, 0]  // s<br>
            // ]<br>
            streak = 0;<br>
            // iterate through the row<br>
            for (ii = 0; ii < state.board.length; ii += 1) {<br>
                if (state.board[ii][positionRow] === state.playerCurrent) {<br>
                    streak += 1;<br>
                    if (streak >= 4) {<br>
                        state.ended = state.playerCurrent;<br>
                        return;<br>
                    }<br>
                } else {<br>
                    streak = 0;<br>
                }<br>
            }<br>
            // naive algorithm to check for win condition in the upward diagonal<br>
            // e.g.<br>
            // [<br>
            // -> rows<br>
            // [1, 2, 0, 0, 0, 0], // |<br>
            // [2, 1, 0, 0, 0, 0], // v<br>
            // [2, 1, 1, 0, 0, 0], //<br>
            // [2, 2, 1, 1, 0, 0], // c<br>
            // [0, 0, 0, 0, 0, 0], // o<br>
            // [0, 0, 0, 0, 0, 0], // l<br>
            // [0, 0, 0, 0, 0, 0]  // s<br>
            // ]<br>
            streak = 0;<br>
            // iterate through the row<br>
            for (ii = 0; ii < state.board.length; ii += 1) {<br>
                if (state.board[ii][positionRow + ii - positionCol] ===<br>
                        state.playerCurrent) {<br>
                    streak += 1;<br>
                    if (streak >= 4) {<br>
                        state.ended = state.playerCurrent;<br>
                        return;<br>
                    }<br>
                } else {<br>
                    streak = 0;<br>
                }<br>
            }<br>
            // naive algorithm to check for win condition in the<br>
downward diagonal<br>
            // e.g.<br>
            // [<br>
            // -> rows<br>
            // [2, 2, 1, 1, 0, 0], // |<br>
            // [2, 1, 1, 0, 0, 0], // v<br>
            // [2, 1, 0, 0, 0, 0], //<br>
            // [1, 2, 0, 0, 0, 0], // c<br>
            // [0, 0, 0, 0, 0, 0], // o<br>
            // [0, 0, 0, 0, 0, 0], // l<br>
            // [0, 0, 0, 0, 0, 0]  // s<br>
            // ]<br>
            streak = 0;<br>
            // iterate through the row<br>
            for (ii = 0; ii < state.board.length; ii += 1) {<br>
                if (state.board[ii][positionRow - ii + positionCol] ===<br>
                        state.playerCurrent) {<br>
                    streak += 1;<br>
                    if (streak >= 4) {<br>
                        state.ended = state.playerCurrent;<br>
                        return;<br>
                    }<br>
                } else {<br>
                    streak = 0;<br>
                }<br>
            }<br>
            // naive algorithm to check if game ends in a draw<br>
            if (state.board.every(function (colList) {<br>
                    return colList[colList.length - 1] !== 0;<br>
                })) {<br>
                state.ended = 0;<br>
                return;<br>
            }<br>
            // switch player for next move<br>
            state.playerCurrent = state.playerCurrent === 1<br>
                ? 2<br>
                : 1;<br>
        };<br>
    }());<br>
    switch (local.modeJs) {<br>
<br>
<br>
<br>
    // run browser js-env code - post-init<br>
    case 'browser':<br>
        local.domGameBoard = document.querySelector('#<wbr>gameBoard1');<br>
        local.gameDraw = function (state) {<br>
        /*<br>
         * this function will draw the current state of the game<br>
         */<br>
            var board, tmp;<br>
            tmp = '';<br>
            // game ended with a draw<br>
            if (state.ended === 0) {<br>
                tmp += 'game is a draw!';<br>
                tmp += '<div class="playerDisc"></div>';<br>
            } else {<br>
                // game ended with a win<br>
                if (state.ended) {<br>
                    tmp += 'player ' + state.playerCurrent + ' has won!';<br>
                // game is ongoing<br>
                } else {<br>
                    tmp += 'player ' + state.playerCurrent + '\'s turn';<br>
                    if (state.error && state.error.message === 'invalid move') {<br>
                        tmp += ' <span style="color: #f00;">(invalid<br>
move, retry!)</span>';<br>
                    }<br>
                }<br>
                tmp += '<div class="playerDisc playerDisc' +<br>
state.playerCurrent + '"></div>';<br>
            }<br>
            document.querySelector('#<wbr>gameStatus1').innerHTML = tmp;<br>
            // remove error<br>
            state.error = null;<br>
            // transpose board<br>
            board = state.board[0].map(function (_, ii) {<br>
                // jslint-hack<br>
                local.nop(_);<br>
                return state.board.map(function (colList) {<br>
                    return colList[ii];<br>
                });<br>
            }).reverse();<br>
            board = '<table>\n' +<br>
                '<thead>' + board[0].map(function (_, ii) {<br>
                    // jslint-hack<br>
                    local.nop(_);<br>
                    return '<th><button data-position-col="' + ii +<br>
'">&#x25BC;</button></th>';<br>
                }).join('') + '</thead>\n' +<br>
                '<tbody>' + board.map(function (rowList) {<br>
                    return '<tr>' + rowList.map(function (playerDisc) {<br>
                        return '<td><div class="playerDisc playerDisc' +<br>
                            playerDisc + '"></div></td>';<br>
                    }).join('') + '</tr>';<br>
                }).join('\n') + '</tbody></table>';<br>
            local.domGameBoard.innerHTML = board;<br>
        };<br>
        local.testRun = function (event) {<br>
            switch (event && <a href="http://event.currentTarget.id" rel="noreferrer" target="_blank">event.currentTarget.id</a>) {<br>
            case 'gameBoard1':<br>
                // perform player move<br>
                if (event.target.dataset.<wbr>positionCol) {<br>
                    local.playerMove(local.<wbr>gameState,<br>
Number(event.target.dataset.<wbr>positionCol));<br>
                    local.gameDraw(local.<wbr>gameState);<br>
                }<br>
                break;<br>
            // reset game<br>
            case 'resetButton1':<br>
                local.gameState = local.gameStateCreate();<br>
                local.gameDraw(local.<wbr>gameState);<br>
                break;<br>
            }<br>
        };<br>
        // init event-handling<br>
        ['click'].forEach(function (event) {<br>
            Array.prototype.slice.call(<br>
                document.querySelectorAll('.<wbr>on' + event)<br>
            ).forEach(function (element) {<br>
                element.addEventListener(<wbr>event, local.testRun);<br>
            });<br>
        });<br>
        // reset game<br>
        document.querySelector('#<wbr>resetButton1').click();<br>
        break;<br>
<br>
<br>
<br>
    // run node js-env code - post-init<br>
    case 'node':<br>
        // require modules<br>
        local.http = require('http');<br>
        local.fs = require('fs');<br>
        try {<br>
            local.utility2 = require('utility2');<br>
        } catch (ignore) {<br>
        }<br>
        // save assets-script<br>
        local.assetsScript = local.fs.readFileSync(__<wbr>filename, 'utf8');<br>
        // init server<br>
        local.server = local.http.createServer(<wbr>function (request, response) {<br>
            // debug<br>
            console.log('handling request ' + request.url);<br>
            // serve assets-script<br>
            if (request.url.lastIndexOf('<wbr>test.js') >= 0) {<br>
                response.end(local.<wbr>assetsScript);<br>
                return;<br>
            }<br>
            // serve main-page<br>
            /* jslint-ignore-begin */<br>
            response.end('\<br>
<html lang="en">\n\<br>
<head>\n\<br>
<meta charset="UTF-8">\n\<br>
<title>connect4</title>\n\<br>
<style>\n\<br>
#gameBoard1 thead button:hover {\n\<br>
    cursor: pointer;\n\<br>
}\n\<br>
#gameBoard1 thead {\n\<br>
    margin-bottom: 10px;\n\<br>
}\n\<br>
#gameBoard1 table {\n\<br>
    background-color: #77f;\n\<br>
}\n\<br>
.playerDisc {\n\<br>
    background-color: #fff;\n\<br>
    border: 1px solid black;\n\<br>
    border-radius: 20px;\n\<br>
    height: 20px;\n\<br>
    margin: 5px;\n\<br>
    width: 20px;\n\<br>
}\n\<br>
.playerDisc1 {\n\<br>
    background-color: #ff0;\n\<br>
}\n\<br>
.playerDisc2 {\n\<br>
    background-color: #f00;\n\<br>
}\n\<br>
</style>\n\<br>
</head>\n\<br>
<body>\n\<br>
<h1><a href="<a href="https://github.com/kaizhu256/node-connect4" rel="noreferrer" target="_blank">https://github.com/<wbr>kaizhu256/node-connect4</a>"><wbr>connect-4<br>
game</a></h1>\n\<br>
<h4><a download href="test.js">download standalone app</a></h4>\n\<br>
<button class="onclick" id="resetButton1">reset game</button><br>\n\<br>
<br>\n\<br>
<h2 id="gameStatus1"></h2>\n\<br>
<div id="gameContainer1">\n\<br>
    <div class="onclick" id="gameBoard1"></div>\n\<br>
</div>\n\<br>
<script src="test.js"></script>\n\<br>
</body>\n\<br>
            ');<br>
            /* jslint-ignore-end */<br>
        });<br>
        local.server.on('error', function (error) {<br>
            if (error.code === 'EADDRINUSE' && !local.EADDRINUSE) {<br>
                local.EADDRINUSE = error;<br>
                local.PORT = Number(local.PORT) + 1;<br>
                local.server.listen(local.<wbr>PORT, function () {<br>
                    console.log('server listening on port ' + local.PORT);<br>
                });<br>
                return;<br>
            }<br>
            throw error;<br>
        });<br>
        local.PORT = process.env.PORT || 8081;<br>
        local.server.listen(local.<wbr>PORT, function () {<br>
            console.log('server listening on port ' + local.PORT);<br>
        });<br>
        break;<br>
    }<br>
<br>
<br>
<br>
    // run shared js-env code - post-init<br>
    (function () {<br>
        return;<br>
    }());<br>
}());<br>
```<br>
<div class="elided-text"><br>
<br>
On 11/5/17, Raul-Sebastian Mihăilă <<a href="mailto:raul.mihaila@gmail.com">raul.mihaila@gmail.com</a>> wrote:<br>
> Also, in the same context, for different mixin associated objects there<br>
> will be different mix objects:<br>
><br>
> ```js<br>
> function F() {<br>
>   const obj = {};<br>
>   const obj2 = {};<br>
><br>
>   mixin obj, mixin1;<br>
>   mixin obj2, mixin2;<br>
> }<br>
><br>
> function mixin1() {<br>
>   return (obj, mix) => {};<br>
> }<br>
><br>
> function mixin2() {<br>
>   return (obj, mix) => {};<br>
> }<br>
> ```<br>
><br>
> The mix argument that the mixin function created by mixin2 receives will be<br>
> different from the one received by the mixin function created by mixin1<br>
> because obj1 !== obj2.<br>
><br>
</div><br>______________________________<wbr>_________________<br>
es-discuss mailing list<br>
<a href="mailto:es-discuss@mozilla.org">es-discuss@mozilla.org</a><br>
<a href="https://mail.mozilla.org/listinfo/es-discuss" rel="noreferrer" target="_blank">https://mail.mozilla.org/<wbr>listinfo/es-discuss</a><br>
<br></blockquote></div><br></div></div></div>