├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── callback-hell.jpg ├── clojure_code_survival.jpeg ├── doc └── intro.md ├── hickey_meme.jpg ├── presentation.html ├── presentation.org ├── project.clj ├── quick_demo.gif ├── resources └── public │ └── index.html ├── src ├── clj │ └── chat42 │ │ └── core.clj └── cljs │ └── chat42 │ └── core.cljs └── test └── chat42 └── core_test.clj /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | /resources/public/js 13 | /resources/public/css 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). 3 | 4 | ## [Unreleased] 5 | ### Changed 6 | - Add a new arity to `make-widget-async` to provide a different widget shape. 7 | 8 | ## [0.1.1] - 2016-12-09 9 | ### Changed 10 | - Documentation on how to make the widgets. 11 | 12 | ### Removed 13 | - `make-widget-sync` - we're all async, all the time. 14 | 15 | ### Fixed 16 | - Fixed widget maker to keep working when daylight savings switches over. 17 | 18 | ## 0.1.0 - 2016-12-09 19 | ### Added 20 | - Files from the new template. 21 | - Widget maker public API - `make-widget-sync`. 22 | 23 | [Unreleased]: https://github.com/your-name/chat42/compare/0.1.1...HEAD 24 | [0.1.1]: https://github.com/your-name/chat42/compare/0.1.0...0.1.1 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor to control, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chat42 Gitter 2 | 3 | We have 4 | a 5 | [demo deployed on IPFS](https://ipfs.io/ipfs/Qmc2fKMZf6o3N7bafPKMkXvhcfBaoVS5uTRXTBUGpeVzFr/). 6 | It uses a websocket connection to our test server on topiq.es. This is a simple 7 | web-chat application which leverages [replikativ](http://replikativ.io) for its 8 | state management. 9 | 10 | 11 | quick demo 12 | 13 | 14 | chat42 consists of two parts, a client written 15 | with [ClojureScript](https://clojurescript.org/) 16 | and [om-next](https://github.com/omcljs/om/wiki/Quick-Start-(om.next)) (react) 17 | that compiles into efficient Javascript, and a server written in Clojure that 18 | brokers communication between peers over a websocket. The server will be 19 | available for node.js soon and is only necessary to ensure a communication 20 | channel. 21 | 22 | There is also a [react native client](https://github.com/replikativ/chat42app). 23 | 24 | It was initially created as 25 | a 26 | [presentation for ClojureScript](https://github.com/replikativ/chat42/blob/master/presentation.org) in 27 | our local JavaScript meetup. 28 | 29 | 30 | ## Usage 31 | 32 | You need to have [Leiningen](https://leiningen.org/) installed. 33 | 34 | 35 | ### Client development 36 | 37 | Just run figwheel and edit `core.cljs` as needed. If the replikativ parts are un clear, also have a look at the [API walkthrough](http://replikativ.io/tut/get-started.html). 38 | 39 | ~~~clojure 40 | lein figwheel 41 | ~~~ 42 | 43 | This allows you to develop the client against our test server. 44 | 45 | ### Server peer 46 | 47 | If you want to persist and distribute your own state, run the server with: 48 | 49 | ~~~clojure 50 | lein run 51 | ~~~ 52 | 53 | The server will automatically connect to our new test net and dump potentially a 54 | few gigabytes to your disk. If you don't want this, comment out: 55 | 56 | ~~~clojure 57 | (connect! stage "ws://replikativ.io") 58 | ~~~ 59 | 60 | to 61 | 62 | ~~~clojure 63 | #_(connect! stage "ws://replikativ.io") 64 | ~~~ 65 | 66 | in [core.clj](https://github.com/replikativ/chat42/blob/master/src/clj/chat42/core.clj#L14) 67 | 68 | You also have to change the uri in `core.cljs` to make the client connect to 69 | your server and not the test server. 70 | 71 | If you have any problems, questions or suggestions, please 72 | join our gitter chat. 73 | 74 | ## License 75 | 76 | Copyright © 2016-2017 Konrad Kühne, Christian Weilbach 77 | 78 | Distributed under the Eclipse Public License either version 1.0 or (at 79 | your option) any later version. 80 | -------------------------------------------------------------------------------- /callback-hell.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/replikativ/chat42/b626e76e3e87ed0ed98d3747e6c16758c10596bf/callback-hell.jpg -------------------------------------------------------------------------------- /clojure_code_survival.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/replikativ/chat42/b626e76e3e87ed0ed98d3747e6c16758c10596bf/clojure_code_survival.jpeg -------------------------------------------------------------------------------- /doc/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to chat42 2 | 3 | TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) 4 | -------------------------------------------------------------------------------- /hickey_meme.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/replikativ/chat42/b626e76e3e87ed0ed98d3747e6c16758c10596bf/hickey_meme.jpg -------------------------------------------------------------------------------- /presentation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Back to the future: Cljs 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 25 | 26 | 27 | 28 |
29 |
30 |

Back to the future: Cljs

Konrad Kühne & Christian Weilbach

Created: 2016-12-14 Wed 18:01

31 |
32 | 33 | 34 |
35 |
36 |

About us

37 |
    38 |
  • professional frontend (app and web) and backend (JVM) developers with 39 | LivelyCode
  • 40 |
  • core devs of isomorphic http://replikativ.io/
  • 41 |
  • regular experience with JavaScript
  • 42 |
  • introduction to FP with underscore.js and JSON data flow from web services
  • 43 |
  • functional programming zealots
  • 44 |
  • pragmatic: Making more money with less work now.
  • 45 | 46 |
47 | 48 | 49 | 50 |
51 |
52 |
53 |
54 |

Why?

55 | 56 |
57 |

hickey_meme.jpg 58 |

59 |
60 | 61 |
62 |
63 |
64 |
65 |

Language design

66 |
    67 |
  • LISP was invented/discovered in 1958
  • 68 |
  • Brandon Eich's design objective: Java-like script language
  • 69 |
  • Time to design: 2 weeks !!!!
  • 70 |
  • \(\Rightarrow\) Some JavaScript core language problems: http://destroyallsoftware.com/talks/wat
  • 71 |
  • comparison design effort JavaScript vs. Clojure:
    72 | 2 weeks vs. 2 years
  • 73 |
  • not to speak of all the history in Lisp language design which has since been 74 | ported to Clojure (for example MetaObject protocol as the "best" OO 75 | approach)
  • 76 | 77 |
78 | 79 | 80 | 81 |
82 |
83 |
84 |
85 |

The original JavaScript

86 | 93 |
    94 |
  • Lisp (Scheme dialect) was intended as the original JavaScript, before Java 95 | became so popular
  • 96 |
  • JS similar to imperative Lisps like Emacs-Lisp
  • 97 |
  • composition: dynamic extension of small core language, like Scheme
  • 98 |
  • Dynamic languages (e.g. Python, Ruby, JavaScript) subset of features of 99 | Lisp: The hundred year language. Paul Graham.
  • 100 | 101 |
102 | 103 | 104 |
105 |
106 |
107 |
108 |

Language limitations

109 | 110 |
111 |

callback-hell.jpg 112 |

113 |
114 | 115 | 116 |
117 |
118 |
119 |
120 |

List Processing

121 |
    122 |
  • "Most important idea in Computer Science." Alan Kay
  • 123 |
  • Remove as much syntax as possible
  • 124 |
  • interpreter of itself can be expressed on half a page, (chapter 4 of SICP)
  • 125 |
  • All code is simplest data structure: List (homoiconic)
  • 126 |
  • adapt language to problem
    127 | \(\Rightarrow\) Lisp Macros: Languages as libraries 128 |
      129 |
    • go-lang as core.async: no callback hell
    • 130 |
    • prolog as core.logic: relational programming
    • 131 |
    • statistics as anglican: probabilistic programming
    • 132 |
    • TypeScript as with core.typed: gradual typing
    • 133 |
    • OCaml style pattern matching as core.match: terse control flow 134 | …
    • 135 | 136 |
  • 137 | 138 |
139 | 140 | 141 |
142 |
143 |
144 |
145 |

Functional programming

146 |
    147 |
  • not just first class functions (closures)
  • 148 |
  • but pure functions: functions that do not mutate their parameters or the 149 | environment, but just return a value
  • 150 |
  • value semantics: true equality
  • 151 |
  • Bret Victor about Haskell: "Language for 21st century."
  • 152 | 153 |
154 | 155 |
156 |
157 |
158 |
159 |

Functional programming in JS

160 |
    161 |
  • JavaScript core datastructures (JSON) are mutable
    162 | \(\Rightarrow\) no real equality, parameters mutated by functions
  • 163 |
  • FP theoretically possible, but practically impossible on top of imperative 164 | programming
  • 165 |
  • JS libraries do not support FP in general
  • 166 |
  • current trend with TypeScript / EcmaScript class syntax rather in imperative 167 | object-oriented direction like Java
  • 168 | 169 |
170 | 171 | 172 |
173 |
174 |
175 |
176 |

ClojureScript and Clojure

177 |
    178 |
  • Clojure is a Lisp dialect for the JVM
  • 179 |
  • persistent datastructures for FP
  • 180 |
  • ClojureScript is a port of Clojure to JavaScript
  • 181 |
  • both are hosted languages, exposing host primitives and abstractions instead 182 | of introducing their own: ClojureScript \(\neq\) Clojure
  • 183 |
  • Clojure brings live coding and strong concurrent programming to the JVM and 184 | CLR
  • 185 |
  • Clojure and ClojureScript can be very nicely integrated, e.g. replikativ
  • 186 | 187 |
188 | 189 | 190 | 191 |
192 |
193 |
194 |
195 |

Cljs 💘 JS

196 |
    197 |
  • First class interop: 198 |
      199 |
    • All primitives are JavaScript primitives
    • 200 |
    • all ClojureScript functions are normal JavaScript functions
    • 201 |
    • data structures can be easily converted from and to JSON
    • 202 |
    • No overhead for large standard library or your code thanks to heavily optimizing 203 | Google Closure compiler (used for GMail, …)
    • 204 | 205 |
  • 206 |
  • ClojureScript with functional programming strengthens the core value of 207 | JavaScript: Interactivity and Live Coding
  • 208 | 209 |
210 | 211 | 212 |
213 |
214 |
215 |
216 |

Relax

217 | 218 |
219 |

clojure_code_survival.jpeg 220 |

221 |
222 | 223 | 224 |
225 |
226 |
227 |
228 |

Live Coding

229 |
    230 |
  • redux, immutable: react state management inspired by Om
  • 231 |
  • React through material-ui
  • 232 | 233 |
234 | 235 |
236 |
237 |
238 |
239 |

References

240 | 252 |
253 |
254 |
255 |
256 | 257 | 258 | 259 | 294 | 295 | 296 | -------------------------------------------------------------------------------- /presentation.org: -------------------------------------------------------------------------------- 1 | #+Title: Back to the future: Cljs 2 | #+Author: Konrad Kühne & Christian Weilbach 3 | #+Email: ch_weil@topiq.es 4 | 5 | #+REVEAL_ROOT: http://cdn.jsdelivr.net/reveal.js/3.0.0/ 6 | #+OPTIONS: reveal_center:t reveal_progress:t reveal_history:t reveal_control:t 7 | #+OPTIONS: reveal_mathjax:t reveal_rolling_Links:t reveal_keyboard:t reveal_overview:t num:nil 8 | #+OPTIONS: reveal_slide_number:t 9 | # +OPTIONS: reveal_width:1420 reveal_height:1080 10 | #+OPTIONS: toc:nil 11 | #+REVEAL_MARGIN: 0.1 12 | #+REVEAL_MIN_SCALE: 0.6 13 | #+REVEAL_MAX_SCALE: 1.2 14 | #+REVEAL_TRANS: linear 15 | #+REVEAL_THEME: sky 16 | #+REVEAL_HLEVEL: 1 17 | 18 | 19 | * About us 20 | - professional frontend (app and web) and backend (JVM) developers with 21 | LivelyCode 22 | - core devs of /isomorphic/ http://replikativ.io 23 | - regular experience with JavaScript 24 | - introduction to FP with underscore.js and JSON data flow from web services 25 | - functional programming zealots 26 | - pragmatic: Making /more/ money with /less/ work now. 27 | 28 | 29 | 30 | * Why? 31 | [[./hickey_meme.jpg]] 32 | 33 | * Language design 34 | - LISP was invented/discovered in *1958* 35 | - Brandon Eich's design objective: Java-like script language 36 | - Time to design: *2 weeks !!!!* 37 | - $\Rightarrow$ Some JavaScript core language problems: http://destroyallsoftware.com/talks/wat 38 | - comparison design effort JavaScript vs. Clojure: \\ 39 | *2 weeks* vs. *2 years* 40 | - not to speak of all the history in Lisp language design which has since been 41 | ported to Clojure (for example MetaObject protocol as the "best" OO 42 | approach) 43 | 44 | 45 | 46 | * The original JavaScript 47 | #+BEGIN_NOTES 48 | - JavaScript can be a *nice* language ("JavaScript the Good Parts") 49 | #+END_NOTES 50 | - Lisp (Scheme dialect) was intended as the /original/ JavaScript, before Java 51 | became so popular 52 | - JS similar to imperative Lisps like Emacs-Lisp 53 | - *composition*: dynamic extension of small core language, like Scheme 54 | - Dynamic languages (e.g. Python, Ruby, JavaScript) subset of features of 55 | Lisp: [[http://paulgraham.com/hundred.html][The hundred year language]]. Paul Graham. 56 | 57 | 58 | * Language limitations 59 | [[./callback-hell.jpg]] 60 | 61 | 62 | * List Processing 63 | - "Most important idea in Computer Science." Alan Kay 64 | - *Remove as much syntax as possible* 65 | - *interpreter of itself* can be expressed on half a page, (chapter 4 of SICP) 66 | - All code is simplest data structure: List (homoiconic) 67 | - adapt language to problem \\ 68 | $\Rightarrow$ *Lisp Macros*: Languages as libraries 69 | * *go-lang* as core.async: *no callback hell* 70 | * *prolog* as core.logic: *relational programming* 71 | * *statistics* as anglican: *probabilistic programming* 72 | * *TypeScript* as with core.typed: *gradual typing* 73 | * *OCaml style pattern matching* as core.match: *terse control flow* 74 | ... 75 | 76 | 77 | * Functional programming 78 | - not just /first class/ functions (closures) 79 | - but *pure* functions: functions that do not mutate their parameters or the 80 | environment, but just return a value 81 | - *value semantics*: true equality 82 | - Bret Victor about Haskell: "Language for 21st century." 83 | 84 | * Functional programming in JS 85 | - JavaScript core datastructures (JSON) are mutable \\ 86 | $\Rightarrow$ no /real/ equality, parameters mutated by functions 87 | - FP theoretically possible, but practically impossible on top of imperative 88 | programming 89 | - JS libraries do not support FP in general 90 | - current trend with TypeScript / EcmaScript class syntax rather in /imperative 91 | object-oriented/ direction like Java 92 | 93 | 94 | * ClojureScript and Clojure 95 | - Clojure is a Lisp dialect for the JVM 96 | - *persistent datastructures* for FP 97 | - ClojureScript is a port of Clojure to JavaScript 98 | - both are /hosted languages/, exposing host primitives and abstractions instead 99 | of introducing their own: ClojureScript $\neq$ Clojure 100 | - Clojure brings live coding and strong concurrent programming to the JVM and 101 | CLR 102 | - Clojure and ClojureScript can be very nicely integrated, e.g. replikativ 103 | 104 | 105 | 106 | * Cljs 💘 JS 107 | - First class interop: 108 | * *All primitives* are JavaScript primitives 109 | * all ClojureScript functions are *normal JavaScript functions* 110 | * data structures can be easily converted from and to JSON 111 | * No overhead for large standard library or your code thanks to heavily optimizing 112 | *Google Closure compiler* (used for GMail, ...) 113 | - ClojureScript with functional programming strengthens the core value of 114 | JavaScript: *Interactivity* and *Live Coding* 115 | 116 | 117 | * Relax 118 | [[./clojure_code_survival.jpeg]] 119 | 120 | 121 | * Live Coding 122 | - redux, immutable: react state management /inspired by/ [[https://github.com/omcljs/om/][Om]] 123 | - React through [[http://www.material-ui.com/][material-ui]] 124 | 125 | * References 126 | - Source code and presentation: https://github.com/replikativ/chat42 127 | - [[https://github.com/boston-clojure/learning-clojure][Boston Clojure - learning resources]] 128 | - [[https://github.com/bhauman/lein-figwheel/wiki/Quick-Start][Figwheel Quick Start]] (look at the FlappyBird Demo ;) ) 129 | - [[https://www.railslove.com/stories/my-way-into-clojure-building-a-card-game-with-om-part-1][Background to Cljs webdev]] 130 | - [[https://github.com/clojure/clojurescript/wiki/Companies-Using-ClojureScript][Some company web sites using cljs]]: Capital One, CircleCI, Cisco, Rackspace, 131 | Thomson Reuters, ... 132 | - [[http://clojure.org/community/companies][Many more use Clojure now]]: Facebook, Deutsche Bank, Daily Mail, Heroku, 133 | Netflix, Oracle, Salesforce, SoundCloud, Walmart Labs, ... 134 | - [[http://cljsrn.org/][ClojureScript + React Native]] 135 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject chat42 "0.1.0-SNAPSHOT" 2 | 3 | :description "Web chat using replikativ." 4 | 5 | :url "http://github.com/replikativ/chat42" 6 | 7 | :main chat42.core 8 | 9 | :license {:name "Eclipse Public License" 10 | :url "http://www.eclipse.org/legal/epl-v10.html"} 11 | 12 | :dependencies [[org.clojure/clojure "1.9.0-alpha14"] 13 | [org.clojure/clojurescript "1.9.229"] 14 | 15 | [com.cognitect/transit-cljs "0.8.239" :scope "provided"] 16 | [io.replikativ/replikativ "0.2.4"] 17 | [sablono "0.8.0"] 18 | [com.fzakaria/slf4j-timbre "0.3.5"] 19 | [org.omcljs/om "1.0.0-alpha46" :exclusions [cljsjs/react 20 | cljsjs/react-dom]] 21 | [cljs-react-material-ui "0.2.44"]] 22 | 23 | :plugins [[lein-figwheel "0.5.8"] 24 | [lein-cljsbuild "1.1.4" :exclusions [[org.clojure/clojure]]]] 25 | 26 | :source-paths ["src/cljs" "src/clj"] 27 | 28 | :clean-targets ^{:protect false} ["resources/public/js/compiled" "target"] 29 | 30 | :cljsbuild {:builds 31 | [{:id "dev" 32 | :source-paths ["src/cljs"] 33 | 34 | ;; the presence of a :figwheel configuration here 35 | ;; will cause figwheel to inject the figwheel client 36 | ;; into your build 37 | :figwheel {:on-jsload "chat42.core/on-js-reload" 38 | ;; :open-urls will pop open your application 39 | ;; in the default browser once Figwheel has 40 | ;; started and complied your application. 41 | ;; Comment this out once it no longer serves you. 42 | :open-urls ["http://localhost:3449/index.html"]} 43 | 44 | :compiler {:main chat42.core 45 | :asset-path "js/compiled/out" 46 | :output-to "resources/public/js/compiled/chat42.js" 47 | :output-dir "resources/public/js/compiled/out" 48 | :source-map-timestamp true 49 | ;; To console.log CLJS data-structures make sure you enable devtools in Chrome 50 | ;; https://github.com/binaryage/cljs-devtools 51 | :preloads [devtools.preload]}} 52 | ;; This next build is an compressed minified build for 53 | ;; production. You can build this with: 54 | ;; lein cljsbuild once min 55 | {:id "min" 56 | :source-paths ["src/cljs"] 57 | :compiler {:output-to "resources/public/js/compiled/chat42.js" 58 | :main chat42.core 59 | :optimizations :advanced 60 | :pretty-print false}}]} 61 | 62 | :figwheel {;; :http-server-root "public" ;; default and assumes "resources" 63 | ;; :server-port 3449 ;; default 64 | ;; :server-ip "127.0.0.1" 65 | 66 | :css-dirs ["resources/public/css"] ;; watch and update CSS 67 | 68 | ;; Start an nREPL server into the running figwheel process 69 | ;; :nrepl-port 7888 70 | 71 | ;; Server Ring Handler (optional) 72 | ;; if you want to embed a ring handler into the figwheel http-kit 73 | ;; server, this is for simple ring servers, if this 74 | 75 | ;; doesn't work for you just run your own server :) (see lein-ring) 76 | 77 | ;; :ring-handler hello_world.server/handler 78 | 79 | ;; To be able to open files in your editor from the heads up display 80 | ;; you will need to put a script on your path. 81 | ;; that script will have to take a file path and a line number 82 | ;; ie. in ~/bin/myfile-opener 83 | ;; #! /bin/sh 84 | ;; emacsclient -n +$2 $1 85 | ;; 86 | ;; :open-file-command "myfile-opener" 87 | 88 | ;; if you are using emacsclient you can just use 89 | ;; :open-file-command "emacsclient" 90 | 91 | ;; if you want to disable the REPL 92 | ;; :repl false 93 | 94 | ;; to configure a different figwheel logfile path 95 | ;; :server-logfile "tmp/logs/figwheel-logfile.log" 96 | } 97 | :profiles {:dev {:dependencies [[binaryage/devtools "0.8.2"] 98 | [figwheel-sidecar "0.5.8"] 99 | [com.cemerick/piggieback "0.2.1"]] 100 | ;; need to add dev source path here to get user.clj loaded 101 | :source-paths ["src" "dev"] 102 | ;; for CIDER 103 | ;; :plugins [[cider/cider-nrepl "0.12.0"]] 104 | :repl-options {; for nREPL dev you really need to limit output 105 | :init (set! *print-length* 50) 106 | :nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}}} 107 | ) 108 | -------------------------------------------------------------------------------- /quick_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/replikativ/chat42/b626e76e3e87ed0ed98d3747e6c16758c10596bf/quick_demo.gif -------------------------------------------------------------------------------- /resources/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/clj/chat42/core.clj: -------------------------------------------------------------------------------- 1 | (ns chat42.core 2 | (:require [replikativ.peer :refer [server-peer]] 3 | [replikativ.stage :refer [create-stage! connect!]] 4 | 5 | [kabel.peer :refer [start stop]] 6 | [konserve.memory :refer [new-mem-store]] 7 | [konserve.filestore :refer [new-fs-store]] 8 | 9 | [superv.async :refer [! chan timeout]] 11 | [superv.async :refer [S] :as sasync] 12 | [cljsjs.material-ui] ;; TODO why? 13 | [om.next :as om :refer-macros [defui] :include-macros true] 14 | [om.dom :as dom :include-macros true] 15 | [cljs-react-material-ui.core :as ui] 16 | [cljs-react-material-ui.icons :as ic] 17 | [sablono.core :as html :refer-macros [html]] 18 | [cljs-react-material-ui.core :as ui] 19 | [cljs-react-material-ui.icons :as ic] 20 | [taoensso.timbre :as timbre]) 21 | (:require-macros [superv.async :refer [go-try (.getTime (js/Date.)) 92 | (- d) 93 | (/ 1000) 94 | js/Math.floor)] 95 | (cond 96 | (>= secs 3600) (str (js/Math.floor (/ secs 3600)) " hours ago") 97 | (>= secs 60) (str (js/Math.floor (/ secs 60)) " minutes ago") 98 | (>= secs 0) (str " seconds ago")))) 99 | 100 | 101 | ;; Material UI with Om 102 | (defn create-msg [name text] 103 | {:text text 104 | :name (if (= name "") 105 | "Anonymous" 106 | name) 107 | :date (.getTime (js/Date.))}) 108 | 109 | 110 | (defn target-val [e] 111 | (.. e -target -value)) 112 | 113 | (timbre/merge-config! 114 | {:appenders {:chat42status 115 | {:enabled? true 116 | :fn 117 | (fn [data] 118 | (let [{:keys [msg_]} data 119 | {:keys [event] :as msg} (cljs.reader/read-string (force msg_)) 120 | m (case event 121 | :connected (str "Connected to " (:url msg)) 122 | :connecting-to (str "Connecting to " (:url msg)) 123 | :creating-ormap (str "Creating OR-Map CRDT.") 124 | ; :streaming-ormap (str "Fetching data.") 125 | :fetching-commits (str "Fechting commits.") 126 | :websocket-error "Connection error. Reconnecting ..." 127 | nil)] 128 | (when m 129 | (swap! val-atom assoc 130 | :snackbar {:open true 131 | :message m}))))}}}) 132 | 133 | 134 | 135 | 136 | (defn name-field [comp input-name] 137 | (dom/div #js {:className "center-xs"} 138 | (ui/text-field 139 | {:floating-label-text "Name" 140 | :class-name "w-80" 141 | :on-change #(om/update-state! comp assoc :input-name (target-val %)) 142 | :value input-name}))) 143 | 144 | 145 | (defn message-field [comp input-text input-name ] 146 | (let [app-state (om/props comp)] 147 | (dom/div #js {:className "center-xs" :key "message"} 148 | (ui/text-field {:floating-label-text "Message" 149 | :class-name "w-80" 150 | :on-change 151 | #(om/update-state! 152 | comp assoc :input-text (target-val %)) 153 | :on-key-down 154 | (fn [e] 155 | (when 156 | (or (= (.-which e) 13) 157 | (= (.-keyCode e) 13)) 158 | (send-message! 159 | app-state (create-msg input-name input-text)) 160 | (om/update-state! comp assoc :input-text ""))) 161 | :value input-text})))) 162 | 163 | 164 | (defn send-button [comp input-text input-name] 165 | (let [app-state (om/props comp)] 166 | (dom/div #js {:className "center-xs"} 167 | (ui/raised-button 168 | {:label "Send" 169 | :disabled (= input-text "") 170 | :on-touch-tap 171 | #(do 172 | (send-message! app-state (create-msg input-name input-text)) 173 | (om/update-state! comp assoc :input-text ""))})))) 174 | 175 | (defn message-item [{:keys [text name date]}] 176 | (ui/list-item {:primary-text 177 | (dom/div nil name 178 | (dom/small nil (str " wrote " (format-time date)))) 179 | :secondary-text text 180 | :secondary-text-lines 2 181 | :key (uuid (str date))})) 182 | 183 | 184 | ;; React App 185 | (defui App 186 | Object 187 | (componentWillMount [this] 188 | (om/set-state! 189 | this 190 | {:input-name "" 191 | :input-text ""})) 192 | (render [this] 193 | (let [{:keys [snackbar posts] :as state} (om/props this) 194 | {:keys [input-name input-text]} (om/get-state this)] 195 | (ui/mui-theme-provider 196 | {:mui-theme (ui/get-mui-theme)} 197 | (html 198 | [:div.col-xs-12.mar-top-10.row 199 | (ui/snackbar {:open (:open snackbar) :message (:message snackbar) 200 | :auto-hide-duration 10000}) 201 | [:div.col-xs-3] 202 | [:div.col-xs-6 203 | (ui/paper {:className "mar-top-20"} 204 | (ui/list 205 | nil 206 | (name-field this input-name) 207 | (message-field this input-text input-name) 208 | (send-button this input-text input-name) 209 | (ui/subheader nil "Messages") 210 | (mapv message-item (sort-by :date > posts)) 211 | (ui/divider nil)))]]))))) 212 | 213 | (def reconciler 214 | (om/reconciler {:state val-atom})) 215 | 216 | (defn ^:export main [& args] 217 | (go-try S 218 | (def client-state (