Falcon (programming language)

Falcon
Paradigm multi-paradigm: procedural, object-oriented, prototype-based, functional, tabular, message passing
Designed by Giancarlo Niccolai
Developer Falcon Committee
First appeared 2003
0.9.6.8 (Chimera) / December 31, 2010[1]
Dynamic
OS Cross-platform
License GPLv2, FPLLv1.1[2] (a modified version of the Apache License)
.ftd, .fal, .fam
Website falconpl.org

Falcon is an open source, multi-paradigm programming language. Design and implementation is led by Giancarlo Niccolai,[3][4] a native of Bologna, Italy and Information Technology graduate from Pistoia.

Falcon translates computer source code to virtual machine instructions for evaluation. The virtual machine[5] is thought both as a stand-alone interpreter and for integration in third-party embedding applications.

A core design consideration for the Falcon programming language is to provide acceptably high performing scripting plug-ins to multi threaded data acquisition, reporting and dispersion applications.

As programming languages go, Falcon design leans more towards conciseness of code and expressiveness than general readability. The Falcon implementation does provide facilities for source level documentation and this documentation may become important as the mixed paradigm potential of Falcon scripting attempts to meet the problems faced with programming in the large.

History

A small project, HASTE,[6] developed in 2002, in an attempt to create a small fast virtual machine, soon evolved into the Falcon programming language. In early 2008, the package was first shipped under open source licensing as a package in Ubuntu, and included in the KDE 4 scripting framework.

Philosophy

Rather than focusing on one programming style or paradigm, Falcon merges several different styles into a single framework. At the same time, it targets multiple application domains (stand-alone, embedded into other applications and server-side dynamic pages), merging them into a single hood of a common architectural design.

At the implementation level, Falcon is driven by the concept of service, where the scripting engine is seen as a service for scripts, modules and in embedded applications when not used as a stand-alone tool.

"Hello World" example

Although there are various forms of basic I/O, an example Hello world program using fast print:

> "Hello World!"

Supporting Unicode,[7] below is an internationalized example of introductions:

 // International class; name and street
 class 国際( なまえ, Straße )
    // set class name and street address
    नाम = なまえ
    شَارِع   =  Straße
    // Say who am I!
    function 言え()
      >@"I am $(self.नाम) from ",self.شَارِع
    end
 end
 // all the people of the world!
 民族 = [ 国際( "高田 Friederich", "台灣" ),
    国際( "Smith Σωκράτης", "Cantù" ),
    国際( "Stanisław Lec", "południow" ) ]
 
 for garçon in 民族: garçon.言え()

which, when evaluated, displays

 I am 高田 Friederich from 台灣
 I am Smith Σωκράτης from Cantù
 I am Stanisław Lec from południow

Data types

Paradigms

Falcon merges six major programming paradigms.

Procedural

Procedural programming is supported through classic function declarations and calls.[9] Every function supports implicitly variable parameter calls and named/positional parameters. A set of procedural style statements (as i.e. for, while, if, switch statements) is provided.

The following is a complete procedural program.

 function sayList( saying )
    for elem in saying
        >> elem
        formiddle: >> " "
        forlast: > "!"
    end
 end
 sayList( List("Have", "a", "nice", "day") )

If the above is saved to a text file as niceday.fal, a command line of falcon niceday.fal produces

Have a nice day!

on standard output.

Functional

Falcon has an evaluation engine called Sigma-reductor, which allows programmers to write completely functional programs without the need to use any procedural construct,[10] not differently from what is seen in Lisp. The intermixed programming style allows use of different paradigms (such as OOP or procedural approaches) in functional sequences, or to use functional evaluations during the course of otherwise procedural programs.

Functional sequences are represented by standard language arrays; this means that sequences can be created, inspected and changed dynamically by the program itself, either across different evaluations or during the course of a Sigma-reduction evaluation. The following example does that by changing a special variable reference, called late binding in a list loop.

  seq = [ printl, '"', &value, '"' ]
 
  dolist( function(p); seq.value = p; eval(seq); end,
          ["Have", "a", "nice", "day"] )

Standard arrays can be called as functions if their first member is itself a callable item, as in the following example.

  f = [printl, "Prompt> "]
  f( "Real data to print" )

One-level functional sequences (as in the above example) can be conceptually treated as cached calls, and once assigned to a variable, they are morphologically equivalent to a function symbol.

The functional paradigm includes an out-of-band item marker. Items can receive an oob flag marker which can be tested through language operators and functions and indicate a special meaning for values traveling in functional sequences. For example, many functional loops, as floop and times, can perform loop restarts or can be interrupted by returning either an out-of-band 1 or 0 from any of the involved functions. The map function, transforming all the values in an array through a mapping function, will ignore the returned value (discarding it) if it's an out-of-band nil; in this way, it is possible to perform map-and-filter operations in place.

Class-based object-orientation

The Falcon programming language provides an OOP paradigm with classes, an inheritance model, class-static members, property initializers and instance constructor.[11] Multiple inheritance is supported under the condition that at most one underlying ancestor class is reflecting native data. Access to base class members is supported.

Instance structure is fixed and immutable,[11] but due to Falcon's functional nature where functions are seen as just a special kind of data, it is possible to set instance members to plain data or functions (making them methods) dynamically. Functional sequences can be assigned to properties, in which case they become functional methods for the given OOP instance.

Falcon supports stand-alone objects, which can be either classless or derived by class ancestors, which are instantiated and readied before the Virtual Machine executes the main script. Instance Resolution order is tracked by the Falcon Linker to ensure proper initialization of stand-alone objects, which may refer one another in program modules.

Class instances can be created through functional sequences, as instancing a class is morphologically equivalent to calling its symbol, and so, evaluating a functional sequence whose first element is a class has the effect of creating an instance.

Falcon OOP model is completed by operator overloading,[11] which allows to create classes on which the mathematical and logical operators have a special behavior.

The C++ classes that build the Falcon engine are Doxygen indexed at falconpl.org.[12]

Prototype-based object-orientation

Prototype OOP[13] is similar to classic Class-based OOP, but it drops the concept of classes. Instances are all classless, and their structure can be dynamically changed. Falcon language dictionaries (ordered key/value pair collections) can include functions; dictionaries can then be blessed to inform the language that they are to be treated as classless instances, and applying dot accessor causes their values to be treated as properties or methods. In the following example, a dictionary becomes an object:

 dict = bless([ 'state' => 0, 'incme' => function(); self.state++; end ])
 dict.incme()
 > dict.state  // will print '1'

Bindings in arrays works similarly.

 array = [1,2,3]
 array.showMe = function()
    for item in self
        > item
    end
 end
 
 array.showMe()

Message-oriented

Message-oriented programming allows indirect calls to one or more registered listeners when a message is broadcast. The contents of the message are arbitrary and can include any language item, including but not limited to classes from which to create instances, functional sequences or tables. Listeners can either compete to receive the message and exclude the others, or participate in building a common reply to the message in ordered steps. Messages can be broadcast and require an immediate reply or can be left in the environment to be received and processed by latecomers (termed assertions in Falcon[14]).

Message oriented programming has a direct interface into the Virtual Machine, on which external native modules and embedding applications can interact. For example, a multithreaded application may throw into the virtual machine messages coming from different threads, for serialized processing at script level and later broadcast of processed solutions directly from within the scripts.

Tabular

Tabular programming[15] can be seen as a special extension of OOP programming, where a class is represented by a table, whose columns are properties and where each row is an instance. Other than keeping all the instances together, and allowing each instance to work on the surrounding rows of the parent table, modification on the table are dynamically reflected into every instance.

Tables offer a means to select behaviors between a finite set of choices, or to mix behaviors and merge them, providing fuzzy logic engines. As each row, actually a Falcon array, can contain both table-specific data and logic or private logic (via array bindings), an entity selected in a table via global selection logic can provide specialized working abilities.

Features

Along with the multiple paradigms, Falcon presents a variety of different features for programmers.

List comprehensions

Further information: List comprehension

Base types and classes exposing the sequence interface to the internal engine offer a "comp" method which offers all the functionality of a list comprehension[16] construct. The comp method takes a mandatory "source" parameter, which can be another sequence, an item of range type or a generator function returning one item at a time, and a special marker at termination.

A function (or in general a callable item) can be provided as second optional parameter, and acts both as a filter and modifier.

Associative pair sequences (as i.e. dictionaries) are supported as well.

The following is a simple example using a range to create a list comprehension; the result is an array of even numbers 2..10:

   even_array = [].comp( [2:11:2] )

This generates a list of random integer numbers in the range 1,9; the list terminates when the random number is 10 (that is, each item as 1/10 probability to be the last).

  random_list = List().comp( function(); n = random(1,10); return n == 10 ? oob(0): n; end )

The next, more complete example, uses a generator to fill a set of exactly 10 unique random numbers chosen in the 1..100 range. In this occasion, the role of determining the end of the comprehension is delegated to the filter.

  random_set = Set().comp(
      [random, 1, 100],  // generator, callable array
      function( number, myself )  // filter, using the optional "myself" param
         if myself.len() == 10
             return oob(0)  // return oob(0) as a generator to terminate
         end
         return number
      end
      )

The "comp" method returns the same object it operates on. So, it is possible to apply it on an already existing sequence to add more data to it.

Similarly, the "mfcomp" generic method allows to create list comprehensions using more input sets, as in the following example.

 sums = [].mfcomp( {x,y=> x+y}, .[1 2 3], .[4 5 6] )

The resulting array in "sums" contains the values obtained summing each element in the first set (x) with each element of the second set (y).

Template documents

Falcon allows scripts to be part of text documents, with the preprocessor <? .. ?> or <?fal .. ?> directive.[17] Scripts saved as ".ftd" files are treated as text documents and simply echoed until one of those processor directives is encountered. Inbound scripts are executed as in the following .ftd example:

   You called this script with <? print( args.len() ) ?> parameters.

FTD documents can be merged with normal Falcon scripts to form applications, where the presentation logic is in dynamic templates (the FTD files), and the application logic is stored in Falcon modules.

FTD documents can be used in driving dynamic websites. Some popular webservers (currently Apache 2), have modules which directly parse and execute ".fal" and ".ftd" scripts, providing an API which integrates in the webserver engine. It is also possible to use dynamic FTD pages along with CGI scripts.

Exceptions

Falcon supports error handling via the raise, try and catch statements.[18] The raise statement can throw any Falcon item, including nil, numbers, strings, objects and so on. Library functions and external modules will usually raise instances of the Error class, or instances of a class derived from that.

The catch statement can be used to catch any type of item, a certain type (i.e. strings or integers), or instances from a certain class. Caught classes are organized on a hierarchical base, so that it is possible to provide more generic error handlers like the following example (TypeError is a library class derived from Error):

 try
  // ... code that can raise ...
 catch TypeError in error
  // ... if we mixed up types ...
 catch Error in error
  // ... another generic error ...
 catch StringType in error
  // ... an explicit raise "something" was issued ...
 catch in error
  // ... some other exception has been raised, referenced in the variable ''error''.
 end

The in clause of the catch statement is optional (this means that the error itself may be discarded).

The catch statement mimics the select statement, which can be used to switch on the type or class of a given variable.

Explicit string expansion

Falcon includes an '@' unary string expansion operator[19] that returns a string with inline '$' variable references replaced. This operation allows for formatting during the substitution.

For example:

  a = 123456.789
  v = "formatted as"
  s = "a = $a, $v $(a:12rg3,.2), rounded hex as $(a:C)"
  printl( @ s)

Which prints:

 a = 123456.789, formatted as   123,456.79, rounded hex as 0x1E241

Embeddable runtime

Falcon is designed for embedding[20] into and extending other systems with a linkable runtime library, libfalcon.

Documentation generator

Falcon ships with an integrated documentation system, called faldoc,[21] which is specifically designed to provide Falcon based libraries (be they native C++ code or module sets written in Falcon) with maintainable documentation.

Virtual filesystem

All I/O operations happening at engine or at virtual machine (script execution) level are delegated to a centralized Virtual Filesystem Provider, to which external modules or embedding application facilities are allowed to register dynamically. Subscribed Virtual Filesystems abstract I/O operations as directory read, file creation and stream opening, and can be addressed from within scripts by URI. This makes it possible to load modules or open resources from any VFS (as network resources or compressed/crypted archives), which may include special virtual locations provided by third party modules and/or by applications embedding the engine.

Concurrency support

In versions 0.8.x, the separate Threading module provides full multithreading to scripts, while starting from version 0.9.x the "Threading" module is integrated in the standard modules and threading support is provided directly inside the main engine. The multithreading model is agent oriented, and data across threads must be explicitly shared through several possible sharing mechanisms. Each thread runs a different virtual machine, which runs separately from any operation happening in the others (as i.e. garbage collection). This allows for efficient parallel processing and zero contention outside the control of the script developer.

Coroutines

Falcon supports quasi-parallel coroutining.[22] Coroutines are code executed in time slices or during idle times by the Virtual Machine. They provide a lighter parallel approach than the full threading model and allow full visibility of program global data through different coroutines. Explicit cooperation of each coroutine is required, (i.e., each coroutine must check for data availability before blocking reads).

Metacompiler

The Falcon compiler contains a meta-compiler[23] that supports macro expansions. A Falcon Virtual Machine in the standard compiler drives the meta-compiler. Output generated from the meta-compiler is sent to the language lexer as if part of the original source. Using \[ ...\] escape sequences, it is possible to dynamically write the contents of the program being compiled by printing it:

  \[ printl( "printl( 'Hello world' )" ) \]

The keyword macro provides a simplified candy-grammar interface to compile-time meta-programming.

Native internationalization

Strings prefixed with an 'i' are recognized as exported (international) strings.[7] Declaring the language used in a module through the directive statement, it is possible to indicate which is the native language in which strings are written, as in the following example:

  directive lang=fr_FR           // uses 5 characters [[ISO 639|ISO language code]]
 
  > i"Bonjour à tout le monde!"

A command line tool called fallc is provided to export 'i' strings into XML definition files, which can be used as templates to provide translations into different languages.

The translated string table is applied to the modules at load time.

Feathers standard library

Supporting modular programming, Falcon ships with Feathers,[24] the standard module suite, which integrates the built-in core module, containing the basic I/O and language-integrated base functions, classes and objects.

Feather modules currently include:

Implementation

The core VM and official modules, (including Feather modules and other community provided support modules) are all written in C++. Some very low level module and engine elements are written in C and Assembly.

Supported platforms

Falcon is distributed through installers on Mac OS X and Windows systems (where building and installing is a more articulated process), or through self-building source packages on various open systems as Linux or OpenSolaris.[25]

On the latter systems, Falcon is usually supported and generally kept up to date on various distributions, among which:

Falcon is available on Solaris based OS distributions through the Blastwave project, and through the DragonFly BSD system.

Falcon Programming Language License

Falcon Programming Language License
Author Giancarlo Niccolai
Latest version 1.1
Published March 2008
DFSG compatible Yes
FSF approved No
OSI approved No
GPL compatible No
Copyleft Yes

The Falcon Programming Language License is the free software license applied to the Falcon programming language and also available to be used in other projects.

The original FPLL 1.0 was described by its creator as being "... mainly an Apache2 license modified to extend the openness of the license to the embedding application and to the scripts."

Version 1.1 has been redesigned not to extend to the scripts.

See also

References

External links