Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The Magic behind functional Streams #1

Open
frank-dspeed opened this issue Oct 11, 2022 · 1 comment
Open

The Magic behind functional Streams #1

frank-dspeed opened this issue Oct 11, 2022 · 1 comment

Comments

@frank-dspeed
Copy link
Member

frank-dspeed commented Oct 11, 2022

Basics

a functional stream consists of a single function then this function can or can not call a other function. Correct thats it!
the most importent carracteristic of a stream is that it needs to have a value without a return value a function would be a sink

so a function that returns a value is a Stream we reference that as run property on a class or object or as run method depending on the language used for example in C you will often see main() referenced as example we call that always the run property of a Task the type of the run property of a task is a function as the name already implicitly tells us in windows world it would be called exec but again to keep it consistent we call it run it references in our wording a runInstruction run is the shorthand for that.

more advanced concepts are scheduling as soon as we implement the concepts of a function that we will reference from now on as run with a scheduler which is something that tell the function when it should run and also handels lifecycle for example reschedules the function at a diffrent point in time when it depends on other streams to get finished first. Ok back to topic once run and scheduler are combined we got a Task so something that should happen at a given point in time for example to keep it simple lets use the defaultScheduler which is now directly that will create a Task that should run now this gets passed to a Sink or lets call it Runner. the default linux scheduler that gets used when you execute your binary inside a shell is for example the kernel which can then defer that task to the app it self or keep managing it so the kernel implements a sink.

a sink or runner is a Task execution Context it handels tasks and transfers or operates on errors it is the main part of the Stream so it constructs a Stream

a Stream is as Sayed a functional Composition of functions that call functions.

now you know the basics about functional streams here a example of a simple functional stream using ECMAScript syntax

(()=>{/** NoOp **/})(); // => Implementation of No Operation functional Stream without Scheduler so directly implements its Sink as Immediately-Invoked Function Expressions (IIFE)
// Note that streams are inmutable by design so every Stream is InMuteable it is like the ownership concept in rust a stream owns its values exclusiv!
const noOpStream = ()=>{/** NoOp **/}; // => Implements a noOpStream without Scheduler so that what we would call run a runInstruction
const sink = (fnOrStream) => { fnOrStream() }; // => Implements a sink a sink never returns it is always void that is importent!
sink(noOpStream); // executes our tasks or pipelines them to a execution context to be more exact it is representing a pipeline in this case a execution pipeline we call that runEffects as the run of Tasks produce Effects. thats why sinks do not implement return values.

// how to mutate something?
const functionalCompositionCreatesMergeStream = (streamOrFn, otherStreamOrFn, ...otherArgs) => () => [streamOrFn, otherStreamOrFn, ...otherArgs];
const aFnThatChangesSomethingTransforms = (inputStream) => Object.assign(inputStream, { changedSomething: ""});
const functionalCompositionCreatesTransformStream = (inputStream) => aFnThatChangesSomethingTransforms(inputStream);

// Note a Stream passed into a Stream creates a new Stream a function is equal to a stream as long as it returns a value.

a sink auto implements the concept of transfer owner ship of the Task after passing a task to a sink it is not mutable anymore from outside the sink similar concept to borrow operators in rust. a stream always consists of inmutable Items by design so a Task is not Muteable the only control and modification options that you got for the task are supplyed via the Scheduler that modifys and handels runtime behavior after that only the sink has complet ownerShip about the task and the Scheduler that the task is affilated with.

So you learned now that Functional Streams by Design implement Borrow and Ownership Principels from rust you just got a better programmer without using any language specifics. Some languages do not work well with this pattern but the good news is they are easy to transpil and you will mostly never need to keep something implemented in such a language implemented in that language thats why stealify exists.

@frank-dspeed
Copy link
Member Author

Concept of a kernel sink

import { sink } = await import('stealify:kernel');
// KERNEL IPC KMS 
sink({
  run: (task, scheduler) => scheduler(task);
})
// The Kernel will now do what you want when you want it to do so 

as you can see here there will never happen a sync function call as Streams are Async by design. to perform sync operations you can only do that inside a stream. But again the Scheduling is always Async it needs to be so because if you got a multi core processor it is also async. And on Single Core CPU's the Async Design gets Sync because there is only one CPU executing that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant