
DeclarativeCOS - Declarative Caché Programming
The DeclarativeCOS project is a cry of the soul on the topic of COS programming.
The goal of the project is to draw the attention of the community to improving the internal core of COS.
The idea of the project is to support concise syntax when working with loops and collections.

So, what did I come up with concise? Welcome to the examples!
The key concept of the project is a declarative approach. It is necessary to indicate WHAT to use and HOW.
Personally, I always lacked a simple operator / command / spell in the COS terminal in order to display the collection on the screen in the form in which you want it. And now there are two nice things: zforeach and $ zjoin !
Here it is worth telling more about the $ zbind function . To begin with, COS can be expanded with its commands and functions, which can be described in detail in the relevant documentation and article on the developer community portal.
This function creates an instance of the Binder class . Its task is to link the collection and the function that needs to be applied to each element of the collection. In this case, a standard function called “io: println” from DeclarativeCOS is used , which for a given value value executes a simple command:
The zforeach team works with an instance of the Binder class, sequentially going through the collection and applying a function to each of its elements.
$ zjoin - creates a string from the collection, combining its elements between which the specified separator is added.
$ zmap - creates a new collection from the elements of the original collection to each element of which the specified function is applied.
$ zfind - Finds the first element of the collection on which the specified function returns $$$ YES. Otherwise returns a null string.
$ zfilter - creates a new collection based on the original collection, but taking only those elements on which the specified function returns $$$ YES. If there are no such elements, then returns an empty collection.
$ zexists - Verifies that the collection has at least one element on which the specified function returns $$$ YES.
$ zcount - count the number of elements in the collection on which the specified function returns $$$ YES.
To install DeclarativeCOS, just download two files from the official GitHub repository of the project:
The DeclarativeCOS project uses the ^ DeclarativeCOS global to store information about methods marked with @Declarative (declarativeName) annotation.
Each such method is saved to the global as follows:
For example, for the io: println function :
Each time the io: println function is used , a global search is performed, and then the $ classmethod function makes a call to the original method (DeclarativeCOS.IO # println) at the given value.
DeclarativeCOS is a contribution to the new Caché ObjectScript. In the very language that really helps its developers write programs quickly, concisely, simply and reliably. Welcome to the criticism, support and opinions in the commentary under this post!)
Disclaimer: this article and my comments on it are my opinion and are not related to the official position of InterSystems Corporation.
The goal of the project is to draw the attention of the community to improving the internal core of COS.
The idea of the project is to support concise syntax when working with loops and collections.

So, what did I come up with concise? Welcome to the examples!
Examples
The key concept of the project is a declarative approach. It is necessary to indicate WHAT to use and HOW.
Personally, I always lacked a simple operator / command / spell in the COS terminal in order to display the collection on the screen in the form in which you want it. And now there are two nice things: zforeach and $ zjoin !
>s words = ##class(%ListOfDataTypes).%New()
>d words.Insert(“Hello”)
>d words.Insert(“World!”)
>zforeach $zbind(words, “io:println”)
Hello
World!
Here it is worth telling more about the $ zbind function . To begin with, COS can be expanded with its commands and functions, which can be described in detail in the relevant documentation and article on the developer community portal.
This function creates an instance of the Binder class . Its task is to link the collection and the function that needs to be applied to each element of the collection. In this case, a standard function called “io: println” from DeclarativeCOS is used , which for a given value value executes a simple command:
>w value,!
The zforeach team works with an instance of the Binder class, sequentially going through the collection and applying a function to each of its elements.
$ zjoin - creates a string from the collection, combining its elements between which the specified separator is added.
Example: create a date based on the day, month, and year using the separator “/”.
>s numbers = ##class(%ListOfDataTypes).%New()
>d numbers.Insert(“04”)
>d numbers.Insert(“03”)
>d numbers.Inset(“2017”)
>w $zjoin(numbers, “ / ”)
04 / 03 / 2017
$ zmap - creates a new collection from the elements of the original collection to each element of which the specified function is applied.
Example: convert each number to hex.
>set numbers = ##class(%ListOfDataTypes).%New()
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>write "[" _ $zjoin(numbers, ", ") _ "]"
[82, 12, 27]
>set hexNumbers = $zmap(numbers, "examples:toHex")
>write "[" _ $zjoin(hexNumbers, ", ") _ “]”
[52, C, 1B]
$ zfind - Finds the first element of the collection on which the specified function returns $$$ YES. Otherwise returns a null string.
Example: find a prime number.
>set numbers = ##class(%ListOfDataTypes).%New()
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>set primeNumber = $zfind(numbers, "examples:isPrime")
>write "[" _ $zjoin(numbers, ", ") _ "]"
[69, 41, 68]
>write "Prime number: " _ $select(primeNumber="":"", 1:primeNumber)
Prime number: 41
$ zfilter - creates a new collection based on the original collection, but taking only those elements on which the specified function returns $$$ YES. If there are no such elements, then returns an empty collection.
Example: select odd numbers.
>set numbers = ##class(%ListOfDataTypes).%New()
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>set filteredNumbers = $zfilter(numbers, "examples:isOdd")
>write "[" _ $zjoin(numbers, ", ") _ "]"
[22, 71, 31]
>write "[" _ $zjoin(filteredNumbers, ", ") _ "]"
[71, 31]
$ zexists - Verifies that the collection has at least one element on which the specified function returns $$$ YES.
Example: check that the collection has even numbers.
>set numbers = ##class(%ListOfDataTypes).%New()
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>set hasEvenNumbers = $zexists(numbers, "examples:isEven")
>write "[" _ $zjoin(numbers, ", ") _ "]"
[51, 56, 53]
>write "Collection has" _ $case(hasEvenNumbers, 1:" ", 0:" no ") _ "even numbers"
Collection has even numbers
$ zcount - count the number of elements in the collection on which the specified function returns $$$ YES.
Example: count the number of palindromes.
>set numbers = ##class(%ListOfDataTypes).%New()
>do numbers.Insert($random(1000))
>do numbers.Insert($random(1000))
>do numbers.Insert($random(1000))
>set palindromicNumbersCount = $zcount(numbers, "examples:isPalindromic")
>write "[" _ $zjoin(numbers, ", ") _ "]"
[715, 202, 898]
>write "Count of palindromic numbers: " _ palindromicNumbersCount
Count of palindromic numbers: 2
Installation
To install DeclarativeCOS, just download two files from the official GitHub repository of the project:
- install.base.xml are just classes. Without z-functions.
- install.advanced.xml -% ZLANG routines that add z-functions.
How to use
- Inherit a class from DeclarativeCOS.DeclarativeProvider .
- Implement a class method.
- Mark this method with @Declarative annotation.
- Use the z-functions of DeclarativeCOS.
- Feel the happiness.
detailed instructions
Step 1. Inherit the class from DeclarativeCOS.DeclarativeProvider.
Class MyPackage.IO extends DeclarativeProvider
{
}
Step 2. Implement the class method.
Class MyPackage.IO extends DeclarativeProvider
{
ClassMethod println(value As %String)
{
w value,!
}
}
Step 3. Mark this method with @Declarative annotation.
Class MyPackage.IO extends DeclarativeProvider
{
/// @Declarative("myIO:myPrintln")
ClassMethod println(value As %String)
{
w value,!
}
}
Step 4. Use the z-functions of DeclarativeCOS.
>s words = ##class(%Library.ListOfDataTypes).%New()
>d words.Insert("Welcome")
>d words.Insert("to")
>d words.Insert("DeclarativeCOS!")
>zforeach $zbind(words, "myIO:println")
Step 5. Feel the happiness!
Welcome
to
DeclarativeCOS!
How it works
The DeclarativeCOS project uses the ^ DeclarativeCOS global to store information about methods marked with @Declarative (declarativeName) annotation.
Each such method is saved to the global as follows:
set ^DeclarativeCOS(declarativeName) = $lb(className, classMethod)
For example, for the io: println function :
set ^DeclarativeCOS(“io:println”) = $lb(“DeclarativeCOS.IO”, “println”)
Each time the io: println function is used , a global search is performed, and then the $ classmethod function makes a call to the original method (DeclarativeCOS.IO # println) at the given value.
Conclusion
DeclarativeCOS is a contribution to the new Caché ObjectScript. In the very language that really helps its developers write programs quickly, concisely, simply and reliably. Welcome to the criticism, support and opinions in the commentary under this post!)
Disclaimer: this article and my comments on it are my opinion and are not related to the official position of InterSystems Corporation.