alshdavid / BorrowScript

TypeScript with a Borrow Checker. Multi-threaded, Tiny binaries. No GC. Easy to write.
1.45k stars 16 forks source link

Inferred gates? #41

Closed WebReflection closed 1 year ago

WebReflection commented 2 years ago

It's not instantly clear from the README why imported utilities or references, such as queue tasks don't require gates, but lamdas do for user defined, not imported, variables.

As I believe this idea would be better off with zero globals around, wouldn't be easier to have outer-scope references infeered, hence with automatic gates around?

The possibilities to discuss would then be:

Thanks in advance for any kind of clarification/discussion/outcome 👋

alshdavid commented 2 years ago

The concurrency part of the specification was drafted initially and left as a rough outline until we refined some of the more foundational language syntax. Gates came after I wrote the concurrency documents.

Initially I wanted to have the Queue be something that could be dependency injected and or managed such that there were multiple queues - perhaps that would be useful to testing or offloading certain workloads to certain processors however after some time thinking about it I think that might be an over optimization for a language with an intention of being simple.

I am thinking of dropping manual queue management and using a built-in concurrency method akin to Goroutines, spawned off a keyword and managed with Promise/Observable types.

What I am currently thinking about is breaking the convention set by other languages with async/await keywords and using async to spawn a coroutine that may or may not be on another thread.

This would disconnect await from async where await would only be used for essentially unwrapping a Promise which is unrelated to managing concurrency. async would not be used to decorate a function that uses an await as it could be inferred by usage.

function main() {
  async function(){
    console.log('Hello World')
  }()

  await time.sleep(time.Duration.Second * 5)
}

An alternative I was thinking about was using async and yield - to avoid confusing C#, Kotlin and JavaScript programmers.

function main() {
  async console.log('Hello World')

  yield time.sleep(time.Duration.Second * 5)
}

At this point I am mentally examining how this would fit in with the Promise pattern or if something like channel which can be passed into the the callback via a ownership gate is necessary

But yes callbacks, concurrent or not, will need to explicitly declare their gates to consume variables from an outer scope.

function main() {
  const foo = 'foo'

  async function()[read foo]{
    console.log(foo)
  }()

  await time.sleep(time.Duration.Second * 5)
}