Fork me on GitHub
#clojurescript
<
2017-04-09
>
john00:04:05

mmm, my goog/basePath is ""

john03:04:54

got it working again. Had to find the right project.clj config to get it all working.

hit02304:04:31

Any 2/3-day-long project anyone could suggest to get a better hang of the language?

john04:04:14

@hit023 not sure what you're interested in, re-frame is considered fairly sexy right now. Here is a TodoMVC example for re-frame: https://github.com/Day8/re-frame/tree/master/examples/todomvc A fun project might be porting that to re-natal, to run on ios or android, found here: https://github.com/drapanjanas/re-natal

hit02304:04:03

Thanks, @john will surely take a look. I had something like a game in mind.

hit02304:04:12

Anything along those lines?

john05:04:22

the Readme for the Figwheel project has a pretty good flappy bird game you can study. There are also a few snake examples out there. There's a quantum tic tac toe. I'm trying to remember this great top down game someone made...

hit02305:04:45

Great! On it. Thanks.

john05:04:33

zetawar uses datascript as a DB in the browser, which is based on the Datomic architecture. Pretty good reference implementation there, I'd imagine.

hit02305:04:59

@john , can I ping you if in any doubt?

john05:04:48

@hit023 sure no prob

thheller10:04:34

@john to be honest I think web workers are a build tool concern. manually setting CLOSURE_IMPORT_SCRIPTS does not work for :advanced for example

thheller10:04:07

wrote some words on how it works in my tool

thheller10:04:04

basically you create a dedicated namespace for each worker, the bundle generation is handled for you

thheller10:04:18

it isn't suitable for what you where trying to do though (REPL only runs in main)

john10:04:01

@thheller That's pretty awesome

john10:04:47

And I understand you can instantiate workers with a Blob of a JS file, rather than a JS file. So, potentially, that shim could be generated programmatically and used to load the worker.

john10:04:45

If you have access to necessary path information

john10:04:52

I've currently got two repls up, side by side, one from the UI and one from a worker.

john10:04:02

talking to each other

thheller10:04:53

I don't think the solution from figwheel is viable to be honest as it doesn't work for :advanced

thheller10:04:25

if you use 2 different builds, the use will download cljs.core twice for example

john10:04:29

yeah, figwheel doesn't appear to be built for this particular use case. I'm using weasel, which is not nearly as pretty atm

john10:04:05

right. Your solution is for a different, and perhaps more common use case

john10:04:23

In fact, your solution is exactly what cljs tooling needed for workers. Worker files specifically generated by the tools.

john10:04:41

This webworker repl thing is just a baby unicorn at this point. Might not pan out at all. There's some interesting potential though.

thheller10:04:58

I haven't used the worker thing in a while, just noticed a bug I introduced recently.

thheller10:04:09

easy fix though

john10:04:52

so let me bounce this other idea off of you

john11:04:17

Imagine a js/setTimeout loop that ingests forms one by one. Before each form, it pulls all bindings, scope and necessary environment information out of an atom, evaluates the form, and then stores it's environment back in the atom. Whenever it sees something like a defer, it branches a second setTimeout loop. Whenever it sees an await it pauses the loop and waits for the deferred item to resolve, then starting the eval loop again

john11:04:39

crazy talk?

john11:04:28

a sort of interruptible synthetic eval loop in js

thheller11:04:37

to what end?

john11:04:52

interruptible evaluation... blocking

thheller11:04:05

I don't get it

john11:04:23

well, you run your "main" logic on the synthetic thread

thheller11:04:34

why not use core.async?

john11:04:35

or some string of logic

john11:04:55

you could probably do it in core.async

john11:04:07

core.async is doing a similar thing, right?

thheller11:04:45

(go (loop []
      (alt!
        interrupt
        ([_] :interrupted)
        
        input
        ([work]
          (when (some? work)
            (do-work work)
            (recur))))))

thheller11:04:00

interrupt and input being async/chan

thheller11:04:17

just (async/close! interrupt) anywhere and the whole work loop stops

thheller11:04:03

gotta grab some food, bbl

john11:04:05

core.async doesn't translate past function boundaries though. So it couldn't make arbitrary code interruptible.

john11:04:48

That also may be a lot of machinery for what will amount to one singular synthetic thread, but maybe plain setTimeout or nextTick etc wouldn't be much better.

john11:04:37

I guess I'm talking about a mini-runtime for cljs on js. Which is similar to core.async, but not with macros. Moreso about floating the execution of (mostly) arbitrary clojure forms over a very fast bouncing loop of asynchronous calls, so that as opposed to the environment/event loop freezing, as it does during the javascript execution loop, the cljs loop continues to move by, without a frozen view of the js environment.

thheller14:04:04

@john still no idea what your goal is. this is all JS so you are bound by the same rules.

john14:04:11

@thheller If I create a timeout loop, which continuously spawns new timeout functions., where each one attempts to deref an atom and if it has "hi" it prints "hi"... If, while it's doing that, I reset the value of the atom to "hi", it will eventually print. There, we changed the value of the atom right underneath the logic of the loop. Not possible in the main loop. In the main loop, if you keep looking at the atom, it never changes. If you keep looking at the thing you want to change, it can't change. If a tree falls in the woods and somebody is right there to hear it, does it make a noise? Not in JS! You've gotta leave the woods and come back in again to even see if it's down.

thheller14:04:48

true, there is no blocking in JS. core.async makes things much much easier than a setTimout loop though

thheller14:04:40

setTimeout loop would execute even if nothing happens, doing a bunch of idle work

john14:04:11

it could just wait for new work

john14:04:44

I don't think it's that expensive. Plus you could run it in a web worker, so it wouldn't put pressure on the main thread

thheller14:04:59

it would still run, even if cheap ...

gazaxian14:04:08

core async has overhead though doesn’t it?

gazaxian14:04:19

it’s hooked into JS’s message tick

gazaxian14:04:23

you just don’t see it

thheller14:04:07

core.async runs only if something is put on channels, if no channels are moving nothing moves

john14:04:09

But it's not a "solution" you'd suggest to user. It would require a very engineered solution that produces a fake thread, which passes/threads a running CLJS execution context through the async loop.

john14:04:33

if core.async has a channel currently waiting on information, checking a predicate against a signal, then core.async is going to check that signal source for new info every nextTick, I believe.

gazaxian14:04:12

This is called every tick isn’t it?

john14:04:13

It won't run the predicate

thheller14:04:25

if you wait on a channel

john14:04:25

But has to check a source

thheller14:04:42

it only does work if something is put on the channel

thheller14:04:49

no background idle loop

thheller14:04:17

dispatch just adds "work to be done" to a queue

thheller14:04:30

but once all work has completed nothing is done until a channel is written to

gazaxian14:04:44

ah I get it

gazaxian14:04:22

so you have overhead on the put instead

gazaxian14:04:30

small overhead

thheller14:04:46

not exactly on put but yes

gazaxian14:04:56

write port?

thheller14:04:46

the put just triggers it, the work is done on the next tick

gazaxian14:04:38

yeah, the overhead is checking to see if it needs to set up the work for next tick on every put

gazaxian14:04:42

is what I meant 🙂

john14:04:37

Spawn a thousand go loops that check various event sources. No overhead?

thheller14:04:52

define event sources?

john14:04:27

Checking to see if a particular atom has been changed... listening for browser clicks, whatever.

thheller14:04:43

you do not use core.async like that

john14:04:14

well, with the browser clicks, you can set call backs. But you can dereference atoms and access other sources from inside a go loop, besides just channels.

gazaxian14:04:45

well this is interesting to me 😄 I’m writing my first cljs game and have channels for network msgs, vsync, etc

gazaxian14:04:01

is it not great for that?

thheller14:04:18

not great no, a game has different concerns. but you can make it work certainly

gazaxian14:04:32

it does work, what would be the down side?

gazaxian14:04:38

it’s not lots of channels

john14:04:48

@gazaxian I think it's a good idea

gazaxian14:04:13

small amount of channels, just some are high frequency updates

thheller14:04:15

in a game you want to achieve a certain framerate, say you want a frame every 16ms

thheller14:04:29

core.async doesn't let you define timing like that

gazaxian14:04:48

I pump animation fraem requests through to a channel

thheller14:04:02

yeah but remember that everything is handled async

thheller14:04:10

so if you put something on a channel

john14:04:16

I'm not trying to say core.async isn't great. And core.async does make asynchronous operations appear synchronous within a block. I'm just wishing for this far fetched idea of a cljs min-runtime. But yeah, it'd run all the time.

gazaxian14:04:18

It’s handled on the tick

thheller14:04:23

setTimeout is called (not really but close enough)

thheller14:04:39

so instead of doing work in requestAnimationFrame, you just handed it off

thheller14:04:43

might not have used it at all

gazaxian14:04:17

I use a blocking !>

gazaxian14:04:24

doesn’t that complete then and there?

thheller14:04:27

no blocking in JS 😉

john14:04:55

"then and there" is an illusion provided by core.async

gazaxian14:04:59

I understand that but it could go and feed immediatley to any blocking waits

gazaxian14:04:32

and I know it’s a macro that creates a state machine, I mean illusory ‘blocking’ 😄

gazaxian14:04:10

so if it use !> it puts it on a list and parks the go block?

john14:04:20

If you can keep latency below 16ms, I say go for it.

gazaxian14:04:39

I can easily change it if it’s shit 🙂

gazaxian14:04:19

always the same, spend half the project building nice abstractions

gazaxian14:04:24

the second half taking them out 😄

gazaxian14:04:52

But thanks for the advice, I’ll keep an eye on it

gazaxian14:04:53

tbh some of this is just to learn how it all works, so I’m overusing lang / lib features

thheller14:04:16

not saying that core.async isn't useful for this, just not ideal. you can still do some amazing things

john14:04:05

Well, if you put a 10 second job and send it down a channel to be handled asynchronously, that job won't hang the main thread for 10 seconds, right? So if it's too much pressure for a very large game loop, perhaps core.async could be used for offloading long running jobs, like you can do with setTimeout

gazaxian14:04:16

well low latency and responsivness is a key thing for me, so if it feels latent I can hook directly into a reqanimation frame callback

gazaxian14:04:55

Network io is lower frequency, it’s handy for that for me

gazaxian14:04:23

On the server each client can be sep threads but the client side is pretty simple

gazaxian14:04:33

just showing stuff on canvas, a little bit of logic

gazaxian14:04:51

haven’t done client side interpolation yet tho

john14:04:08

@gazaxian also check out chromashift by chris granger: https://github.com/ibdknox/ChromaShift

john14:04:23

pretty old, but if you're building a platformer, that'll have some good pointers.

john14:04:28

predates core.async

john14:04:13

and had "time travel" way back in the day 🙂

john14:04:51

And I believe he has a blog post or two somewhere on some methods he used to keep work below 16ms

Pablo Fernandez16:04:34

Why when I run the tests by calling cljs.test/run-test or cljs.test/run-all-tests, at the end, I get the devtools disconnect, the page gets blank and I have to reload the page for it to start working again? Is this how running tests is supposed to work?

noisesmith16:04:09

I've never seen that happen

john16:04:12

@pupeno what browser are you using, btw?

john16:04:28

oh, that's different

Pablo Fernandez16:04:40

So, essentially, Chrome.

Pablo Fernandez16:04:26

@john why were you asking?

john17:04:38

I was wondering if maybe you were using a less mainstream browser. I've never heard of the issue before.

Pablo Fernandez17:04:41

In the RELP, I get:

Pablo Fernandez17:04:10

Figured out. Doo was messing with it.

john18:04:35

wow that was cryptic 🙂

Tiago Dall'Oca20:04:40

I'm trying do use ClojureScript on 'Bash on Ubuntu on Windows'. I'm getting this exception when trying lein figwheel:

Tiago Dall'Oca20:04:01

sun.nio.fs.UnixException: Bad file descriptor
        at sun.nio.fs.UnixNativeDispatcher.read(Native Method)
        at sun.nio.fs.LinuxWatchService$Poller.run(LinuxWatchService.java:318)
        at java.lang.Thread.run(Thread.java:745)

Tiago Dall'Oca20:04:13

After Successfully compiled "blah/blah/blah.js"

Tiago Dall'Oca20:04:55

Any suggestions here?

noisesmith20:04:26

did you do something that would move / rename / delete files while it was running?

noisesmith20:04:32

iirc windows doesn't have the same rules for deleted/moved files that linux does, so this could be a bug that only shows up on windows systems (under linux, your file handle remains valid until you close it or exit, even if someone else removes or renames or moves the file)

Tiago Dall'Oca20:04:23

I rebooted the system after the exception and tried again

Tiago Dall'Oca20:04:41

Same result though

noisesmith20:04:14

I wonder if it should be using LinuxWatchService there or if that is a sign of some issue?

Tiago Dall'Oca20:04:15

I have very little experience using Linux

Tiago Dall'Oca20:04:37

I saw two related issues

Tiago Dall'Oca20:04:48

Both are closed