I do NOT have a sleep problem. OK, yes I do.

Published March 11, 2009
Advertisement
Static validation for tasks is now complete.

I found a nice, simple solution to the higher-order-function bug - when a function reference is passed to another function, a binding record is placed on the stack. This record basically links the function parameter to an actual function; this record is how the code knows which function to call.

Safety-checking this is simply a matter of having the stack instruction do validation, rather than the function call instruction. Since the stack instruction knows what function it's placing on the stack, we can simply follow that reference and go validate the function itself.

This means that we literally can cover more code during the validation traversal than is actually executable. For instance, even if you do an unspeakable thing inside an if(false) block, the validator will walk into that block and catch you red-handed. You filthy little devil.


The validator puts out some nice contextual information that indicates how and where things went wrong. Here's an example output:

EXEGEN - Epoch development toolkitParsing: first pass...Parsing: second pass...Performing static safety validations...VALIDATION FAILURE: Task performs an unsafe operationCall stack:   entrypoint()   pi()File: .\scratch.epoch Line: 38 Column: 13                        debugwritestring("Uh oh! I am illegal!")                        ^ERROR: Program failed validation.0 of 1 programs executed successfully.


So we can immediately see why the function failed validation (filename and code position are displayed) as well as the situation under which the failure occurred (call stack). The combination of these two facts should make it very convenient to fix task issues.


With this bit officially done, there's only one major item left on my GDC checklist: message passing. I will spend a few minutes thinking about this as I drift off to sleep, and hopefully tomorrow I can get a finalized design and start banging out the implementation.

From there, it's mostly a matter of documentation and a bit of double-checking to make sure all the examples and test programs work correctly. Once that's done, it's time to start burning CDs with the GDC distribution on them [smile]
0 likes 5 comments

Comments

choffstein
I have to ask: why do you not allow functions that perform side effects in your parallel tasks? I understand the inherent non-deterministic issues, but that doesn't seem like reason enough. I know you are also trying to avoid locks -- but I can think of some legitimate reasons as to where I will actually need them ... or at least something similar. What if I want two threads to read and write from different tables in a database? Technically, this is a side-effect, though a totally legitimate place for threads. What if I want to perform file I/O in my tasks?

It seems to me that you have limited tasks to the mere crunching of numbers...
March 11, 2009 08:22 AM
ApochPiQ
Functions with side effects are completely permitted. The limitation is that any side effects must not propagate outside the task. The idea is that if you can write your task in pure Epoch without having to call external functions, you are guaranteed a safe and lock-free environment for the job.

Of course there will be situations like you describe, where two tasks have a contention for a single resource. In these cases I will be building in systems to help manage the side effects; but at the moment I haven't dug too deep into that subject.

This is pure speculation and shouldn't be taken seriously, but I'd see it working something like this:

resource(database)

entrypoint : () -> ()
{
  task(db1)
  {
    lockresource(database)
    ExecuteSQL(database, some_sql_query)
    // We use RAII style here so when we exit the scope the DB is unlocked
  }

  task(db2)
  {
    lockresource(database)
    ExecuteSQL(database, some_other_sql_query)
  }
}



I'm not planning on eliminating locking or other traditional synchronization techniques; I just want a minimal environment where everything is safe and simple.
March 11, 2009 10:23 AM
nolongerhere
I may be over looking something, but are you keeping the syntax of expressions and declaring new types as if theyre functions?
integer(index, 100)
assign(index, subtract(index, 1))

Any chances of posting a more extended road map? Perhaps to R7?
:)
Cheers!

March 11, 2009 11:53 AM
ApochPiQ
The syntax for defining a type is similar to but not identical to function syntax:

IAmAFunction : (integer(foo)) -> (integer(bar, 0))
{
  // Do stuff
}

structure IAmAType : (integer(foo))


Defining a type actually creates two things: one is the type itself, which is referenced using the name (in this case, IAmAType); secondly, it creates a function with the same name as the type, which acts as the type's constructor.

This basic pattern will hold for all language elements, or at least as close to it as I can get. My goal is a very simple and consistent syntax (i.e. you don't have to remember weird symbols all the time [wink])


As for a roadmap - I'm really not comfortable plotting too much ahead, for a number of reasons. Mainly, this is still a side project for me, so the amount of time I have to work on Epoch is limited. So I don't want to lock myself into a schedule that I can't keep.

The other big reason I want to avoid a detail roadmap is that I often switch priorities based on various factors: what's needed in the language to accomplish certain programming tasks, what's interesting that I feel like playing with, what's broken that really needs fixing, etc. Since this is a side project, reprioritizing everything is actually pretty common. (I maintain a text file with a list of all my tasks on it, and I rearrange the priorities at least once a day.)

Finally, anything after R6/the GDC release depends entirely on how things go at GDC this year. If I do manage to drum up some interest, that's most likely going to affect what I work on and when.

So for now, stay tuned [smile]
March 11, 2009 12:51 PM
nolongerhere
Hah that was my mistake, I was asking about declaring a new variable, not a type. Though I am glad that you showed me the syntax of defining a new type. Though it does help with consistency, it seems odd to write expressions with a series of function calls as opposed to using a algebra-like form of writing them. It will be interested in seeing how people react to it when people start writing more complex and less trivial applications.
March 11, 2009 02:03 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement