IO

Source: reference-book. Raw markdown: /raw/docs/reference-book/6-wrappers/IO.md

An <<<io>>> wrapper shell has both an activation or input layer and also an output layer, both encoded into the activator expression. It's just a different use case of wrapper shells.

An IO shell does not have any difference with conditional shell as it uses the same syntax. The difference is in how we setup the activation layer. As we saw in previous section, a conditional shell passes data only from outside to inside the shell. Using IO shell we can also send data out from inside the shell and have a bi-directional vibration flow.

Before getting started with io shells, let's meet a useful operator.

Layer Operator

Layer operator <<<.>>> is a special operator which is quite useful. Let's first start with a short history. In CPLs it is called <<<Member Access Operator>>> or simply <<<Dot Operator>>>. It is used to access members (fields, properties, methods) of an object, structure or class instance.

While this application is almost similar to what <<<.>>> does in simorg, the mindset behind it is a bit different. Let's see a quick example,

(
  "Hello!" $hello,
  "Bye!" $bye
) $message

message.hello:?

You can see our <<<AND>>> gate is acting as a layer around <<<hello>>> and <<<bye>>> identifiers, binding them together. This layer is identified by another identifier called <<<message>>>.

Using <<<.>>> operator we can traverse through the layers of our vibration so to reach the exact data that we need.

It's also possible to push data into a specific field of a gate. For example,

(
  $hello,
  $bye
) $message

"Hello" message.hello
"Bye" message.bye

message ?

""" sim -f layer.art """ (hello: Hello, bye: Bye) !!!!

To make the usage even simpler, we can use structure and destructure patterns as,

(
  $hello,
  $bye
) $message

("Hello", "Bye") message

message ?

$$$AlertBox type=HINT title=Gates and Layer Operator message=As you may have noticed, gates are behaving more like CPL objects, making it possible for layer operator to read specific slot if the slot is already an identifier. So if a gate is using an identifier whether declared or not, you can access the slot using a . operator.$$$

If the gate on the receiver side is an <<<OR>>> then any number of vibrations that are available will be picked and pushed into the slots in order that they are used, otherwise if the receiver is an <<<AND>>> gate, it is mandatory for inflow vibration to have the same length, otherwise an <<<INVALID_DESTRUCTION_PATTERN>>> error will be logged by the engine and vibration is discarded.

IO Shells

Now that we are more familiar with layer operator and pattern matching, let's see how we can have an io shell by an example,

$sum {
  // arg declaration
  ($a, $b) $args

  // destructuring incoming vibration
  sum args 

  // logic
  args.a + args.b sum
}

(10, 20) sum ? // 30

This classical example is representing an adder logic which receives two values and adds them together.

  • Line 3 does an API declaration for necessary arguments.
  • Line 6 is pushing whatever received through <<<sum>>> into our args declaration so utilizing destruction pattern.
  • Line 9 does the logic and pushes back the result into <<<sum>>>. A wrapper shell is smart enough to understand that this vibration is coming from inside the shell so it won't activate the shell again. Due to the same reason line 6 is not vibrated by an internal vibration of <<<sum>>>.
  • When sum is vibrated from inside, the value returns back so continuing and completing the pipeline and finally logging the value 30.

$$$AlertBox type=HINT title=Mathematical IO message=The similar look and feel of an IO shell to the concept of a function should not mislead us! Although similar on the surface but fundamentally different in implementation. What happens here is a pure data driven mathematical structure in action without any program counter, return address management etc.$$$

Now, this is one possible way of having an IO behavior. If the logic is more complex with multiple inputs and outputs, the declaration can be done in activation layer. For example,

[$arg1, $arg2, $add, $sub, $mul, $div] $calculate {
   calculate.arg1 + calculate.arg2 calculate.add
   calculate.arg1 - calculate.arg2 calculate.sub
   calculate.arg1 * calculate.arg2 calculate.mul
   calculate.arg1 / calculate.arg2 calculate.div
}

(10,5)calculate?

Running the code will result in,

""" sim -f calculator.art """ [add: 15, sub: 5, mul: 50, div: 2] !!!!

This is how the usage of an <<<OR>>> gate becomes handy. This is just another possible way of declaring io behavior in simorg.

Wrapper shells when combined with dataflow activator layers become quite powerful. Using wrappers we can even implement similar patterns of CPLs e.g. classes and traits. But the question is do we really need it?

When a declaration is having its own wrapper shell, like the examples above, only the vibrations which are happening inside the shell are considered the final value of the identifier.

So repeating the last example and adding a standalone logger on line 10,

[$arg1, $arg2, $add, $sub, $mul, $div] $calculate {
   calculate.arg1 + calculate.arg2 calculate.add
   calculate.arg1 - calculate.arg2 calculate.sub
   calculate.arg1 * calculate.arg2 calculate.mul
   calculate.arg1 / calculate.arg2 calculate.div
}
(10,5)calculate
(20,5)calculate

calculate ?

We can see that the values of <<<arg1>>> and <<<arg2>>> are not received. Line 10 is using our variable in the head of a pipeline so making it a pure receiver which will receive all possible vibrations from different pipelines.

$$$AlertBox type=HINT title=Manifestation of Reality message=Simorg language is not trying to mimic similar patterns of CPLs. Some of the classical paradigms e.g object oriented programming must be avoided while writing simorg code. In code level we are focusing on creating a reality. The final look and result should be manifested in the creature as a result not as a mechanism.$$$