понедельник, 18 января 2016 г.

#868. PROCEDURE, FUNCTION. Parameters at the left and at the right. Part 1

Original in Russian: http://programmingmindstream.blogspot.ru/2015/12/1163-wordworker-operator.html

With reference to - https://bitbucket.org/lulinalex/mindstream/wiki/Articles%20in%20English/Script%20engine%20organisation/A%20real%20example%20of%20code%20generation%20using%20the%20model.%20Mere%20code

The previous series was here - Caching. Let us talk about adding the nested elements.

They asked me about the word parameters (functions) - http://programmingmindstream.blogspot.ru/2015/12/1162.html?showComment=1450717154802#c256225446808977907 (in Russian)

I translate from Russian:

Where can I read about the WordWorker? What are the ways of passing arguments exist (at the right or atthe left, at the right without function executed)? I will appreciate if you give me a direct reference =)
Actually, it would be great you had thorough documentation, but I understand not all is at the same time.

Once I happen to be asked, I will try to describe how the words and word parameters are defined.

Commits history is available at - https://bitbucket.org/lulinalex/mindstream/commits/branch/B284_Inheritance_Try.

Let me stress:
Our script engine is based on the idea of the stack FORTH-machine - https://en.wikipedia.org/wiki/Forth_%28programming_language%29.

Thus, one should become familiar with FORTH (general guideline).

So.

The simplest word is defined as follows:

: // is the sign of word beginning
A // is the word name
 1 >>std::out // is the word code that prints the number 1 as well as
 1 . // prints the number 1
; // is the sign of word end
 
A // calls the word A

The example can be copied in the Example.script file and launched:

call.ms.script.exe Example.script or
call.ms.script.exe Example.script > a.out

The call.ms.script.exe utility is here - https://bitbucket.org/lulinalex/mindstream/src/0bea4adaed7cbc645faa484fcb38f8aae6562827/Examples/Scripts/call.ms.script.exe?at=B284_Inheritance_Try

Note:
The utility may not launch by default which means it is blocked by the anti-virus for it “came from an unreliable source”.

In this case, it should be checked with the anti-virus and added to the list of allowed applications.
Let’s go on.

It is obvious that, as in any programming language, our words may have parameters.

A simplest example:

: A
  IN aParam // specifies the aParam parameter, at the left of the word A
 aParam // returns the parameter value
 . // prints the parameter value 
: // A
 
1 A // calls the word A and passes the VALUE of the number 1 as a parameter value to it

The example can be developed with defining the parameter TYPE in this way:

: A
  INTEGER IN aParam // determines the INTEGER parameter aParam at the left of the word A
 aParam // returns the parameter value
 . // prints the parameter value
: // A
 
1 A // calls the word A and passes the VALUE of the number 1 as a parameter value to it

Thus, we can pass ONLY INTEGER values to our function.

The type of parameters and variables will be discussed further in a separate article.

Speaking aside, I’d like to recommend to see the description of the “axiomatic basis”- https://bitbucket.org/lulinalex/mindstream/src/a071353dbd21d3afaf8f42b774cc890e0f5a74ce/Examples/ScriptedAxiomatics/kwMain.rc.script?at=B284_Inheritance_Try&fileviewer=file-view-default  (commented in Russian)

So far, we have considered ONE parameter at the left.

Now, let us look at a NUMBER of parameters at the left.

The example:

: A
  INTEGER IN aParam1 // specifies the first parameter
  INTEGER IN aParam2 // specifies the second parameter
 aParam1 // returns the value of the parameter aParam1
 aParam2 // returns the value of the parameter aParam2
 + // gives the sum of the two values
 . // prints the result
; // A
 
1 2 A // calls the word A for two INTEGER values 1 and 2

Fine. We have discussed parameters passed to the word.

But, how can we get a value from the word?

Let us examine it.

A simplest example:

: A
  INTEGER IN aParam1 // specifies the first parameter
  INTEGER IN aParam2 // specifies the second parameter
 aParam1 // returns the value of the parameter aParam1
 aParam2 //  returns the value of the parameter aParam2
 + // gives the sum of the two values
 // prints nothing, simply leaves the result value in the stack
; // A
 
1 2 A // calls the word A for two INTEGER values 1 and 2
. // prints the value from the stack, in fact, the one returned by the function A

The technique of "leaving the value in the stack" is not only used in the “antediluvian FORTH" but in the quite “up-to-date Ruby" as well - https://en.wikipedia.org/wiki/Ruby_%28programming_language%29.

There is a negative aspect (in fact it is an advantage): the function called can FAIL to push anything in the stack, or push ONE SINGLE value, or a NUMBER of values.

The person that calls will not be able to control this process.

What’s to be done?

We need to define the TYPE of the value RETURNED.

An example:

INTEGER // specifies the type of the value returned and the “implicit value” Result
: A
  INTEGER IN aParam1 // specifies the first parameter
  INTEGER IN aParam2 // specifies the second parameter
 aParam1 // returns the value of the parameter aParam1
 aParam2 // returns the value of the parameter aParam2
 + // gives the sum of the two values
 >>> Result // pops the value from the stack and write it in the variable Result.
; // A
 
1 2 A // calls the word A for two INTEGER values 1 and 2
. // prints the value in the stack, in fact this is the value returned by the function A

In this case, the script engine ENSURES that ONE and ONLY ONE integer value will be returned.

There is a “but”.

The script engine controls the values returned but not popped from the stack.

We can write as follows.

INTEGER // specifies the type of the value returned and the “implicit value” Result
: A
  INTEGER IN aParam1 // specifies the first parameter
  INTEGER IN aParam2 // specifies the second parameter
 aParam1 // returns the value of the parameter aParam1
 aParam2 // returns the value of the parameter aParam2 
 + // gives the sum of the two values aParam1 and aParam2
 + // gives the sum of the previous value and the value in the stack
 >>> Result // pops the value from the stack and pushes it in the write it in the variable Result.
; // A
 
1 2 3 A // calls the word A for THREE integer values 1, 2 and 3

Sometimes it helps but what about when you want the “total control”?

For this, we have “analogues” of the word :, namely FUNCTION and PROCEDURE.

The example:

INTEGER // specifies the type of the value returned and the “implicit value” Result
FUNCTION // FUNCTION is used instead :
 A
  INTEGER IN aParam1 // specifies the first parameter
  INTEGER IN aParam2 // specifies the second parameter
 aParam1 // returns the value of the parameter aParam1
 aParam2 // returns the value of the parameter aParam2
 + // gives the sum of the two values
 >>> Result // pops the value from the stack and write it in the variable Result.
; // A
 
1 2 A // calls the word A for two INTEGER values 1 and 2
. // prints the value in the stack, in fact this is the value returned by the function A

In this case, both the number of inputs and outputs will be controlled by the script engine.

Here is an example of using the word PROCEDURE:

PROCEDURE // PROCEDURE is used instead of :
 A
  INTEGER IN aParam1 // specifies the first parameter
  INTEGER IN aParam2 // specifies the second parameter
 aParam1 // returns the value of the parameter aParam1
 aParam2 // returns the value of the parameter aParam2
 + // gives the sum of the two values
 . // prints the result value
; // A
 
1 2 A // calls the word A for two INTEGER values 1 and 2

The word PROCEDURE ENSURES that NO VALUES will be returned by the word.

Let’s sum up.

In the article the key words ( :, ;, IN, FUNCTION, PROCEDURE), passing the parameters to the words and returning values to them were considered.

We have scratched the surface of value typing.

Apart from INTEGER type there are STRING, OBJECT, CLASS, INTERFACE, CHAR, ARRAY, FILE, BOOLEAN.

There is also ANY that stands for “any type value”, and PRINTABLE that stands for “any printable value”, and VOID that stands for “sure value absense".

Other types including ITERATABLE, ORDINAL, and ATOMIC will be discussed later.

For now, please find the example of axiomatic:

INTEGER BOOLEAN TYPE ORDINAL
STRING ORDINAL TYPE ATOMIC
ATOMIC TYPE COMPARABLE
 
FILE ARRAY TYPE ITERATABLE
ITERATABLE ATOMIC CASTABLE INTERFACE TYPE ANY
ANY TYPE VARIANT
 
ARRAY TYPE ITERATOR
 
FUNCTOR TYPE VAR_REF

Next, we will discuss the “parameters at the right” (why we need them and how to use them).

Hope, the article was of some use for you.

Комментариев нет:

Отправить комментарий