Hacker News new | ask | show | jobs
Show HN: CandyJS – transparent bridge between Go and JavaScript (github.com)
72 points by mcuadros 4014 days ago
5 comments

Nice project! One little remark: I see you're being slightly lazy and using JSON to save some value conversion work. One problem is that this is not very good from a performance standpoint. The other, more serious issue is that your code will not work if someone tries to pass around a data structure containing NaN value, like []float64{math.NaN()} Got bitten by this problem, had to fix it: https://github.com/contactless/wb-rules/commit/067ff7564f16a...
True in some cases I fold back to JSON: https://github.com/mcuadros/go-candyjs/blob/master/base.go#L...

But the main goal of the project is be fully transparent more than the performance. At the very beginning I was making every case by hand but this is a endless work: https://github.com/mcuadros/go-candyjs/blob/54c8beb723aa8b1b...

I will take a closer look to the NaN issue and also a closer look to your code.

BTW I made a PR to go-duktape based on you fork: https://github.com/olebedev/go-duktape/commit/65f0be48ece4f6...

Unfortunately NaN behavior seems to be hard-wired in encoding/json code. The proper way to fix it is perhaps taking encoding/json sources and converting marshalling/unmarshalling code to use go-duktape Push/To/etc. functions instead of JSON writing/parsing. That's indeed a sizable amount of work, though.

As of integrating (some of) changes from my fork to the go-duktape mainline, thanks a lot! Didn't get around to do it myself.

I built a package to bridge spidermonkey/Go last year[0]. I ended up doing most of the communication via JSON (after several less stable versions using reflect) which was fine for the use-case I had. Unfortunately since it builds spidermonkey and some wrapper code it ruined any chance of "go get" working cleanly which doesn't make it a very attractive package.

CandyJS looks much simpler. Good work.

[0] https://github.com/chrisfarms/jsapi

Hi Chris, thanks for your support. Your packages looks like very interesting, I couldn't find it before.

About the pool of workers, they share the stack? Or how you keep the same status on each.

No the contexts in pools do not share any state. Once you call an Eval from Go-land you'll be tied to context until that Eval returns, but Go-land will yield during that time so other goroutines(/contexts) are free to execute. It's just a convenience for setting up and working with multiple contexts to take advantage of multiple cores. Probably better to think of it like a process-pool.

The use case I had was along the lines of:

    * Bind/Expose a bunch of Go functions to N JS worker contexts.
    * Execute a large queue of JS-functions using the workers.
Spidermonkey did actually have a way to do a kind of shallow copy of a context and save/restore stack, which shared state, however this actually ended up making things much slower for my use as it required locking the threads and constantly copying stacks.
This is pretty interesting, although I don't know if it's... necessary.

What do you think are some of the pros/cons between Go and JavaScript? When would you prefer to use JavaScript instead of Go, or vice versa?

I think Go can be more performant than Node.js, but I remember seeing some conflicting benchmarks where V8 can actually manage more RPS.

The other thing that comes to mind is how React Native uses JavaScript to manipulate UI Components on iOS. If Google ever supports Go on Android, then this kind of thing could be pretty interesting.

the main goal of CandyJS is allow to other developers build extendable programs without the requirement of compile.

A good example could be a chan bot in Go with plugins written on JS. (like https://github.com/djosephsen/lazlo) but with CandyJS the effort to make this will be minimal, since you can use the same structures on JS and Go.

About the performance, CandyJS javascript is much slower than pure Go, since the reflection is very expensive.

A small quick bench of this example: https://github.com/mcuadros/go-candyjs/blob/master/examples/...

Pure Go: 165951 requests

CandyJS: 36304 requests

That means that CandyJS is 4,5 times slower than pure Go. Both

Duktape is good for scripting. My particular app is a simple rule engine for smart home applications which runs on relatively low-powered ARM board. It would hardly be practical to have Go compiler there, and duktape is resource-efficient ECMAScript engine which serves this purpose just fine.
Oh I see, that's pretty cool!
Great work! But is there any reason that you didn't build on top of the really nice V8 binding https://github.com/ry/v8worker instead of Duktape?
v8worker, was one of the evaluated projects, but V8 is not very fast compiling... takes several mins.

With go-duktape, you can compile CandyJS just lake a normal Go package without any other tool or library.

Other reason is that many of the features are based on ECMA6 Proxy, something that is not supported on v8.

cool! why and how are the Go methods called with camelcase names?

  var engine = gin.default();
  engine.get("/back", CandyJS.proxy(function(ctx) {
    var future = time.date(2015, 10, 21, 4, 29 ,0, 0, time.UTC);
    var now = time.now();

    ctx.json(200, {
      future: future.string(),
      now: now.string(),
      nsecs: future.sub(now)
    });
  }));
the method and field names are converted to lowerCamelCase to be compliant with the JS coding style. Let's see if this transformation becomes a headache.

BTW this behaviour is undocumented, I will fix that.

got it!