google / clojure-turtle

A Clojure library that implements the Logo programming language in a Clojure context
Apache License 2.0
426 stars 41 forks source link

Add ClojureScript support #1

Closed jeisses closed 8 years ago

jeisses commented 8 years ago

Replace functions that are not supported in Quil clojurescript. Also update the clojure, clojurescript and quil dependencies

echeran commented 8 years ago

Cool! I definitely can use help with ClojureScript-ifying things, so this is greatly appreciated! (Help in this department will turn CLJS support from a wish list to a nearer-term work list item.) I'll take a look at the PR in further detail later today.

For now, I'll just leave some initial questions/comments. Also, is there an easy way to give the ClojureScript version of the code a spin? (Or is that an item for the todo list?)

jeisses commented 8 years ago

Hi, nice to hear you're interested in clojurescript support!

The changes are currently functional, I only had to replace functions that ProcessingJS doesn't support. And added the cljs defsketch macro. This works really nice with Figwheel, you can live control the turtle in your browser from the REPL. I'll commit some instructions soon on how to get it running so you can test it.

Edit: i'll also add some cljs build config to the dev profile of this project

jeisses commented 8 years ago

So there were a few hurdles after all :) In order to keep the repl plug-and-play nature of the new-window macro a few additions were needed for clojurescript:

My last commit contains a demo that can be run with lein figwheel; then browse to http://localhost:3449 and use the figwheel repl. What do you think?

echeran commented 8 years ago

Excellent work! You did a good job in following all of those fixes and workarounds to get thing working. It's great to see the canvas in a webpage, now.

The issue of not being able to call defsketch from the REPL is not so much of an issue, but it could be useful to think about in the future. The reason being that truly independent sessions of canvas + turtle state hasn't yet been worked out to begin with... in the Java Clojure version, new windows only reflect the state of the turtle atom in clojure-turtle.core. Plumbing exists to not rely on such global variables -- you can pass any other turtle atom to the main turtle fns (forward, right, ...), but that generalization work didn't carry through to sketch rendering, which only uses the single global state turtle atom to paint the canvas. The tradeoff I was wrestling with is how it would affect the difficulty for users who are new to programming in having to always pass in a turtle atom for each fn (ex: (forward my-turt 30) (right my-turt 90) ...), and since Logo doesn't do it, I decided to not pursue promoting that idea. There's also a limitation in the Clojure/Script implementations in that you only have 1 REPL / Figwheel session. So with only prompt open, it's simplest to only allow the user to manipulate one turtle's state, anyways.

If there's a utility to new-window from the Clojure REPL, it's that you can obtain the Quil canvas size of your choosing (ex: the turtle "goes off the screen", but what the turtle drew still exists and can be seen with a bigger window). So if you explore a way to call defsketch after ProcessingJS has loaded, if that's possible, then maybe an HTML form next to the canvas that allows the user to enter the canvas size and have that take effect. (On a side note, what I thought was interesting was what happens when you load the Figwheel URL into multiple tabs at different times. Each tab's canvas's turtle responds to Figwheel's REPL session, but each turtle may have different states depending on whether they received earlier commands or were started too late for that.)

One thing that I've thought of as another way to handle multiple turtle sessions is do so serially, by allowing the user to save and load the state. I can think of how to do that in plain Clojure, but I don't know if ClojureScript supports pr/pr-str or clojure.edn/read. And although it might take a bit of effort and time, another idea that CLJS could use is to embed a REPL in the webpage that connects to the canvas of the same page, sort of like what Replumb (demo'ed on http://clojurescript.io).