tj / luna

luna programming language - a small, elegant VM implemented in C
2.46k stars 148 forks source link

support callback? #54

Closed yorkie closed 10 years ago

yorkie commented 10 years ago

hi, @visionmedia

Is @luna plan to implement callback like javascript for async IO? I think this feature would be very important for IO.

tj commented 10 years ago

nope, no callbacks in luna-land (internally of course), the plan is/was to go with coroutines to suspend functions

DAddYE commented 10 years ago

Hi mate, wondering on is/was. Is the project dead? What's the plan?

yorkie commented 10 years ago

I love every small thing, so I love this project, I'd like to do some contributes for this.

tj commented 10 years ago

nah not dead but definitely low priority for me ATM :( unfortunately

ranadeep47 commented 10 years ago

Yep couroutines > callbacks . The & is amazing

yorkie commented 10 years ago

Actually I'm so new guy to coroutinues, then why it bigger than callbacks? I just wanna get a notification when an async io event is completed, for example:

delete('/user/1') &
delete('/user/2') &

How could we knows the first user/1 has been deleted, also paralleled them. In Javascript:

delete('/user/1', function() {
  // get notification for user/1
});
delete('/user/2', null);
yawnt commented 10 years ago

a coroutine is basically a function which can be paused and resumed from that point.. in your case the function would be paused after the first delete... after the async call is finished it would be resumed and would thus continue with the second delete

yorkie commented 10 years ago

Then we need a join like pthread to get result of those corresponding coroutines, am I right? Their definition has a little bit similar, but I see, thanks very much.

yawnt commented 10 years ago

the idea is to have a scheduler which is basically responsible for running coroutines and is a loop

say you have this file main.rb

IO.read :file

the runtime would look something like

coro_ready = [:main] # main is the code block in main.rb
coro_stopped = []

class IO
  def read
    async_read { |result|  # <- this function call doesn't block
      coro_ready.push :main
    }
  end
end

while true
  fn = coro_ready.pop
  fn()
  # when fn returns it means it's waiting for async io
  coro_stopped.push :main
end

of course by adding coroutines to those two lists you can achieve concurrency (with async I/O and your code would still look synchronous)

am i right @visionmedia ?

tj commented 10 years ago

im not 100% sold on the fork/join stuff I have in the readme ATM, there's a lot of different ways to approach it - at the lower level lua-style is probably the safest, but I'd like to have a scheduler in core, or pluggable like rust.

yea the idea is instead of a callback, within something like fs.read() you have a coroutine.yield() so that stack (and where it was called) is suspended so something else can do work, then when it's done it gets resumed. The easiest way to think of it is like a callback, it's basically the same thing, just easier to read and better exception handling haha

tj commented 10 years ago

but with the fork/join example to run them in parallel and grab the results:

let a = get('/foo') &
let b = get('/bar') &
let a, b = join(a, b)

sugar for something like:

let a = task(def; return get('/foo'); end)
let b = task(def; return get('/bar'); end)
let a, b = join(a, b)

I have a fork with some syntax refinements though, I'm not 100% sold on the ruby-ish stuff, I love it at the root level, I think the symmetry of def <name> looks really nice but once you get to closures etc I think it looks kinda bad

tj commented 10 years ago

I'll try and get the fork up soon

yorkie commented 10 years ago

The easiest way to think of it is like a callback, it's basically the same thing, just easier to read and better exception handling

+1 for this summary, just find a easy way to let programmers express its thoughts better :)

Plus, I think & just defines a function in parallel, then program is to queue these functions by calling join, but postposition of & is more like linux shell, how about this syntax:

let a = &get('/foo')
let b = &get('/bar')
let a, b = join(a, b)

Further to say, we can define join, parallel, series, etc, to decide that how the VM queues these functions defined by &.

Just a suggestion :)

tj commented 10 years ago

I just thought & at the end was kinda cool since it's really familiar for shell users haha but yea kinda gimmicky, however the cool thing with it being a low-precedence operator is expressions:

let res = get('/foo') + get('/bar') &
let res = fork(def; return get('/foo') + get('/bar'); end)

is pretty clear that it wraps the whole expression, whereas with an unary it looks like it should just be the first (since unary operators are typically high precedence):

let res = &get('/foo') + get('/bar')
let res = fork(def; return get('/foo'); end) + get('/bar')
yorkie commented 10 years ago

Yup, I see.

tj commented 10 years ago

example of how it's working now: https://gist.github.com/visionmedia/8761361 that's just with coroutines but if/when we have a scheduler it'll look similar for regular IO in request/response cycles etc