This repository has been archived by the owner. It is now read-only.

Event-Driven Programming #15

Closed
rfratto opened this Issue Jul 7, 2015 · 0 comments

Comments

Projects
None yet
1 participant
@rfratto
Copy link
Member

rfratto commented Jul 7, 2015

I was thinking about how event-driven programming could work in Orange. My solution uses a when keyword to register a callback for when some expression evaluates to true in the future.

My example here will be making a lot of assumptions about other Orange features, but I'll explain them along the way.

class Person
    int age = 1
end 

def agePerson(var p)
   forever do 
      sleep_for_one_year 
      p.age++
   end 
end 

# assumption: pointers can be created using new keyword 
var john = new Person() 

# assumption: -> not necessary in Orange
john.age = 23

when john.age == 25
    # let john rent a car 
end 

# assumption: 'do' keyword executes function in a different thread 
do agePerson(&john) 

# program _probably_ blocks here 

This would work by whenever the when keyword is used, the compiler wires up the specific object to be used for events. That means that, for john, whenever age is changed, the event handler is told to update. Other people objects that aren't being watched will not call event handlers, since that would add a singificant amount of overhead.

The compiler would know what methods change which members of a class. john's age member is currently being watched, john is passed to agePerson, which modifies age. Therefore, when generating the code for agePerson, create a copy of it specifically for john that will update the event handler when age is changed. This copy of agePerson will be used for any instance of Person that is watching age.

Polymorphic objects will essentially work the same way: when calling a method on a polymorphic object, its event handler will be updated. It doesn't matter if anything is watching it or not.

Now, when you use the when keyword, it registers the condition, the dependencies, and the block to execute in a list of callbacks. So, whenever age is updated, john.age == 25 is evaluated. If it's true, run the block. The block won't run again until john.age is set to 25 again at a later date (which in this case, won't happen).

Let's expand our example to have a more detailed condition:

class Person
    int age = 1
    bool alive = true 

    def canRentCar()
        discard false if alive == false 
        return age >= 25 
     end 
end 

var john = new Person()
john.age = 23 

when john.canRentCar()
    # rent a car for every year after 25 

    # please don't drive anymore, john
    discard if john.age > 108 
end 

do agePerson(&john) # won't define it here, but it's the same method 

This works very similarly to before: on the when statement, the compiler sees that we're calling
canRentCar, which accesses alive and age. Those are our two dependencies. The discard keyword is used to discard the event, and it will no longer be checked. Discard only has an effect if being called from a when statement, otherwise it acts as a return.

The implmentation of this and figuring out all the details will definitely be tricky, but I think this could be a powerful feature. Imagine if it existed for an http server:

var server = new HttpServer()

when server.serves("/") 
    # give the root page to the client 
end 
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.