Carrot Programming

With Carrot you have $expressiveness


Tutorial

Haiku is a condensed Japanese poetry form. In a world ridden by ADD (attention deficit disorder), Haiku carries the promise to reach the reader before the small window of attention closes. Readers frightened by the sheer amount of text on this website (and the author definitely is his own reader in that regard) might feel comforted to know the following haiku as a substitute for not yet written study guides about Carrot.

A world formula becomes code
Hundred module files in action
Hello World

This tutorial consists of several parts. The first part covers a very basic script and ensures that Carrot actually works for you. Keep in mind that Carrot is highly experimental. Any fundamental problem in running Carrot is more easily identified and solved with a basic example which doesn't pull all bells and whistles.

The second part shows the antagonist of raw scripts: cooked programs. For cooked programs you have to write plugins, which are special classes. That topic is covered in the third part. Carrot brings more expressiveness to Perl 5. But it didn't show up explicitly in the first three parts. The fourth part shows a simple example of how to use $expressiveness in a script explicitly.

Part 1: Running a raw script

If a framework can print Hello World, then it can do anything else as well. In that spirit this tutorial starts with that compulsory example. The purpose of the script is not to demonstrate anything but to make sure that Carrot is working for you.

Listing 1-1
01
02
03
04
05
06
07
08
09
10
11
package main
# /type library
# /capability "Prints 'Hello World.' (and tests Carrot)"
{
        use strict;
        use warnings 'FATAL' => 'all';

        print "Hello World.\n";

        return(PERL_FILE_LOADED);
}
Show output of script run

Formally a script is a file containing the special package 'main' in form of a library. The block specifying the library must end with return(PERL_FILE_LOADED). /capability documents the script in a minimal way. Well, that's all. Where is $expressiveness? In the background. The above script is too simple for it to show up.

Store the above code in a file called hello_world.pl. Use the wrapper carrot_script.sh to run the script like in the following example:

cd Carrot-1.1.309 # a reminder to start in the unpacked archive

./lib/Carrot./carrot_script.sh  hello_world.pl	--carrot-mode=development

ls -l hello_world.

#Show output of commands

Looking at the screen output of the script is pretty boring. Therefore the last command above looks at the file output. Expressiveness has created a dot directory for your script. The dot directory holds all supportive files for the script, including documentation, error messages, configuration, optimizations, and temporary files. You want a more extensive documentation than what fits under /capability? Then create a pod file in the directory hello_world./documentation/.

Part 2: Running a cooked program

Writing a raw script is like starting at square one, ready to re-invent the wheel. For small projects consisting of a screenful of code that might not be a problem. But Carrot targets at larger projects, for which pre-assembled components are the way to go.

Regarding Hello World, such a program plugin has been written before. In order to create a cooked program with that plugin, the class name of the plugin is written into the configuration file.

Listing 2-1
01
02
03
04
05
06
07
08
09
10
11
[::Continuity::Operation::Program]
name	features
	*---------------+-------------------------------------*
	| program       | plugin                              |
	+===============+=====================================+
	| *             | ::Control::Signal                   |
	|               + - - - - - - - - - - - - - - - - - - +
	|               | ::Control::PID_File                 |
	+---------------+-------------------------------------+
	| hello_world   | ::Work::Hello_World                 |
	*---------------+-------------------------------------*

Cooked means, you write as little Perl code as possible. Or issue no Perl statements at all. The above configuration file would even load plugins for signal handling and a pid file. Configuration files are searched in the following directories:

  1. <program_file_base>./configuration/ (program-specific)
  2. $ENV{'HOME'}/carrot/configuration/ (user-specific)
  3. /etc/carrot/configuration/ (system-wide)

The name of the configuration file is either +.cfg or <class_name>.cfg (Carrot::Continuity::Operation::Program.cfg in the above case). Definition and data of configuration files are subject to inheritance. Practically it means that the * entry could be defined in a global configuration file and the hello_world entry could be defined in a more specific configuration file. Note that the directories of the system and the user are meant for debugging or development. Other uses indicate an act of despair. The Install.txt ships a ~/.carrot/configuration/+.cfg? Right, that has to go one day.

cd Carrot-1.1.309 # a reminder to start in the unpacked archive

./lib/Carrot./carrot_program.sh  hello_world  --carrot-mode=development

#Show output of commands

Notice the subtle difference in the commands compared to part 1. Just 'program' instead of 'script' and no .pl.

Part 3: Writing an object oriented class

It's already time to check whether you have learned anything about Carrot. What is your guess about the style of a class declaration: will it be with or without Perl code? All answers are right. Though the example quoted below features no Perl statements in the package block (the region between { and }).

Carrot promotes a simple declarative syntax for creating classes. The following listing mainly declares the class name Carrot::Personality::Structured::Geometry::2D::Point and the attributes x and y. (The point class is historically the Hello World of object orientation.)

Listing 3-1
01
02
03
04
05
06
07
08
09
package Carrot::Personality::Structured::Geometry::2D::Point
# /type class
# /attribute_type ::Many_Declared::Ordered
# //attribute_construction
#       x  ::Personality::Valued::Number  +method
#       y  ::Personality::Valued::Number  +method
# /capability "Represent the coordinates of a 2 dimensional point"
{
}
Show shadow file

Slash-keyword constructs before the opening brace are called block modifiers. A package is a general block and /type modifies it to be a class. Putting the block modifiers behind comment signs allows for extensibility by plugins. For example, //attribute_construction isn't a static keyword, but implemented by the plugin Carrot::Diversity::Block_Modifiers::Plugin::Package::Attribute_Construction. You could even have a /print modifier - doesn't conflict with the built-in function print(). The block modifiers are what the perl-attributes always wanted to be.

Attribute types are a preservation of the original flexibility of OO in Perl 5. The two most relevant attribute types are ::One_Anonymous::Scalar and ::Many_Declared::Ordered.

Last but not least the shadow file is the actual code fed into Perl. It's created and maintained by expressiveness plugins. Reminds you somewhat of the early days of C++, when it still was C + macros + macros? Sure, but $expressiveness is more systematic and is rather meant to be integrated into other languages.

Part 4: Using expressiveness explicitly

Now add a little bit of visible expressiveness to the above script. Nothing can directly be done with $expressiveness. Instead it calls plugins for performing actual work. One such plugin is Carrot::Individuality::Controlled::Class_Names. It has a (configurable) shortcut 'class_names'. The plugin can provide instances of classes. In the example below it creates an instance of the class ::Meta::Greenhouse::Test_Plans. The class is a basic tool for creating unit tests.

Listing 4-1
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
package main
# /type library
# /capability "Prints 'Hello World.' (and demonstrates Carrot)"
{
        use strict;
        use warnings 'FATAL' => 'all';

	my $expressiveness = Carrot::individuality;
        $expressiveness->class_names->provide_instance(
                my $test_plans = '::Meta::Greenhouse::Test_Plans');

        $test_plans->set_sections(1);

        $test_plans->report('print',
                (print "Hello World.\n"));

        $test_plans->summary;

        return(PERL_FILE_LOADED);
}
Show output of script run

Again the output of the above script contains no surprises. Now to a similar script with surprises. This time not an instance of ::Test_Plans is requested, but a class. From the class instances can be created with ->indirect_constructor. A dump of the variables illustrates the difference.

Listing 4-2
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
package main
# /type library
# /capability "Prints 'Hello World.' (and demonstrates Carrot)"
{
        use strict;
        use warnings 'FATAL' => 'all';

	my $expressiveness = Carrot::individuality;
        $expressiveness->class_names->provide(
                my $test_plans_class = '::Meta::Greenhouse::Test_Plans');

        my $test_plans = $test_plans_class->indirect_constructor;

	require Data::Dumper;
	print STDERR Data::Dumper::Dumper($test_plans_class, $test_plans);

        return(PERL_FILE_LOADED);
}
Show output of script run

Note the different meaning of 'Carrot::Meta::Greenhouse::Test_Plans' in the output. Inside $test_plans_class it's data and in $test_plans it's meta data. (You need the skill of reading the output of Data::Dumper in order to perform the comparison.)